diff --git a/core/src/net/sf/openrocket/aerodynamics/AerodynamicForces.java b/core/src/net/sf/openrocket/aerodynamics/AerodynamicForces.java index cbfc3ddb7..da41651be 100644 --- a/core/src/net/sf/openrocket/aerodynamics/AerodynamicForces.java +++ b/core/src/net/sf/openrocket/aerodynamics/AerodynamicForces.java @@ -286,7 +286,7 @@ public class AerodynamicForces implements Cloneable, Monitorable { /** * Zero all values to 0 / Coordinate.NUL. Component is left as it was. */ - public void zero() { + public AerodynamicForces zero() { // component untouched setAxisymmetric(true); @@ -303,6 +303,8 @@ public class AerodynamicForces implements Cloneable, Monitorable { setCD(0); setPitchDampingMoment(0); setYawDampingMoment(0); + + return this; } @@ -388,4 +390,39 @@ public class AerodynamicForces implements Cloneable, Monitorable { public int getModID() { return modID; } + + public AerodynamicForces merge(AerodynamicForces other) { + + this.cp = cp.average(other.getCP()); + this.CNa = CNa + other.getCNa(); + this.CN = CN + other.getCN(); + this.Cm = Cm + other.getCm(); + this.Cside = Cside + other.getCside(); + this.Cyaw = Cyaw + other.getCyaw(); + this.Croll = Croll + other.getCroll(); + this.CrollDamp = CrollDamp + other.getCrollDamp(); + this.CrollForce = CrollForce + other.getCrollForce(); + + modID++; + + return this; + } + + public AerodynamicForces multiplex(final int instanceCount) { + + this.cp = cp.setWeight(cp.weight*instanceCount); + this.CNa = CNa*instanceCount; + this.CN = CN*instanceCount; + this.Cm = Cm*instanceCount; + this.Cside = Cside*instanceCount; + this.Cyaw = Cyaw*instanceCount; + this.Croll = Croll*instanceCount; + this.CrollDamp = CrollDamp*instanceCount; + this.CrollForce = CrollForce*instanceCount; + + modID++; + + return this; + } + } diff --git a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java index f70b959cb..ad79ec07d 100644 --- a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java +++ b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java @@ -158,22 +158,16 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { * Perform the actual CP calculation. */ private AerodynamicForces calculateNonAxialForces(FlightConfiguration configuration, FlightConditions conditions, - Map map, WarningSet warnings) { + Map calculators, WarningSet warnings) { checkCache(configuration); - AerodynamicForces total = new AerodynamicForces(); - total.zero(); - - AerodynamicForces forces = new AerodynamicForces(); - if (warnings == null) warnings = ignoreWarningSet; if (conditions.getAOA() > 17.5 * Math.PI / 180) warnings.add(new Warning.LargeAOA(conditions.getAOA())); - if (calcMap == null) buildCalcMap(configuration); @@ -182,60 +176,60 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { warnings.add( Warning.DIAMETER_DISCONTINUITY); } - for (RocketComponent component : configuration.getActiveComponents()) { - - // Skip non-aerodynamic components - if (!component.isAerodynamic()) - continue; - - - // Call calculation method - forces.zero(); - RocketComponentCalc calcObj = calcMap.get(component); - calcObj.calculateNonaxialForces(conditions, forces, warnings); - - - // previous unstable version - // int instanceCount = component.getLocations().length; - final boolean isAssembly = (component.allowsChildren() && (component.getInstanceCount() > 1)); - - // we will need to adjust the calculations *somehow* here... - - Coordinate x_cp_comp = forces.getCP(); - Coordinate x_cp_weighted = x_cp_comp.setWeight(x_cp_comp.weight); - Coordinate x_cp_absolute = component.toAbsolute(x_cp_weighted)[0]; - forces.setCP(x_cp_absolute); - double CN_instanced = forces.getCN(); - forces.setCm(CN_instanced * forces.getCP().x / conditions.getRefLength()); - - if (map != null) { - AerodynamicForces f = map.get(component); - - f.setCP(forces.getCP()); - f.setCNa(forces.getCNa()); - f.setCN(forces.getCN()); - f.setCm(forces.getCm()); - f.setCside(forces.getCside()); - f.setCyaw(forces.getCyaw()); - f.setCroll(forces.getCroll()); - f.setCrollDamp(forces.getCrollDamp()); - f.setCrollForce(forces.getCrollForce()); - } - - total.setCP(total.getCP().average(forces.getCP())); - total.setCNa(total.getCNa() + forces.getCNa()); - total.setCN(total.getCN() + forces.getCN()); - total.setCm(total.getCm() + forces.getCm()); - total.setCside(total.getCside() + forces.getCside()); - total.setCyaw(total.getCyaw() + forces.getCyaw()); - total.setCroll(total.getCroll() + forces.getCroll()); - total.setCrollDamp(total.getCrollDamp() + forces.getCrollDamp()); - total.setCrollForce(total.getCrollForce() + forces.getCrollForce()); - } + AerodynamicForces total = calculateAssemblyNonAxialForces(configuration.getRocket(), configuration, conditions, calculators, warnings, ""); return total; } + private AerodynamicForces calculateAssemblyNonAxialForces( final RocketComponent component, + FlightConfiguration configuration, FlightConditions conditions, + Map calculators, WarningSet warnings, + String indent) { + + final AerodynamicForces assemblyForces= new AerodynamicForces().zero(); + +// System.err.println(String.format("%s@@ %s <%s>", indent, component.getName(), component.getClass().getSimpleName())); + + // ==== calculate child forces ==== + for (RocketComponent child: component.getChildren()) { + AerodynamicForces childForces = calculateAssemblyNonAxialForces( child, configuration, conditions, calculators, warnings, indent+" "); + assemblyForces.merge(childForces); + } + + // calculate *this* component's forces + RocketComponentCalc calcObj = calcMap.get(component); + if(null != calcObj) { + AerodynamicForces componentForces = new AerodynamicForces().zero(); + calcObj.calculateNonaxialForces(conditions, componentForces, warnings); + + Coordinate x_cp_comp = componentForces.getCP(); + Coordinate x_cp_weighted = x_cp_comp.setWeight(x_cp_comp.weight); + Coordinate x_cp_absolute = component.toAbsolute(x_cp_weighted)[0]; + componentForces.setCP(x_cp_absolute); + double CN_instanced = componentForces.getCN(); + componentForces.setCm(CN_instanced * componentForces.getCP().x / conditions.getRefLength()); + +// if( 0.0001 < Math.abs(0 - componentForces.getCNa())){ +// System.err.println(String.format("%s....Component.CNa: %g @ CPx: %g", indent, componentForces.getCNa(), componentForces.getCP().x)); +// } + + assemblyForces.merge(componentForces); + } + +// if( 0.0001 < Math.abs(0 - assemblyForces.getCNa())){ +// System.err.println(String.format("%s....Assembly.CNa: %g @ CPx: %g", indent, assemblyForces.getCNa(), assemblyForces.getCP().x)); +// } + + // fetches instanced versions + // int instanceCount = component.getLocations().length; + + if( component.allowsChildren() && (component.getInstanceCount() > 1)) { + return assemblyForces.multiplex(component.getInstanceCount()); + }else { + return assemblyForces; + } + } + @Override public boolean isContinuous( final Rocket rkt){ diff --git a/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java b/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java index 06e67aa94..068cdf54e 100644 --- a/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java +++ b/core/test/net/sf/openrocket/aerodynamics/BarrowmanCalculatorTest.java @@ -108,7 +108,6 @@ public class BarrowmanCalculatorTest { assertEquals(" Estes Alpha III CNa value is incorrect:", exp_cna, calcCP.weight, EPSILON); } - @Test public void testCPDoubleStrapOn() { Rocket rocket = TestRockets.makeFalcon9Heavy(); @@ -117,8 +116,8 @@ public class BarrowmanCalculatorTest { FlightConditions conditions = new FlightConditions(config); WarningSet warnings = new WarningSet(); - double expCPx = 0.994642; - double expCNa = 15.437111; + double expCPx = 1.04662388; + double expCNa = 21.5111598; Coordinate calcCP = calc.getCP(config, conditions, warnings); assertEquals(" Falcon 9 Heavy CP x value is incorrect:", expCPx, calcCP.x, EPSILON);