Merge pull request #603 from JoePfeiffer/fix-568
[Fixes 568] Consider all instances of components when calculating drag
This commit is contained in:
commit
18a8caa5b7
@ -388,90 +388,100 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
|
|
||||||
double finFriction = 0;
|
double finFriction = 0;
|
||||||
double bodyFriction = 0;
|
double bodyFriction = 0;
|
||||||
double maxR = 0, len = 0;
|
double maxR = 0, minX = Double.MAX_VALUE, maxX = 0;
|
||||||
|
|
||||||
double[] roughnessLimited = new double[Finish.values().length];
|
double[] roughnessLimited = new double[Finish.values().length];
|
||||||
Arrays.fill(roughnessLimited, Double.NaN);
|
Arrays.fill(roughnessLimited, Double.NaN);
|
||||||
|
|
||||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
final InstanceMap imap = configuration.getActiveInstances();
|
||||||
|
for(Map.Entry<RocketComponent, ArrayList<InstanceContext>> entry: imap.entrySet() ) {
|
||||||
|
final RocketComponent c = entry.getKey();
|
||||||
|
|
||||||
// Consider only SymmetricComponents and FinSets:
|
// Consider only SymmetricComponents and FinSets:
|
||||||
if (!(c instanceof SymmetricComponent) &&
|
if (!(c instanceof SymmetricComponent) &&
|
||||||
!(c instanceof FinSet))
|
!(c instanceof FinSet))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Calculate the roughness-limited friction coefficient
|
// iterate across component instances
|
||||||
Finish finish = ((ExternalComponent) c).getFinish();
|
final ArrayList<InstanceContext> contextList = entry.getValue();
|
||||||
if (Double.isNaN(roughnessLimited[finish.ordinal()])) {
|
for(InstanceContext context: contextList ) {
|
||||||
roughnessLimited[finish.ordinal()] =
|
|
||||||
|
// Calculate the roughness-limited friction coefficient
|
||||||
|
Finish finish = ((ExternalComponent) c).getFinish();
|
||||||
|
if (Double.isNaN(roughnessLimited[finish.ordinal()])) {
|
||||||
|
roughnessLimited[finish.ordinal()] =
|
||||||
0.032 * Math.pow(finish.getRoughnessSize() / configuration.getLength(), 0.2) *
|
0.032 * Math.pow(finish.getRoughnessSize() / configuration.getLength(), 0.2) *
|
||||||
roughnessCorrection;
|
roughnessCorrection;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Actual Cf is maximum of Cf and the roughness-limited value.
|
* Actual Cf is maximum of Cf and the roughness-limited value.
|
||||||
* For perfect finish require additionally that Re > 1e6
|
* For perfect finish require additionally that Re > 1e6
|
||||||
*/
|
*/
|
||||||
double componentCf;
|
double componentCf;
|
||||||
if (configuration.getRocket().isPerfectFinish()) {
|
if (configuration.getRocket().isPerfectFinish()) {
|
||||||
|
|
||||||
|
// For perfect finish require Re > 1e6
|
||||||
|
if ((Re > 1.0e6) && (roughnessLimited[finish.ordinal()] > Cf)) {
|
||||||
|
componentCf = roughnessLimited[finish.ordinal()];
|
||||||
|
} else {
|
||||||
|
componentCf = Cf;
|
||||||
|
}
|
||||||
|
|
||||||
// For perfect finish require Re > 1e6
|
|
||||||
if ((Re > 1.0e6) && (roughnessLimited[finish.ordinal()] > Cf)) {
|
|
||||||
componentCf = roughnessLimited[finish.ordinal()];
|
|
||||||
} else {
|
} else {
|
||||||
componentCf = Cf;
|
|
||||||
|
// For fully turbulent use simple max
|
||||||
|
componentCf = Math.max(Cf, roughnessLimited[finish.ordinal()]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
//Handle Overriden CD for Whole Rocket
|
||||||
|
if(c.isCDOverridden()) {
|
||||||
// For fully turbulent use simple max
|
continue;
|
||||||
componentCf = Math.max(Cf, roughnessLimited[finish.ordinal()]);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//Handle Overriden CD for Whole Rocket
|
|
||||||
if(c.isCDOverridden()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Calculate the friction drag:
|
|
||||||
if (c instanceof SymmetricComponent) {
|
|
||||||
|
|
||||||
SymmetricComponent s = (SymmetricComponent) c;
|
|
||||||
|
|
||||||
bodyFriction += componentCf * s.getComponentWetArea();
|
|
||||||
|
|
||||||
if (map != null) {
|
|
||||||
// Corrected later
|
|
||||||
map.get(c).setFrictionCD(componentCf * s.getComponentWetArea()
|
|
||||||
/ conditions.getRefArea());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double r = Math.max(s.getForeRadius(), s.getAftRadius());
|
|
||||||
if (r > maxR)
|
|
||||||
maxR = r;
|
|
||||||
len += c.getLength();
|
|
||||||
|
|
||||||
} else if (c instanceof FinSet) {
|
// Calculate the friction drag:
|
||||||
|
if (c instanceof SymmetricComponent) {
|
||||||
|
|
||||||
FinSet f = (FinSet) c;
|
SymmetricComponent s = (SymmetricComponent) c;
|
||||||
double mac = ((FinSetCalc) calcMap.get(c)).getMACLength();
|
|
||||||
double cd = componentCf * (1 + 2 * f.getThickness() / mac) *
|
bodyFriction += componentCf * s.getComponentWetArea();
|
||||||
2 * f.getFinCount() * f.getPlanformArea();
|
|
||||||
finFriction += cd;
|
if (map != null) {
|
||||||
|
// Corrected later
|
||||||
|
map.get(c).setFrictionCD(componentCf * s.getComponentWetArea()
|
||||||
|
/ conditions.getRefArea());
|
||||||
|
}
|
||||||
|
|
||||||
|
final double componentMinX = context.getLocation().x;
|
||||||
|
minX = Math.min(minX, componentMinX);
|
||||||
|
|
||||||
|
final double componentMaxX = componentMinX + c.getLength();
|
||||||
|
maxX = Math.max(maxX, componentMaxX);
|
||||||
|
|
||||||
|
final double componentMaxR = Math.max(s.getForeRadius(), s.getAftRadius());
|
||||||
|
maxR = Math.max(maxR, componentMaxR);
|
||||||
|
|
||||||
|
} else if (c instanceof FinSet) {
|
||||||
|
|
||||||
|
FinSet f = (FinSet) c;
|
||||||
|
double mac = ((FinSetCalc) calcMap.get(c)).getMACLength();
|
||||||
|
double cd = componentCf * (1 + 2 * f.getThickness() / mac) *
|
||||||
|
2 * f.getPlanformArea();
|
||||||
|
finFriction += cd;
|
||||||
|
|
||||||
|
if (map != null) {
|
||||||
|
map.get(c).setFrictionCD(cd / conditions.getRefArea());
|
||||||
|
}
|
||||||
|
|
||||||
if (map != null) {
|
|
||||||
map.get(c).setFrictionCD(cd / conditions.getRefArea());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fB may be POSITIVE_INFINITY, but that's ok for us
|
// fB may be POSITIVE_INFINITY, but that's ok for us
|
||||||
double fB = (len + 0.0001) / maxR;
|
double fB = (maxX - minX + 0.0001) / maxR;
|
||||||
double correction = (1 + 1.0 / (2 * fB));
|
double correction = (1 + 1.0 / (2 * fB));
|
||||||
|
|
||||||
// Correct body data in map
|
// Correct body data in map
|
||||||
@ -483,8 +493,6 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (finFriction + correction * bodyFriction) / conditions.getRefArea();
|
return (finFriction + correction * bodyFriction) / conditions.getRefArea();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,7 +510,6 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
Map<RocketComponent, AerodynamicForces> map, WarningSet warnings) {
|
Map<RocketComponent, AerodynamicForces> map, WarningSet warnings) {
|
||||||
|
|
||||||
double stagnation, base, total;
|
double stagnation, base, total;
|
||||||
double radius = 0;
|
|
||||||
|
|
||||||
if (calcMap == null)
|
if (calcMap == null)
|
||||||
buildCalcMap(configuration);
|
buildCalcMap(configuration);
|
||||||
@ -511,36 +518,47 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
base = calculateBaseCD(conditions.getMach());
|
base = calculateBaseCD(conditions.getMach());
|
||||||
|
|
||||||
total = 0;
|
total = 0;
|
||||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
final InstanceMap imap = configuration.getActiveInstances();
|
||||||
|
for(Map.Entry<RocketComponent, ArrayList<InstanceContext>> entry: imap.entrySet() ) {
|
||||||
|
final RocketComponent c = entry.getKey();
|
||||||
if (!c.isAerodynamic())
|
if (!c.isAerodynamic())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Pressure fore drag
|
// iterate across component instances
|
||||||
double cd = calcMap.get(c).calculatePressureDragForce(conditions, stagnation, base,
|
final ArrayList<InstanceContext> contextList = entry.getValue();
|
||||||
warnings);
|
for(InstanceContext context: contextList ) {
|
||||||
total += cd;
|
|
||||||
|
|
||||||
if (map != null) {
|
// Pressure fore drag
|
||||||
map.get(c).setPressureCD(cd);
|
double cd = calcMap.get(c).calculatePressureDragForce(conditions, stagnation, base,
|
||||||
}
|
warnings);
|
||||||
|
total += cd;
|
||||||
|
|
||||||
if(c.isCDOverridden()) continue;
|
if (map != null) {
|
||||||
|
map.get(c).setPressureCD(cd);
|
||||||
|
|
||||||
// Stagnation drag
|
|
||||||
if (c instanceof SymmetricComponent) {
|
|
||||||
SymmetricComponent s = (SymmetricComponent) c;
|
|
||||||
|
|
||||||
if (radius < s.getForeRadius()) {
|
|
||||||
double area = Math.PI * (pow2(s.getForeRadius()) - pow2(radius));
|
|
||||||
cd = stagnation * area / conditions.getRefArea();
|
|
||||||
total += cd;
|
|
||||||
if (map != null) {
|
|
||||||
map.get(c).setPressureCD(map.get(c).getPressureCD() + cd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
radius = s.getAftRadius();
|
if(c.isCDOverridden())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Stagnation drag
|
||||||
|
if (c instanceof SymmetricComponent) {
|
||||||
|
SymmetricComponent s = (SymmetricComponent) c;
|
||||||
|
|
||||||
|
double radius = 0;
|
||||||
|
final SymmetricComponent prevComponent = s.getPreviousSymmetricComponent();
|
||||||
|
if (prevComponent != null)
|
||||||
|
radius = prevComponent.getAftRadius();
|
||||||
|
|
||||||
|
if (radius < s.getForeRadius()) {
|
||||||
|
double area = Math.PI * (pow2(s.getForeRadius()) - pow2(radius));
|
||||||
|
cd = stagnation * area / conditions.getRefArea();
|
||||||
|
total += cd;
|
||||||
|
|
||||||
|
if (map != null) {
|
||||||
|
map.get(c).setPressureCD(map.get(c).getPressureCD() + cd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -558,11 +576,9 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private double calculateBaseDrag(FlightConfiguration configuration, FlightConditions conditions,
|
private double calculateBaseDrag(FlightConfiguration configuration, FlightConditions conditions,
|
||||||
Map<RocketComponent, AerodynamicForces> map, WarningSet warnings) {
|
Map<RocketComponent, AerodynamicForces> map, WarningSet warnings) {
|
||||||
|
|
||||||
double base, total;
|
double base, total;
|
||||||
double radius = 0;
|
|
||||||
RocketComponent prevComponent = null;
|
|
||||||
|
|
||||||
if (calcMap == null)
|
if (calcMap == null)
|
||||||
buildCalcMap(configuration);
|
buildCalcMap(configuration);
|
||||||
@ -570,36 +586,51 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator {
|
|||||||
base = calculateBaseCD(conditions.getMach());
|
base = calculateBaseCD(conditions.getMach());
|
||||||
total = 0;
|
total = 0;
|
||||||
|
|
||||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
final InstanceMap imap = configuration.getActiveInstances();
|
||||||
|
for(Map.Entry<RocketComponent, ArrayList<InstanceContext>> entry: imap.entrySet() ) {
|
||||||
|
final RocketComponent c = entry.getKey();
|
||||||
|
|
||||||
if (!(c instanceof SymmetricComponent))
|
if (!(c instanceof SymmetricComponent))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SymmetricComponent s = (SymmetricComponent) c;
|
SymmetricComponent s = (SymmetricComponent) c;
|
||||||
|
|
||||||
if(c.isCDOverridden()) {
|
// iterate across component instances
|
||||||
total += c.getOverrideCD();
|
final ArrayList<InstanceContext> contextList = entry.getValue();
|
||||||
continue;
|
for(InstanceContext context: contextList ) {
|
||||||
}
|
if(c.isCDOverridden()) {
|
||||||
|
total += c.getOverrideCD();
|
||||||
if (radius > s.getForeRadius()) {
|
continue;
|
||||||
double area = Math.PI * (pow2(radius) - pow2(s.getForeRadius()));
|
|
||||||
double cd = base * area / conditions.getRefArea();
|
|
||||||
total += cd;
|
|
||||||
if (map != null) {
|
|
||||||
map.get(prevComponent).setBaseCD(cd);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
radius = s.getAftRadius();
|
// if aft radius of previous component is greater than my forward radius, set
|
||||||
prevComponent = c;
|
// its aft CD
|
||||||
}
|
double radius = 0;
|
||||||
|
final SymmetricComponent prevComponent = s.getPreviousSymmetricComponent();
|
||||||
|
if (prevComponent != null) {
|
||||||
|
radius = prevComponent.getAftRadius();
|
||||||
|
}
|
||||||
|
|
||||||
if (radius > 0) {
|
if (radius > s.getForeRadius()) {
|
||||||
double area = Math.PI * pow2(radius);
|
double area = Math.PI * (pow2(radius) - pow2(s.getForeRadius()));
|
||||||
double cd = base * area / conditions.getRefArea();
|
double cd = base * area / conditions.getRefArea();
|
||||||
total += cd;
|
total += cd;
|
||||||
if (map != null) {
|
if ((map != null) && (prevComponent != null)) {
|
||||||
map.get(prevComponent).setBaseCD(cd);
|
map.get(prevComponent).setBaseCD(cd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if I'm the last componenet, set my base CD
|
||||||
|
// note I can't depend on the iterator serving up components in order,
|
||||||
|
// so I can't just do this after the last iteration.
|
||||||
|
if (s.getNextSymmetricComponent() == null) {
|
||||||
|
double area = Math.PI * pow2(s.getAftRadius());
|
||||||
|
double cd = base * area / conditions.getRefArea();
|
||||||
|
total += cd;
|
||||||
|
if (map != null) {
|
||||||
|
map.get(s).setBaseCD(cd);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -645,7 +645,7 @@ public class FinSetCalc extends RocketComponentCalc {
|
|||||||
// Airfoil assumed to have zero base drag
|
// Airfoil assumed to have zero base drag
|
||||||
|
|
||||||
// Scale to correct reference area
|
// Scale to correct reference area
|
||||||
drag *= finCount * span * thickness / conditions.getRefArea();
|
drag *= span * thickness / conditions.getRefArea();
|
||||||
|
|
||||||
return drag;
|
return drag;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import java.util.Collection;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.sf.openrocket.preset.ComponentPreset;
|
import net.sf.openrocket.preset.ComponentPreset;
|
||||||
|
import net.sf.openrocket.rocketcomponent.PodSet;
|
||||||
import net.sf.openrocket.rocketcomponent.position.AxialMethod;
|
import net.sf.openrocket.rocketcomponent.position.AxialMethod;
|
||||||
import net.sf.openrocket.util.Coordinate;
|
import net.sf.openrocket.util.Coordinate;
|
||||||
import net.sf.openrocket.util.MathUtil;
|
import net.sf.openrocket.util.MathUtil;
|
||||||
@ -561,34 +562,37 @@ public abstract class SymmetricComponent extends BodyComponent implements Radial
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the previous symmetric component, or null if none exists.
|
* Return the previous symmetric component, or null if none exists.
|
||||||
* NOTE: This method currently assumes that there are no external
|
|
||||||
* "pods".
|
|
||||||
*
|
*
|
||||||
* @return the previous SymmetricComponent, or null.
|
* @return the previous SymmetricComponent, or null.
|
||||||
*/
|
*/
|
||||||
protected final SymmetricComponent getPreviousSymmetricComponent() {
|
public final SymmetricComponent getPreviousSymmetricComponent() {
|
||||||
RocketComponent c;
|
RocketComponent c;
|
||||||
for (c = this.getPreviousComponent(); c != null; c = c.getPreviousComponent()) {
|
for (c = this.getPreviousComponent(); c != null; c = c.getPreviousComponent()) {
|
||||||
|
if (c instanceof PodSet) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (c instanceof SymmetricComponent) {
|
if (c instanceof SymmetricComponent) {
|
||||||
return (SymmetricComponent) c;
|
return (SymmetricComponent) c;
|
||||||
}
|
}
|
||||||
if (!(c instanceof AxialStage) &&
|
if (!(c instanceof AxialStage) &&
|
||||||
(c.axialMethod == AxialMethod.AFTER))
|
(c.axialMethod == AxialMethod.AFTER)) {
|
||||||
return null; // Bad component type as "parent"
|
return null; // Bad component type as "parent"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the next symmetric component, or null if none exists.
|
* Return the next symmetric component, or null if none exists.
|
||||||
* NOTE: This method currently assumes that there are no external
|
|
||||||
* "pods".
|
|
||||||
*
|
*
|
||||||
* @return the next SymmetricComponent, or null.
|
* @return the next SymmetricComponent, or null.
|
||||||
*/
|
*/
|
||||||
protected final SymmetricComponent getNextSymmetricComponent() {
|
public final SymmetricComponent getNextSymmetricComponent() {
|
||||||
RocketComponent c;
|
RocketComponent c;
|
||||||
for (c = this.getNextComponent(); c != null; c = c.getNextComponent()) {
|
for (c = this.getNextComponent(); c != null; c = c.getNextComponent()) {
|
||||||
|
if (c instanceof PodSet) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if (c instanceof SymmetricComponent) {
|
if (c instanceof SymmetricComponent) {
|
||||||
return (SymmetricComponent) c;
|
return (SymmetricComponent) c;
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
package net.sf.openrocket.util;
|
package net.sf.openrocket.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import net.sf.openrocket.appearance.Appearance;
|
import net.sf.openrocket.appearance.Appearance;
|
||||||
import net.sf.openrocket.file.openrocket.OpenRocketSaver;
|
|
||||||
import net.sf.openrocket.database.Databases;
|
import net.sf.openrocket.database.Databases;
|
||||||
import net.sf.openrocket.document.OpenRocketDocument;
|
import net.sf.openrocket.document.OpenRocketDocument;
|
||||||
import net.sf.openrocket.document.OpenRocketDocumentFactory;
|
import net.sf.openrocket.document.OpenRocketDocumentFactory;
|
||||||
import net.sf.openrocket.document.Simulation;
|
import net.sf.openrocket.document.Simulation;
|
||||||
|
import net.sf.openrocket.file.openrocket.OpenRocketSaver;
|
||||||
import net.sf.openrocket.material.Material;
|
import net.sf.openrocket.material.Material;
|
||||||
import net.sf.openrocket.material.Material.Type;
|
import net.sf.openrocket.material.Material.Type;
|
||||||
import net.sf.openrocket.motor.Manufacturer;
|
import net.sf.openrocket.motor.Manufacturer;
|
||||||
@ -34,6 +37,8 @@ import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
|||||||
import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
|
import net.sf.openrocket.rocketcomponent.FlightConfigurationId;
|
||||||
import net.sf.openrocket.rocketcomponent.FreeformFinSet;
|
import net.sf.openrocket.rocketcomponent.FreeformFinSet;
|
||||||
import net.sf.openrocket.rocketcomponent.InnerTube;
|
import net.sf.openrocket.rocketcomponent.InnerTube;
|
||||||
|
import net.sf.openrocket.rocketcomponent.InstanceContext;
|
||||||
|
import net.sf.openrocket.rocketcomponent.InstanceMap;
|
||||||
import net.sf.openrocket.rocketcomponent.InternalComponent;
|
import net.sf.openrocket.rocketcomponent.InternalComponent;
|
||||||
import net.sf.openrocket.rocketcomponent.LaunchLug;
|
import net.sf.openrocket.rocketcomponent.LaunchLug;
|
||||||
import net.sf.openrocket.rocketcomponent.MassComponent;
|
import net.sf.openrocket.rocketcomponent.MassComponent;
|
||||||
@ -1630,4 +1635,53 @@ public class TestRockets {
|
|||||||
return rocketDoc;
|
return rocketDoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Alpha III modified to put fins on "phantom" pods
|
||||||
|
public static final Rocket makeEstesAlphaIIIWithPods() {
|
||||||
|
Rocket rocket = TestRockets.makeEstesAlphaIII();
|
||||||
|
|
||||||
|
// find the body and fins
|
||||||
|
final InstanceMap imap = rocket.getSelectedConfiguration().getActiveInstances();
|
||||||
|
for(Map.Entry<RocketComponent, ArrayList<InstanceContext>> entry: imap.entrySet() ) {
|
||||||
|
RocketComponent c = entry.getKey();
|
||||||
|
if (c instanceof TrapezoidFinSet) {
|
||||||
|
final TrapezoidFinSet fins = (TrapezoidFinSet) c;
|
||||||
|
final BodyTube body = (BodyTube) fins.getParent();
|
||||||
|
body.removeChild(fins);
|
||||||
|
|
||||||
|
// create a PodSet to hook the fins to
|
||||||
|
PodSet podset = new PodSet();
|
||||||
|
podset.setInstanceCount(fins.getFinCount());
|
||||||
|
|
||||||
|
body.addChild(podset);
|
||||||
|
|
||||||
|
// put a phantom body tube on the pods
|
||||||
|
BodyTube podBody = new BodyTube(fins.getRootChord(), 0);
|
||||||
|
podBody.setName("Pod Body");
|
||||||
|
podset.addChild(podBody);
|
||||||
|
|
||||||
|
// change the number of fins to 1 and put the revised
|
||||||
|
// finset on the podbody
|
||||||
|
fins.setFinCount(1);
|
||||||
|
podBody.addChild(fins);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dump a test rocket to a file, so we can open it in OR
|
||||||
|
*/
|
||||||
|
static void dumpRocket(Rocket rocket, String filename) {
|
||||||
|
|
||||||
|
OpenRocketDocument doc = OpenRocketDocumentFactory.createDocumentFromRocket(rocket);
|
||||||
|
OpenRocketSaver saver = new OpenRocketSaver();
|
||||||
|
try {
|
||||||
|
FileOutputStream str = new FileOutputStream(filename);
|
||||||
|
saver.save(str, doc, null);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
System.err.println("exception " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,4 +231,50 @@ public class BarrowmanCalculatorTest {
|
|||||||
|
|
||||||
assertFalse(" Missed discontinuity in Falcon 9 Heavy:", calc.isContinuous( rocket));
|
assertFalse(" Missed discontinuity in Falcon 9 Heavy:", calc.isContinuous( rocket));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPhantomTubes() {
|
||||||
|
Rocket rocketNoPods = TestRockets.makeEstesAlphaIII();
|
||||||
|
FlightConfiguration configNoPods = rocketNoPods.getSelectedConfiguration();
|
||||||
|
FlightConditions conditionsNoPods = new FlightConditions(configNoPods);
|
||||||
|
WarningSet warningsNoPods = new WarningSet();
|
||||||
|
|
||||||
|
Rocket rocketWithPods = TestRockets.makeEstesAlphaIIIWithPods();
|
||||||
|
FlightConfiguration configPods = rocketWithPods.getSelectedConfiguration();
|
||||||
|
FlightConditions conditionsPods = new FlightConditions(configPods);
|
||||||
|
WarningSet warningsPods = new WarningSet();
|
||||||
|
AerodynamicCalculator calcPods = new BarrowmanCalculator();
|
||||||
|
AerodynamicCalculator calcNoPods = new BarrowmanCalculator();
|
||||||
|
|
||||||
|
final AerodynamicForces forcesNoPods = calcPods.getAerodynamicForces(configNoPods, conditionsNoPods, warningsNoPods);
|
||||||
|
final AerodynamicForces forcesPods = calcPods.getAerodynamicForces(configPods, conditionsPods, warningsPods);
|
||||||
|
assertEquals(" Estes Alpha III With Pods rocket CD value is incorrect:", forcesPods.getCD(), forcesNoPods.getCD(), EPSILON);
|
||||||
|
|
||||||
|
// The "with pods" version has no way of seeing the fins are
|
||||||
|
// on the actual body tube rather than the phantom tubes,
|
||||||
|
// so CD won't take fin-body interference into consideration.
|
||||||
|
// So we'll adjust our CD in these tests. The magic numbers
|
||||||
|
// in x and w come from temporarily disabling the
|
||||||
|
// interference calculation in FinSetCalc and comparing
|
||||||
|
// results with and without it
|
||||||
|
// cpNoPods (0.34125,0.00000,0.00000,w=16.20502) -- interference disabled
|
||||||
|
// cpNoPods (0.34797,0.00000,0.00000,w=19.34773) -- interference enabled
|
||||||
|
|
||||||
|
// another note: the fact that this is seen as three one-fin
|
||||||
|
// FinSets instead of a single three-fin FinSet means the CP
|
||||||
|
// will be off-axis (one of the fins is taken as having an
|
||||||
|
// angle of 0 to the airstream, so it has no contribution).
|
||||||
|
// This doesn't turn out to cause a problem in an actual
|
||||||
|
// simulation.
|
||||||
|
|
||||||
|
final Coordinate cpNoPods = calcNoPods.getCP(configNoPods, conditionsNoPods, warningsNoPods);
|
||||||
|
final Coordinate cpPods = calcPods.getCP(configPods, conditionsPods, warningsPods);
|
||||||
|
System.out.printf("with pods %s\n", cpPods.toString());
|
||||||
|
System.out.printf("without pods %s\n", cpNoPods.toString());
|
||||||
|
assertEquals(" Alpha III With Pods rocket cp x value is incorrect:", cpNoPods.x - 0.002788761352, cpPods.x, EPSILON);
|
||||||
|
assertEquals(" Alpha III With Pods rocket cp y value is incorrect:", cpNoPods.y - 0.005460218430206499, cpPods.y, EPSILON);
|
||||||
|
assertEquals(" Alpha III With Pods rocket cp z value is incorrect:", cpNoPods.z, cpPods.z, EPSILON);
|
||||||
|
assertEquals(" Alpha III With Pods rocket CNa value is incorrect:", cpPods.weight, cpNoPods.weight - 3.91572, EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user