From 2e7b3da1c0dc44286935627a5aa6d576da1f71ca Mon Sep 17 00:00:00 2001 From: JoePfeiffer Date: Wed, 30 Jan 2019 15:10:41 -0700 Subject: [PATCH] Addresses Issue 481 Modify BarrowmanCalculator to use InstanceMap and InstanceContext to iterate through all components. This addresses 481 by actually computing nonaxial forces for all components, instead of computing a single instanceable component and using it as a representative of all instances. Modify calculateNonAxialForces to accept a Transformation argument, so they can use rotations from instances (only actually affects FinSetCalc and TubeFinSetCalc) --- .../aerodynamics/BarrowmanCalculator.java | 100 ++++++++---------- .../aerodynamics/barrowman/FinSetCalc.java | 6 +- .../aerodynamics/barrowman/LaunchLugCalc.java | 3 +- .../barrowman/RocketComponentCalc.java | 6 +- .../barrowman/SymmetricComponentCalc.java | 3 +- .../barrowman/TubeFinSetCalc.java | 5 +- .../sf/openrocket/util/Transformation.java | 20 ++++ .../aerodynamics/FinSetCalcTest.java | 7 +- .../SymmetricComponentCalcTest.java | 7 +- .../rocketcomponent/FreeformFinSetTest.java | 4 +- 10 files changed, 94 insertions(+), 67 deletions(-) diff --git a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java index 675ffde0f..260e57f4a 100644 --- a/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java +++ b/core/src/net/sf/openrocket/aerodynamics/BarrowmanCalculator.java @@ -2,6 +2,7 @@ package net.sf.openrocket.aerodynamics; import static net.sf.openrocket.util.MathUtil.pow2; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; @@ -10,6 +11,9 @@ import java.util.LinkedList; import java.util.Map; import java.util.Queue; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import net.sf.openrocket.aerodynamics.barrowman.FinSetCalc; import net.sf.openrocket.aerodynamics.barrowman.RocketComponentCalc; import net.sf.openrocket.rocketcomponent.ComponentAssembly; @@ -17,6 +21,8 @@ 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.InstanceContext; +import net.sf.openrocket.rocketcomponent.InstanceMap; import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.rocketcomponent.SymmetricComponent; @@ -24,6 +30,7 @@ import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.PolyInterpolator; import net.sf.openrocket.util.Reflection; +import net.sf.openrocket.util.Transformation; /** * An aerodynamic calculator that uses the extended Barrowman method to @@ -36,6 +43,8 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { private static final String BARROWMAN_PACKAGE = "net.sf.openrocket.aerodynamics.barrowman"; private static final String BARROWMAN_SUFFIX = "Calc"; + private static final Logger log = LoggerFactory.getLogger(BarrowmanCalculator.class); + private Map calcMap = null; @@ -176,65 +185,50 @@ public class BarrowmanCalculator extends AbstractAerodynamicCalculator { warnings.add( Warning.DIAMETER_DISCONTINUITY); } - 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 InstanceMap imap = configuration.getActiveInstances(); + 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); + + // iterate through all components + for(Map.Entry> entry: imap.entrySet() ) { + final RocketComponent comp = entry.getKey(); + RocketComponentCalc calcObj = calcMap.get(comp); + log.debug("comp=" + comp); - Coordinate cp_comp = componentForces.getCP(); - - Coordinate cp_weighted = cp_comp.setWeight(cp_comp.weight); - Coordinate cp_absolute = component.toAbsolute(cp_weighted)[0]; - if(1 < component.getInstanceCount()) { - cp_absolute = cp_absolute.setY(0.).setZ(0.); + if (null != calcObj) { + // iterate across component instances + final ArrayList contextList = entry.getValue(); + + for(InstanceContext context: contextList ) { + // since FinSetCalc calculates forces for entire FinSet + // only consider first fin in each set (happily, + // in each instance of a PodSet or similar + // instanceable RocketComponent with childre, the + // child FinSets all start numbering with 0 + if (!(comp instanceof FinSet) || (context.instanceNumber == 0)) { + AerodynamicForces instanceForces = new AerodynamicForces().zero(); + + calcObj.calculateNonaxialForces(conditions, context.transform, instanceForces, warnings); + log.debug("instanceForces[" + context.instanceNumber + "]=" + instanceForces); + Coordinate cp_comp = instanceForces.getCP(); + + Coordinate cp_abs = context.transform.transform(cp_comp); + + instanceForces.setCP(cp_abs); + double CN_instanced = instanceForces.getCN(); + instanceForces.setCm(CN_instanced * instanceForces.getCP().x / conditions.getRefLength()); + + log.debug("instanceForces=" + instanceForces); + assemblyForces.merge(instanceForces); + } + } } - - componentForces.setCP(cp_absolute); - double CN_instanced = componentForces.getCN(); - componentForces.setCm(CN_instanced * componentForces.getCP().x / conditions.getRefLength()); - -// if( 0.0001 < Math.abs(componentForces.getCNa())){ -// final Coordinate cp = assemblyForces.getCP(); -// System.err.println(String.format("%s....Component.CNa: %g @ CP: { %f, %f, %f}", indent, componentForces.getCNa(), cp.x, cp.y, cp.z)); -// } - - assemblyForces.merge(componentForces); - } - -// if( 0.0001 < Math.abs(0 - assemblyForces.getCNa())){ -// final Coordinate cp = assemblyForces.getCP(); -// System.err.println(String.format("%s....Assembly.CNa: %g @ CP: { %f, %f, %f}", indent, assemblyForces.getCNa(), cp.x, cp.y, cp.z)); -// } - - if( component.allowsChildren() && (component.getInstanceCount() > 1)) { - return assemblyForces.multiplex(component.getInstanceCount()); - }else { - return assemblyForces; } + + log.debug("assemblyForces=" + assemblyForces); + return assemblyForces; } - @Override public boolean isContinuous( final Rocket rkt){ return testIsContinuous( rkt); diff --git a/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java b/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java index e56f26df6..66e193de5 100644 --- a/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java +++ b/core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java @@ -16,7 +16,7 @@ import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.LinearInterpolator; import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.PolyInterpolator; - +import net.sf.openrocket.util.Transformation; public class FinSetCalc extends RocketComponentCalc { @@ -84,7 +84,7 @@ public class FinSetCalc extends RocketComponentCalc { * (normal and side forces, pitch, yaw and roll moments, CP position, CNa). */ @Override - public void calculateNonaxialForces(FlightConditions conditions, + public void calculateNonaxialForces(FlightConditions conditions, Transformation transform, AerodynamicForces forces, WarningSet warnings) { if (span < 0.001) { @@ -114,7 +114,7 @@ public class FinSetCalc extends RocketComponentCalc { // Multiple fins with fin-fin interference double cna; double theta = conditions.getTheta(); - double angle = baseRotation; + double angle = baseRotation + transform.getXrotation(); // Compute basic CNa without interference effects if (finCount == 1 || finCount == 2) { diff --git a/core/src/net/sf/openrocket/aerodynamics/barrowman/LaunchLugCalc.java b/core/src/net/sf/openrocket/aerodynamics/barrowman/LaunchLugCalc.java index cd7fea012..99329280d 100644 --- a/core/src/net/sf/openrocket/aerodynamics/barrowman/LaunchLugCalc.java +++ b/core/src/net/sf/openrocket/aerodynamics/barrowman/LaunchLugCalc.java @@ -6,6 +6,7 @@ import net.sf.openrocket.aerodynamics.WarningSet; import net.sf.openrocket.rocketcomponent.LaunchLug; import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.util.MathUtil; +import net.sf.openrocket.util.Transformation; public class LaunchLugCalc extends RocketComponentCalc { @@ -24,7 +25,7 @@ public class LaunchLugCalc extends RocketComponentCalc { } @Override - public void calculateNonaxialForces(FlightConditions conditions, + public void calculateNonaxialForces(FlightConditions conditions, Transformation transform, AerodynamicForces forces, WarningSet warnings) { // Nothing to be done } diff --git a/core/src/net/sf/openrocket/aerodynamics/barrowman/RocketComponentCalc.java b/core/src/net/sf/openrocket/aerodynamics/barrowman/RocketComponentCalc.java index 71f4ef0cf..900b507d9 100644 --- a/core/src/net/sf/openrocket/aerodynamics/barrowman/RocketComponentCalc.java +++ b/core/src/net/sf/openrocket/aerodynamics/barrowman/RocketComponentCalc.java @@ -4,6 +4,7 @@ import net.sf.openrocket.aerodynamics.AerodynamicForces; import net.sf.openrocket.aerodynamics.FlightConditions; import net.sf.openrocket.aerodynamics.WarningSet; import net.sf.openrocket.rocketcomponent.RocketComponent; +import net.sf.openrocket.util.Transformation; public abstract class RocketComponentCalc { @@ -20,11 +21,12 @@ public abstract class RocketComponentCalc { * computed around the local origin. * * @param conditions the flight conditions. + * @param transform transformation from InstanceMap to get rotations rotations * @param forces the object in which to store the values. * @param warnings set in which to store possible warnings. */ - public abstract void calculateNonaxialForces(FlightConditions conditions, - AerodynamicForces forces, WarningSet warnings); + public abstract void calculateNonaxialForces(FlightConditions conditions, Transformation transform, + AerodynamicForces forces, WarningSet warnings); /** diff --git a/core/src/net/sf/openrocket/aerodynamics/barrowman/SymmetricComponentCalc.java b/core/src/net/sf/openrocket/aerodynamics/barrowman/SymmetricComponentCalc.java index 1bfcfa2ee..6fa72428b 100644 --- a/core/src/net/sf/openrocket/aerodynamics/barrowman/SymmetricComponentCalc.java +++ b/core/src/net/sf/openrocket/aerodynamics/barrowman/SymmetricComponentCalc.java @@ -16,6 +16,7 @@ import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.LinearInterpolator; import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.PolyInterpolator; +import net.sf.openrocket.util.Transformation; @@ -95,7 +96,7 @@ public class SymmetricComponentCalc extends RocketComponentCalc { * subsonic speeds. */ @Override - public void calculateNonaxialForces(FlightConditions conditions, + public void calculateNonaxialForces(FlightConditions conditions, Transformation transform, AerodynamicForces forces, WarningSet warnings) { // Pre-calculate and store the results diff --git a/core/src/net/sf/openrocket/aerodynamics/barrowman/TubeFinSetCalc.java b/core/src/net/sf/openrocket/aerodynamics/barrowman/TubeFinSetCalc.java index d6e1d56d7..1efab0c04 100644 --- a/core/src/net/sf/openrocket/aerodynamics/barrowman/TubeFinSetCalc.java +++ b/core/src/net/sf/openrocket/aerodynamics/barrowman/TubeFinSetCalc.java @@ -17,6 +17,7 @@ import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.LinearInterpolator; import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.PolyInterpolator; +import net.sf.openrocket.util.Transformation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -92,7 +93,7 @@ public class TubeFinSetCalc extends RocketComponentCalc { * pitch, yaw and roll moments, CP position, CNa). */ @Override - public void calculateNonaxialForces(FlightConditions conditions, + public void calculateNonaxialForces(FlightConditions conditions, Transformation transform, AerodynamicForces forces, WarningSet warnings) { if (span < 0.001) { @@ -124,7 +125,7 @@ public class TubeFinSetCalc extends RocketComponentCalc { // Multiple fins with fin-fin interference double cna; double theta = conditions.getTheta(); - double angle = baseRotation; + double angle = baseRotation + transform.getXrotation(); // Compute basic CNa without interference effects if (finCount == 1 || finCount == 2) { diff --git a/core/src/net/sf/openrocket/util/Transformation.java b/core/src/net/sf/openrocket/util/Transformation.java index d31bb7906..b40d9041c 100644 --- a/core/src/net/sf/openrocket/util/Transformation.java +++ b/core/src/net/sf/openrocket/util/Transformation.java @@ -374,5 +374,25 @@ public class Transformation implements java.io.Serializable { public Coordinate getTranslationVector() { return this.translate; } + + /** + * Calculate X, Y, and Z rotation angles from rotation matrices + */ + public double getXrotation() { + return Math.atan2((rotation[2][1] - rotation[1][2])/2.0, + (rotation[1][1] + rotation[2][2])/2.0); + } + + public double getYrotation() { + return Math.atan2((rotation[0][2] - rotation[2][0])/2.0, + (rotation[0][0] + rotation[2][2])/2.0); + } + + public double getZrotation() { + return Math.atan2((rotation[1][0] - rotation[0][1])/2.0, + (rotation[0][0] + rotation[1][1])/2.0); + + } + } diff --git a/core/test/net/sf/openrocket/aerodynamics/FinSetCalcTest.java b/core/test/net/sf/openrocket/aerodynamics/FinSetCalcTest.java index 7eb12199f..ab677fb32 100644 --- a/core/test/net/sf/openrocket/aerodynamics/FinSetCalcTest.java +++ b/core/test/net/sf/openrocket/aerodynamics/FinSetCalcTest.java @@ -16,6 +16,7 @@ import net.sf.openrocket.rocketcomponent.Rocket; import net.sf.openrocket.rocketcomponent.TrapezoidFinSet; import net.sf.openrocket.startup.Application; import net.sf.openrocket.util.TestRockets; +import net.sf.openrocket.util.Transformation; public class FinSetCalcTest { protected final double EPSILON = 0.0001; @@ -50,6 +51,7 @@ public class FinSetCalcTest { assertEquals(" Estes Alpha III fins have wrong height: ", 0.05, fins.getHeight(), EPSILON); FlightConfiguration config = rocket.getSelectedConfiguration(); + Transformation transform = Transformation.IDENTITY; FlightConditions conditions = new FlightConditions(config); WarningSet warnings = new WarningSet(); AerodynamicForces forces = new AerodynamicForces(); @@ -57,7 +59,7 @@ public class FinSetCalcTest { // vvv TEST MEH! vvv - calcObj.calculateNonaxialForces(conditions, forces, warnings); + calcObj.calculateNonaxialForces(conditions, transform, forces, warnings); // ^^^ double exp_cna_fins = 24.146933; @@ -84,6 +86,7 @@ public class FinSetCalcTest { assertEquals(" Estes Alpha III fins have wrong height: ", 0.05, fins.getHeight(), EPSILON); FlightConfiguration config = rocket.getSelectedConfiguration(); + Transformation transform = Transformation.IDENTITY; FlightConditions conditions = new FlightConditions(config); WarningSet warnings = new WarningSet(); AerodynamicForces forces = new AerodynamicForces(); @@ -91,7 +94,7 @@ public class FinSetCalcTest { // vvv TEST MEH! vvv - calcObj.calculateNonaxialForces(conditions, forces, warnings); + calcObj.calculateNonaxialForces(conditions, transform, forces, warnings); // ^^^ double exp_cna_fins = 32.195911; diff --git a/core/test/net/sf/openrocket/aerodynamics/SymmetricComponentCalcTest.java b/core/test/net/sf/openrocket/aerodynamics/SymmetricComponentCalcTest.java index 3fb44f26e..83bee1322 100644 --- a/core/test/net/sf/openrocket/aerodynamics/SymmetricComponentCalcTest.java +++ b/core/test/net/sf/openrocket/aerodynamics/SymmetricComponentCalcTest.java @@ -18,6 +18,7 @@ import net.sf.openrocket.rocketcomponent.Transition; import net.sf.openrocket.startup.Application; import net.sf.openrocket.util.MathUtil; import net.sf.openrocket.util.TestRockets; +import net.sf.openrocket.util.Transformation; public class SymmetricComponentCalcTest { protected final double EPSILON = MathUtil.EPSILON*1000; @@ -52,13 +53,14 @@ public class SymmetricComponentCalcTest { FlightConfiguration config = rocket.getSelectedConfiguration(); FlightConditions conditions = new FlightConditions(config); + Transformation transform = Transformation.IDENTITY; WarningSet warnings = new WarningSet(); AerodynamicForces forces = new AerodynamicForces(); SymmetricComponentCalc calcObj = new SymmetricComponentCalc( nose ); conditions.setAOA(0.0); // vvv TEST MEH! vvv - calcObj.calculateNonaxialForces(conditions, forces, warnings); + calcObj.calculateNonaxialForces(conditions, transform, forces, warnings); // ^^^ double cna_nose = 2; @@ -82,13 +84,14 @@ public class SymmetricComponentCalcTest { FlightConfiguration config = rocket.getSelectedConfiguration(); FlightConditions conditions = new FlightConditions(config); + Transformation transform = Transformation.IDENTITY; WarningSet warnings = new WarningSet(); AerodynamicForces forces = new AerodynamicForces(); SymmetricComponentCalc calcObj = new SymmetricComponentCalc( nose ); conditions.setAOA(0.0); // vvv TEST vvv - calcObj.calculateNonaxialForces(conditions, forces, warnings); + calcObj.calculateNonaxialForces(conditions, transform, forces, warnings); // ^^^ ^^^ double l_nose = nose.getLength(); diff --git a/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java b/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java index 38499750c..a0c0d0697 100644 --- a/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java +++ b/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java @@ -23,6 +23,7 @@ import net.sf.openrocket.util.Color; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.LineStyle; import net.sf.openrocket.util.BaseTestCase.BaseTestCase; +import net.sf.openrocket.util.Transformation; public class FreeformFinSetTest extends BaseTestCase { @@ -1203,9 +1204,10 @@ public class FreeformFinSetTest extends BaseTestCase { bt.addChild(fins); FinSetCalc calc = new FinSetCalc(fins); FlightConditions conditions = new FlightConditions(null); + Transformation transform = Transformation.IDENTITY; AerodynamicForces forces = new AerodynamicForces(); WarningSet warnings = new WarningSet(); - calc.calculateNonaxialForces(conditions, forces, warnings); + calc.calculateNonaxialForces(conditions, transform, forces, warnings); //System.out.println(forces); assertEquals(0.023409, forces.getCP().x, 0.0001); }