[BugFix] Fixed Continuity Test
- Reimplemented the continuity test in BarrowmanCalculator - Added corresponding unit tests, too
This commit is contained in:
parent
0ab8dde5fb
commit
3f9be1387d
@ -2,12 +2,8 @@ package net.sf.openrocket.aerodynamics;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.util.BugException;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
|
||||
|
||||
@ -19,7 +15,6 @@ import net.sf.openrocket.util.Coordinate;
|
||||
*/
|
||||
|
||||
public abstract class AbstractAerodynamicCalculator implements AerodynamicCalculator {
|
||||
private static final Logger log = LoggerFactory.getLogger(AbstractAerodynamicCalculator.class);
|
||||
|
||||
/** Number of divisions used when calculating worst CP. */
|
||||
public static final int DIVISIONS = 360;
|
||||
|
@ -3,6 +3,7 @@ package net.sf.openrocket.aerodynamics;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
import net.sf.openrocket.util.Monitorable;
|
||||
@ -66,5 +67,6 @@ public interface AerodynamicCalculator extends Monitorable {
|
||||
* @return a new, independent instance of this aerodynamic calculator type
|
||||
*/
|
||||
public AerodynamicCalculator newInstance();
|
||||
|
||||
|
||||
public boolean isContinuous( final Rocket rkt);
|
||||
}
|
||||
|
@ -6,15 +6,19 @@ import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
|
||||
import net.sf.openrocket.aerodynamics.barrowman.FinSetCalc;
|
||||
import net.sf.openrocket.aerodynamics.barrowman.RocketComponentCalc;
|
||||
import net.sf.openrocket.rocketcomponent.ComponentAssembly;
|
||||
import net.sf.openrocket.rocketcomponent.ExternalComponent;
|
||||
import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
|
||||
import net.sf.openrocket.rocketcomponent.FinSet;
|
||||
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.RingInstanceable;
|
||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.rocketcomponent.SymmetricComponent;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
@ -151,11 +155,7 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Perform the actual CP calculation.
|
||||
*/
|
||||
|
||||
private AerodynamicForces calculateNonAxialForces(FlightConfiguration configuration, FlightConditions conditions,
|
||||
Map<RocketComponent, AerodynamicForces> map, WarningSet warnings) {
|
||||
|
||||
@ -164,8 +164,6 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
AerodynamicForces total = new AerodynamicForces();
|
||||
total.zero();
|
||||
|
||||
double radius = 0; // aft radius of previous component
|
||||
double componentX = 0; // aft coordinate of previous component
|
||||
AerodynamicForces forces = new AerodynamicForces();
|
||||
|
||||
if (warnings == null)
|
||||
@ -178,6 +176,11 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
if (calcMap == null)
|
||||
buildCalcMap(configuration);
|
||||
|
||||
|
||||
if( ! isContinuous( configuration.getRocket() ) ){
|
||||
warnings.add( Warning.DIAMETER_DISCONTINUITY);
|
||||
}
|
||||
|
||||
for (RocketComponent component : configuration.getActiveComponents()) {
|
||||
|
||||
// Skip non-aerodynamic components
|
||||
@ -185,35 +188,6 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
continue;
|
||||
|
||||
|
||||
// TODO: refactor this code block to a separate method, where it will operate on each stage separately.
|
||||
//
|
||||
// Developer's Note:
|
||||
// !! this code assumes all SymmetricComponents are along the centerline
|
||||
// With the implementation of ParallelStages and Pods, this is no longer true. -Daniel Williams
|
||||
//
|
||||
// // Check for discontinuities
|
||||
if (component instanceof SymmetricComponent) {
|
||||
SymmetricComponent sym = (SymmetricComponent) component;
|
||||
// TODO:LOW: Ignores other cluster components (not clusterable)
|
||||
double x = component.toAbsolute(Coordinate.NUL)[0].x;
|
||||
|
||||
// Check for lengthwise discontinuity
|
||||
if (x > componentX + 0.0001) {
|
||||
if (!MathUtil.equals(radius, 0)) {
|
||||
warnings.add(Warning.DISCONTINUITY);
|
||||
radius = 0;
|
||||
}
|
||||
}
|
||||
componentX = component.toAbsolute(new Coordinate(component.getLength()))[0].x;
|
||||
|
||||
// Check for radius discontinuity
|
||||
if (!MathUtil.equals(sym.getForeRadius(), radius)) {
|
||||
warnings.add(Warning.DISCONTINUITY);
|
||||
// TODO: MEDIUM: Apply correction to values to cp and to map
|
||||
}
|
||||
radius = sym.getAftRadius();
|
||||
}
|
||||
|
||||
// Call calculation method
|
||||
forces.zero();
|
||||
RocketComponentCalc calcObj = calcMap.get(component);
|
||||
@ -273,6 +247,51 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isContinuous( final Rocket rkt){
|
||||
return testIsContinuous( rkt);
|
||||
}
|
||||
|
||||
private boolean testIsContinuous( final RocketComponent treeRoot ){
|
||||
Queue<RocketComponent> queue = new LinkedList<RocketComponent>();
|
||||
queue.addAll(treeRoot.getChildren());
|
||||
|
||||
boolean isContinuous = true;
|
||||
SymmetricComponent prevComp = null;
|
||||
while((isContinuous)&&( null != queue.peek())){
|
||||
RocketComponent comp = queue.poll();
|
||||
if( comp instanceof SymmetricComponent ){
|
||||
queue.addAll( comp.getChildren());
|
||||
|
||||
SymmetricComponent sym = (SymmetricComponent) comp;
|
||||
if( null == prevComp){
|
||||
prevComp = sym;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for radius discontinuity
|
||||
if ( !MathUtil.equals(sym.getForeRadius(), prevComp.getAftRadius())) {
|
||||
isContinuous = false;
|
||||
}
|
||||
|
||||
// double x = component.toAbsolute(Coordinate.NUL)[0].x;
|
||||
// // Check for lengthwise discontinuity
|
||||
// if (x > componentX + 0.0001) {
|
||||
// if (!MathUtil.equals(radius, 0)) {
|
||||
// warnings.add(Warning.DISCONTINUITY);
|
||||
// radius = 0;
|
||||
//}
|
||||
//componentX = component.toAbsolute(new Coordinate(component.getLength()))[0].x;
|
||||
|
||||
prevComp = sym;
|
||||
}else if( comp instanceof ComponentAssembly ){
|
||||
isContinuous &= testIsContinuous( comp );
|
||||
}
|
||||
|
||||
}
|
||||
return isContinuous;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////// DRAG CALCULATIONS ////////////////
|
||||
|
@ -321,7 +321,7 @@ public abstract class Warning {
|
||||
|
||||
/** A <code>Warning</code> that the body diameter is discontinuous. */
|
||||
////Discontinuity in rocket body diameter.
|
||||
public static final Warning DISCONTINUITY =
|
||||
public static final Warning DIAMETER_DISCONTINUITY =
|
||||
new Other(trans.get("Warning.DISCONTINUITY"));
|
||||
|
||||
/** A <code>Warning</code> that the fins are thick compared to the rocket body. */
|
||||
|
@ -115,7 +115,7 @@ public class AxialStage extends ComponentAssembly implements FlightConfigurableC
|
||||
public boolean isAfter(){
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public boolean isLaunchStage(){
|
||||
return ( getRocket().getBottomCoreStage().equals(this));
|
||||
}
|
||||
|
@ -1938,8 +1938,6 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
|
||||
return (MathUtil.pow2(innerRadius) + MathUtil.pow2(outerRadius)) / 2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////// OTHER
|
||||
|
||||
|
||||
|
@ -833,52 +833,53 @@ public class TestRockets {
|
||||
coreFins.setHeight(0.12);
|
||||
coreFins.setSweep(0.18);
|
||||
coreBody.addChild(coreFins);
|
||||
}
|
||||
|
||||
// ====== Booster Stage Set ======
|
||||
// ====== ====== ====== ======
|
||||
ParallelStage boosterStage = new ParallelStage();
|
||||
boosterStage.setName("Booster Stage");
|
||||
coreStage.addChild( boosterStage);
|
||||
boosterStage.setRelativePositionMethod(Position.BOTTOM);
|
||||
boosterStage.setAxialOffset(0.0);
|
||||
boosterStage.setInstanceCount(2);
|
||||
boosterStage.setRadialOffset(0.075);
|
||||
|
||||
{
|
||||
NoseCone boosterCone = new NoseCone(Transition.Shape.POWER, 0.08, 0.0385);
|
||||
boosterCone.setShapeParameter(0.5);
|
||||
boosterCone.setName("Booster Nose");
|
||||
boosterCone.setThickness(0.002);
|
||||
//payloadFairingNoseCone.setLength(0.118);
|
||||
//payloadFairingNoseCone.setAftRadius(0.052);
|
||||
boosterCone.setAftShoulderRadius( 0.051 );
|
||||
boosterCone.setAftShoulderLength( 0.02 );
|
||||
boosterCone.setAftShoulderThickness( 0.001 );
|
||||
boosterCone.setAftShoulderCapped( false );
|
||||
boosterStage.addChild( boosterCone);
|
||||
|
||||
BodyTube boosterBody = new BodyTube(0.8, 0.0385, 0.001);
|
||||
boosterBody.setName("Booster Body");
|
||||
boosterBody.setOuterRadiusAutomatic(true);
|
||||
boosterStage.addChild( boosterBody);
|
||||
// ====== Booster Stage Set ======
|
||||
// ====== ====== ====== ======
|
||||
ParallelStage boosterStage = new ParallelStage();
|
||||
boosterStage.setName("Booster Stage");
|
||||
coreStage.addChild( boosterStage);
|
||||
boosterStage.setRelativePositionMethod(Position.BOTTOM);
|
||||
boosterStage.setAxialOffset(0.0);
|
||||
boosterStage.setInstanceCount(2);
|
||||
boosterStage.setRadialOffset(0.075);
|
||||
|
||||
{
|
||||
InnerTube boosterMotorTubes = new InnerTube();
|
||||
boosterMotorTubes.setName("Booster Motor Tubes");
|
||||
boosterMotorTubes.setLength(0.15);
|
||||
boosterMotorTubes.setOuterRadius(0.015); // => 29mm motors
|
||||
boosterMotorTubes.setThickness(0.0005);
|
||||
boosterMotorTubes.setClusterConfiguration( ClusterConfiguration.CONFIGURATIONS[5]); // 4-ring
|
||||
//boosterMotorTubes.setClusterConfiguration( ClusterConfiguration.CONFIGURATIONS[13]); // 9-star
|
||||
boosterMotorTubes.setClusterScale(1.0);
|
||||
boosterBody.addChild( boosterMotorTubes);
|
||||
NoseCone boosterCone = new NoseCone(Transition.Shape.POWER, 0.08, 0.0385);
|
||||
boosterCone.setShapeParameter(0.5);
|
||||
boosterCone.setName("Booster Nose");
|
||||
boosterCone.setThickness(0.002);
|
||||
//payloadFairingNoseCone.setLength(0.118);
|
||||
//payloadFairingNoseCone.setAftRadius(0.052);
|
||||
boosterCone.setAftShoulderRadius( 0.051 );
|
||||
boosterCone.setAftShoulderLength( 0.02 );
|
||||
boosterCone.setAftShoulderThickness( 0.001 );
|
||||
boosterCone.setAftShoulderCapped( false );
|
||||
boosterStage.addChild( boosterCone);
|
||||
|
||||
FlightConfigurationId motorConfigId = config.getFlightConfigurationID();
|
||||
MotorConfiguration motorInstance = TestRockets.generateMotorInstance_G77_29mm();
|
||||
motorInstance.setID( new MotorInstanceId( boosterMotorTubes.getName(), 1) );
|
||||
boosterMotorTubes.setMotorInstance( motorConfigId, motorInstance);
|
||||
boosterMotorTubes.setMotorOverhang(0.01234);
|
||||
BodyTube boosterBody = new BodyTube(0.8, 0.0385, 0.001);
|
||||
boosterBody.setName("Booster Body");
|
||||
boosterBody.setOuterRadiusAutomatic(true);
|
||||
boosterStage.addChild( boosterBody);
|
||||
|
||||
{
|
||||
InnerTube boosterMotorTubes = new InnerTube();
|
||||
boosterMotorTubes.setName("Booster Motor Tubes");
|
||||
boosterMotorTubes.setLength(0.15);
|
||||
boosterMotorTubes.setOuterRadius(0.015); // => 29mm motors
|
||||
boosterMotorTubes.setThickness(0.0005);
|
||||
boosterMotorTubes.setClusterConfiguration( ClusterConfiguration.CONFIGURATIONS[5]); // 4-ring
|
||||
//boosterMotorTubes.setClusterConfiguration( ClusterConfiguration.CONFIGURATIONS[13]); // 9-star
|
||||
boosterMotorTubes.setClusterScale(1.0);
|
||||
boosterBody.addChild( boosterMotorTubes);
|
||||
|
||||
FlightConfigurationId motorConfigId = config.getFlightConfigurationID();
|
||||
MotorConfiguration motorInstance = TestRockets.generateMotorInstance_G77_29mm();
|
||||
motorInstance.setID( new MotorInstanceId( boosterMotorTubes.getName(), 1) );
|
||||
boosterMotorTubes.setMotorInstance( motorConfigId, motorInstance);
|
||||
boosterMotorTubes.setMotorOverhang(0.01234);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
package net.sf.openrocket.aerodynamics;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
@ -12,7 +14,10 @@ import com.google.inject.Module;
|
||||
|
||||
import net.sf.openrocket.ServicesForTesting;
|
||||
import net.sf.openrocket.plugin.PluginModule;
|
||||
import net.sf.openrocket.rocketcomponent.BodyTube;
|
||||
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
||||
import net.sf.openrocket.rocketcomponent.NoseCone;
|
||||
import net.sf.openrocket.rocketcomponent.ParallelStage;
|
||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.util.Coordinate;
|
||||
@ -102,4 +107,51 @@ public class BarrowmanCalculatorTest {
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContinuousRocket() {
|
||||
Rocket rocket = TestRockets.makeEstesAlphaIII();
|
||||
AerodynamicCalculator calc = new BarrowmanCalculator();
|
||||
|
||||
assertTrue("Estes Alpha III should be continous: ", calc.isContinuous( rocket));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testContinuousRocketWithStrapOns() {
|
||||
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
||||
AerodynamicCalculator calc = new BarrowmanCalculator();
|
||||
|
||||
assertTrue("F9H should be continuous: ", calc.isContinuous( rocket));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRadialDiscontinuousRocket() {
|
||||
Rocket rocket = TestRockets.makeEstesAlphaIII();
|
||||
AerodynamicCalculator calc = new BarrowmanCalculator();
|
||||
|
||||
NoseCone nose = (NoseCone)rocket.getChild(0).getChild(0);
|
||||
BodyTube body = (BodyTube)rocket.getChild(0).getChild(1);
|
||||
|
||||
nose.setAftRadius(0.015);
|
||||
body.setOuterRadius( 0.012 );
|
||||
body.setName( body.getName()+" << discontinuous");
|
||||
|
||||
assertFalse(" Estes Alpha III has an undetected discontinuity:", calc.isContinuous( rocket));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRadialDiscontinuityWithStrapOns() {
|
||||
Rocket rocket = TestRockets.makeFalcon9Heavy();
|
||||
AerodynamicCalculator calc = new BarrowmanCalculator();
|
||||
|
||||
ParallelStage booster = (ParallelStage)rocket.getChild(1).getChild(1);
|
||||
NoseCone nose = (NoseCone)booster.getChild(0);
|
||||
BodyTube body = (BodyTube)booster.getChild(1);
|
||||
|
||||
nose.setAftRadius(0.015);
|
||||
body.setOuterRadius( 0.012 );
|
||||
body.setName( body.getName()+" << discontinuous");
|
||||
|
||||
assertFalse(" Missed discontinuity in Falcon 9 Heavy:", calc.isContinuous( rocket));
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user