From efacebf5d8c7c1026a4831ed88f28f75fdebbabd Mon Sep 17 00:00:00 2001 From: JoePfeiffer Date: Thu, 7 Mar 2019 18:05:44 -0700 Subject: [PATCH] Refactored MassCalculation.calculateAssembly() to separate calculation of structure from calculation of motors, so mass and CG overrides don't affect motors Modified structure calculation so that when an override is in effect and children are also being overridden, don't include root of tree as an element in its own right when computing MOI. Modified MassCalculatorTest to look for correct MOI value. --- .../openrocket/masscalc/MassCalculation.java | 160 ++++++++++++------ .../masscalc/MassCalculatorTest.java | 45 ++++- 2 files changed, 152 insertions(+), 53 deletions(-) diff --git a/core/src/net/sf/openrocket/masscalc/MassCalculation.java b/core/src/net/sf/openrocket/masscalc/MassCalculation.java index 9ecbacdc8..ca59e2019 100644 --- a/core/src/net/sf/openrocket/masscalc/MassCalculation.java +++ b/core/src/net/sf/openrocket/masscalc/MassCalculation.java @@ -246,6 +246,108 @@ public class MassCalculation { * */ /* package-scope */ MassCalculation calculateAssembly(){ + + if (this.type.includesStructure) { + MassCalculation structureCalc = this.copy(this.root, this.transform); + structureCalc.calculateStructure(); + this.merge(structureCalc); + } + + if (this.type.includesMotorCasing || this.type.includesPropellant) { + MassCalculation motorCalc = this.copy(this.root, this.transform); + motorCalc.calculateMotors(); + this.merge(motorCalc); + } + + return this; + } + + MassCalculation calculateStructure() { + final RocketComponent component = this.root; + final Transformation parentTransform = this.transform; + final int instanceCount = component.getInstanceCount(); + Coordinate[] instanceLocations = component.getInstanceLocations(); + +// // vvv DEBUG +// if( this.config.isComponentActive(component) ){ +// System.err.println(String.format( "%s[%s]....", prefix, component.getName())); +// } + + // iterate over the aggregated instances for the whole tree. + MassCalculation children = this.copy(component, parentTransform ); + for( int instanceNumber = 0; instanceNumber < instanceCount; ++instanceNumber) { + Coordinate currentLocation = instanceLocations[instanceNumber]; + Transformation currentTransform = parentTransform.applyTransformation( Transformation.getTranslationTransform( currentLocation )); + + for (RocketComponent child : component.getChildren()) { + // child data, relative to rocket reference frame + MassCalculation eachChild = copy( child, currentTransform); + + eachChild.prefix = prefix + "...."; + eachChild.calculateStructure(); + + // accumulate children's data + children.merge( eachChild ); + } + } + + if( 0 < children.getMass() ) { + this.merge( children ); +// // vvv DEBUG +// System.err.println(String.format( "%s....assembly mass (incl/children): %s", prefix, this.toCMDebug())); + } + + if (this.config.isComponentActive(component) ){ + Coordinate compCM = component.getComponentCG(); + + if (!component.getOverrideSubcomponents()) { + if (component.isMassOverridden()) { +// System.err.println("mass override=" + component.getOverrideMass()); + compCM = compCM.setWeight(MathUtil.max(component.getOverrideMass(), MIN_MASS)); + } + if (component.isCGOverridden()) + compCM = compCM.setXYZ(component.getOverrideCG()); + } + + // mass data for *this component only* in the rocket-frame + compCM = parentTransform.transform( compCM.add(component.getPosition()) ); + this.addMass( compCM ); + + double compIx = component.getRotationalUnitInertia() * compCM.weight; + double compIt = component.getLongitudinalUnitInertia() * compCM.weight; + RigidBody componentInertia = new RigidBody( compCM, compIx, compIt, compIt ); + + this.addInertia( componentInertia ); +// vvv DEBUG +// if( 0 < compCM.weight ) { +// System.err.println(String.format( "%s....componentData: %s", prefix, compCM.toPreciseString() )); +// } + + if (component.getOverrideSubcomponents()) { + if (component.isMassOverridden()) { + double newMass = MathUtil.max(component.getOverrideMass(), MIN_MASS); + Coordinate newCM = this.getCM().setWeight( newMass ); + this.setCM( newCM ); + } + + if (component.isCGOverridden()) { + Coordinate newCM = this.getCM().setX( component.getOverrideCGX() ); + this.setCM( newCM ); + } + } + } + +// // vvv DEBUG +// if( this.config.isComponentActive(component) && 0 < this.getMass() ) { +// System.err.println(String.format( "%s....<< return assemblyData: %s (tree @%s)", prefix, this.toCMDebug(), component.getName() )); +// } +// // ^^^ DEBUG + + return this; + } + + MassCalculation calculateMotors() { + final RocketComponent component = this.root; final Transformation parentTransform = this.transform; @@ -257,37 +359,14 @@ public class MassCalculation { // System.err.println(String.format( "%s[%s]....", prefix, component.getName())); // } - if( this.type.includesStructure && this.config.isComponentActive(component) ){ - Coordinate compCM = component.getCG(); - double compIx = component.getRotationalUnitInertia() * compCM.weight; - double compIt = component.getLongitudinalUnitInertia() * compCM.weight; - - if (!component.getOverrideSubcomponents()) { - if (component.isMassOverridden()) - compCM = compCM.setWeight(MathUtil.max(component.getOverrideMass(), MIN_MASS)); - if (component.isCGOverridden()) - compCM = compCM.setXYZ(component.getOverrideCG()); - } - - // mass data for *this component only* in the rocket-frame - compCM = parentTransform.transform( compCM.add(component.getPosition()) ); - this.addMass( compCM ); - - RigidBody componentInertia = new RigidBody( compCM, compIx, compIt, compIt ); - this.addInertia( componentInertia ); - -// if( 0 < compCM.weight ) { // vvv DEBUG -// System.err.println(String.format( "%s....componentData: %s", prefix, compCM.toPreciseString() )); -// } - } - - if( component.isMotorMount() && ( this.type.includesMotorCasing || this.type.includesPropellant )) { + if (component.isMotorMount()) { MassCalculation propellant = this.copy(component, parentTransform); propellant.calculateMountData(); this.merge( propellant ); - + +// // vvv DEBUG // if( 0 < propellant.getMass() ) { // System.err.println(String.format( "%s........++ propellantData: %s", prefix, propellant.toCMDebug())); // } @@ -304,7 +383,7 @@ public class MassCalculation { MassCalculation eachChild = copy( child, currentTransform); eachChild.prefix = prefix + "...."; - eachChild.calculateAssembly(); + eachChild.calculateMotors(); // accumulate children's data children.merge( eachChild ); @@ -316,25 +395,11 @@ public class MassCalculation { //System.err.println(String.format( "%s....assembly mass (incl/children): %s", prefix, this.toCMDebug())); } - // Override total data - if (component.getOverrideSubcomponents()) { - if (component.isMassOverridden()) { - double newMass = MathUtil.max(component.getOverrideMass(), MIN_MASS); - Coordinate newCM = this.getCM().setWeight( newMass ); - this.setCM( newCM ); - } - if (component.isCGOverridden()) { - Coordinate newCM = this.getCM().setX( component.getOverrideCGX() ); - this.setCM( newCM ); - } - } - - // vvv DEBUG - //if( this.config.isComponentActive(component) && 0 < this.getMass() ) { - //System.err.println(String.format( "%s....<< return assemblyData: %s (tree @%s)", prefix, this.toCMDebug(), component.getName() )); - // System.err.println(String.format( "%s Ixx = %.8f Iyy = %.8f", prefix, getIxx(), getIyy() )); - //} - // ^^^ DEBUG +// // vvv DEBUG +// if( this.config.isComponentActive(component) && 0 < this.getMass() ) { +// System.err.println(String.format( "%s....<< return assemblyData: %s (tree @%s)", prefix, this.toCMDebug(), component.getName() )); +// } +// ^^^ DEBUG return this; } @@ -350,11 +415,10 @@ public class MassCalculation { double Ir=0, It=0; for( final RigidBody eachLocal : this.bodies ){ final RigidBody eachGlobal = eachLocal.rebase( this.centerOfMass ); - Ir += eachGlobal.Ixx; It += eachGlobal.Iyy; } - + return new RigidBody( centerOfMass, Ir, It, It ); } diff --git a/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java b/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java index ab56fcc62..66334245f 100644 --- a/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java +++ b/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java @@ -32,6 +32,7 @@ public class MassCalculatorTest extends BaseTestCase { @Test public void testAlphaIIIStructure() { + System.err.println("testing AlphaIII structure"); Rocket rocket = TestRockets.makeEstesAlphaIII(); rocket.setName("AlphaIII."+Thread.currentThread().getStackTrace()[1].getMethodName()); @@ -51,6 +52,33 @@ public class MassCalculatorTest extends BaseTestCase { assertEquals("Simple Rocket CM.y is incorrect: ", expCM.y, actualRocketDryCM.y, EPSILON); assertEquals("Simple Rocket CM.z is incorrect: ", expCM.z, actualRocketDryCM.z, EPSILON); assertEquals("Simple Rocket CM is incorrect: ", expCM, actualRocketDryCM); + + + double expMOIrot = 5.441190348849436E-5; + double expMOIlong = 3.03467093714368E-4; + + double actualMOIrot = actualStructure.getRotationalInertia(); + double actualMOIlong = actualStructure.getLongitudinalInertia(); + assertEquals("Alpha III Rotational MOI calculated incorrectly: ", expMOIrot, actualMOIrot, EPSILON); + assertEquals("Alpha III Longitudinal MOI calculated incorrectly: ", expMOIlong, actualMOIlong, EPSILON); + + // if we use a mass override, setting to same mass, we should get same result + System.err.println("calculating AlphaIII with mass override"); + AxialStage sustainer = (AxialStage) rocket.getChild(0); + + sustainer.setOverrideSubcomponents(true); + sustainer.setMassOverridden(true); + sustainer.setOverrideMass(actualRocketDryMass); + + final RigidBody overrideStructure = MassCalculator.calculateStructure( config ); + final Coordinate overrideRocketDryCM = overrideStructure.cm; + + assertEquals("Simple Rocket Override CM is incorrect: ", actualRocketDryCM, overrideRocketDryCM); + + double overrideMOIrot = overrideStructure.getRotationalInertia(); + double overrideMOIlong = overrideStructure.getLongitudinalInertia(); + assertEquals("Alpha III Rotational MOI calculated incorrectly: ", actualMOIrot, overrideMOIrot, EPSILON); + assertEquals("Alpha III Longitudinal MOI calculated incorrectly: ", actualMOIlong, overrideMOIlong, EPSILON); } @Test @@ -713,10 +741,10 @@ public class MassCalculatorTest extends BaseTestCase { double expMOI_axial = 0.01261079; double boosterMOI_xx= burnout.getRotationalInertia(); assertEquals(" Booster x-axis MOI is incorrect: ", expMOI_axial, boosterMOI_xx, EPSILON); - - double expMOI_tr = 16.163954943504205; + + double expMOI_tr = 16.046826943504207; double boosterMOI_tr= burnout.getLongitudinalInertia(); - assertEquals(" Booster transverse MOI is incorrect: ", expMOI_tr, boosterMOI_tr, EPSILON); + assertEquals(" Booster transverse MOI is incorrect: ", expMOI_tr, boosterMOI_tr, EPSILON); } @Test @@ -734,17 +762,24 @@ public class MassCalculatorTest extends BaseTestCase { NoseCone nose = (NoseCone)boosters.getChild(0); nose.setMassOverridden(true); nose.setOverrideMass( 0.71 ); - + // cm= 0.71000000g @[0.53971058,0.07700000,0.00000000] + BodyTube body = (BodyTube)boosters.getChild(1); body.setMassOverridden(true); body.setOverrideMass( 0.622 ); - + // cm= 0.62200000g @[0.96400000,0.07700000,0.00000000] + InnerTube mmt = (InnerTube)boosters.getChild(1).getChild(0); mmt.setMassOverridden(true); mmt.setOverrideMass( 0.213 ); + // cm= 0.21300000g @[1.28900000,0.07700000,0.00000000] + + // Fin mass is not overriden + // cm= 0.15995232g @[1.23793939,0.07700000,0.00000000] RigidBody boosterData = MassCalculator.calculateStructure( config ); Coordinate boosterCM = boosterData.getCM(); + // cm= 3.409905g@[0.853614,-0.000000,0.000000] double expTotalMass = 3.40990464; assertEquals(" Booster Launch Mass is incorrect: ", expTotalMass, boosterData.getMass(), EPSILON);