Update unit tests for SymmetricComponent. This is another pretty big rewrite -- the old code had a lot of references to numbers transcribed from an unnamed 2D CAD package, and also expected values that were just presented without derivation. New code has the trig functions to calculate the numbers, has helper functios for the comparisons, and puts a much tighter bound on results.

This commit is contained in:
JoePfeiffer 2023-12-13 09:12:21 -07:00
parent 9f13635357
commit 4dd2c3a86a

View File

@ -4,384 +4,389 @@ import static org.junit.Assert.assertEquals;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
import net.sf.openrocket.util.MathUtil;
import static net.sf.openrocket.util.MathUtil.pow2;
import org.junit.Test;
public class SymmetricComponentVolumeTest extends BaseTestCase {
final double EPSILON = MathUtil.EPSILON*1000;
@Test
public void testVolumeSimpleConeFilled() {
NoseCone nc = new NoseCone();
// helper functions
final double epsilonPercent = 0.001;
final double density = 2.0;
// return Coordinate containing CG and volume of (possibly hollow if thickness < outerR) shoulder
private Coordinate calculateShoulderCG(double x1, double length, double outerR, double thickness) {
final double cg = x1 + length/2.0;
nc.setLength(1.0);
nc.setFilled(true);
nc.setShapeType(Transition.Shape.CONICAL);
nc.setAftRadius(1.0);
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
final double innerR = Math.max(0.0, outerR - thickness);
final double volume = Math.PI * length * (pow2(outerR) - pow2(innerR));
return new Coordinate(cg, 0, 0, volume);
}
// return Coordinate containing CG and volume of frustum
// still OK if foreward radius is 0 (ie a cone)
private Coordinate calculateFrustumCG(double length, double foreRadius, double aftRadius) {
final double moment = Math.PI * pow2(length) * (pow2(foreRadius) + 2.0 * foreRadius * aftRadius + 3.0 * pow2(aftRadius))/12.0;
final double volume = Math.PI * length * (pow2(foreRadius) + foreRadius * aftRadius + pow2(aftRadius)) / 3.0;
return new Coordinate(moment/volume, 0, 0, volume);
}
// return Coordinate containing CG and volume of conical transition
private Coordinate calculateConicalTransitionCG(double length, double foreRadius, double aftRadius, double thickness) {
// get moment and volume of outer frustum
final Coordinate fullCG = calculateFrustumCG(length, foreRadius, aftRadius);
// project thickness onto yz plane to get height
final double angle = Math.atan((aftRadius - foreRadius)/length);
final double height = thickness/Math.cos(angle);
// if aftRadius <= height the transition is filled and we don't need to mess with
// the inner frustum
if (aftRadius <= height) {
return fullCG;
}
double innerLen = length;
double innerForeRad = foreRadius - height;
final double innerAftRad = aftRadius - height;
// if forward radius <= height the transition is a cone; we
// need to determine its length
if (foreRadius < height) {
innerLen = length * (aftRadius - height) / (aftRadius - foreRadius);
innerForeRad = 0;
}
final Coordinate innerCG = calculateFrustumCG(innerLen, innerForeRad, innerAftRad);
// subtract inner from outer
final double offset = length - innerLen;
final double moment = fullCG.x * fullCG.weight - (innerCG.x + offset) * innerCG.weight;
final double volume = fullCG.weight - innerCG.weight;
return new Coordinate(moment/volume, 0, 0, volume);
}
// combine three CGs (typically forward shoulder, transition, and aft shoulder)
private Coordinate combineCG(Coordinate cg1, Coordinate cg2, Coordinate cg3) {
final double moment1 = cg1.x * cg1.weight;
final double moment2 = cg2.x * cg2.weight;
final double moment3 = cg3.x * cg3.weight;
final double volume = cg1.weight + cg2.weight + cg3.weight;
return new Coordinate((moment1 + moment2 + moment3) / volume, 0, 0, volume);
}
// check CG, volume, mass
private void checkCG(Coordinate expectedCG, Transition nc) {
Coordinate cg = nc.getCG();
double volume = Math.PI / 3.0;
double mass = density * volume;
assertEquals("CG is incorrect", expectedCG.x, cg.x, EPSILON);
assertEquals("Volume is incorrect", expectedCG.weight, nc.getComponentVolume(), EPSILON);
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
final double mass = expectedCG.weight * nc.getMaterial().getDensity();
assertEquals("Mass is incorrect", mass, nc.getMass(), EPSILON);
assertEquals("Mass (stored in cg.weight) is incorrect", mass, cg.weight, EPSILON);
}
@Test
public void testVolumeSimpleConeFilled() {
assertEquals(0.75, cg.x, epsilonPercent * 0.75);
assertEquals(mass, cg.weight, epsilonPercent * mass);
final double length = 1.0;
final double aftRadius = 1.0;
final double density = 2.0;
NoseCone nc = new NoseCone();
nc.setLength(length);
nc.setFilled(true);
nc.setShapeType(Transition.Shape.CONICAL);
nc.setAftRadius(aftRadius);
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
Coordinate expectedCG = calculateConicalTransitionCG(length, 0, aftRadius, aftRadius);
checkCG(expectedCG, nc);
}
@Test
public void testVolumeSimpleConeWithShoulderFilled() {
NoseCone nc = new NoseCone();
final double epsilonPercent = 0.001;
final double length = 1.0;
final double aftRadius = 1.0;
final double thickness = 1.0;
final double density = 2.0;
nc.setLength(1.0);
NoseCone nc = new NoseCone();
nc.setLength(length);
nc.setFilled(true);
nc.setShapeType(Transition.Shape.CONICAL);
nc.setAftRadius(1.0);
nc.setAftShoulderRadius(1.0);
nc.setAftShoulderLength(1.0);
nc.setAftShoulderThickness(1.0);
nc.setAftRadius(aftRadius);
nc.setAftShoulderRadius(aftRadius);
nc.setAftShoulderLength(length);
nc.setAftShoulderThickness(aftRadius);
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
Coordinate cg = nc.getCG();
final Coordinate coneCG = calculateConicalTransitionCG(length, 0, aftRadius, aftRadius);
final Coordinate shoulderCG = calculateShoulderCG(length, length, aftRadius, aftRadius);
final Coordinate expectedCG = coneCG.average(shoulderCG);
double volume = Math.PI / 3.0;
volume += Math.PI;
double mass = density * volume;
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
assertEquals(1.312, cg.x, epsilonPercent * 1.071);
assertEquals(mass, cg.weight, epsilonPercent * mass);
checkCG(expectedCG, nc);
}
@Test
public void testVolumeSimpleConeHollow() {
NoseCone nc = new NoseCone();
final double epsilonPercent = 0.001;
final double length = 1.0;
final double aftRadius = 1.0;
final double thickness = 0.5;
final double density = 2.0;
nc.setLength(1.0);
nc.setAftRadius(1.0);
nc.setThickness(0.5);
NoseCone nc = new NoseCone();
nc.setLength(length);
nc.setAftRadius(aftRadius);
nc.setThickness(thickness);
nc.setShapeType(Transition.Shape.CONICAL);
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
Coordinate cg = nc.getCG();
Coordinate expectedCG = calculateConicalTransitionCG(length, 0.0, aftRadius, thickness);
double volume = Math.PI / 3.0; // outer volume
// manually projected Thickness of 0.5 on to radius to determine
// the innerConeDimen. Since the outer cone is "square" (height = radius),
// we only need to compute this one dimension in order to compute the
// volume of the inner cone.
double innerConeDimen = 1.0 - Math.sqrt(2.0) / 2.0;
double innerVolume = Math.PI / 3.0 * innerConeDimen * innerConeDimen * innerConeDimen;
volume -= innerVolume;
double mass = density * volume;
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
assertEquals(0.7454, cg.x, epsilonPercent * 0.7454);
assertEquals(mass, cg.weight, epsilonPercent * mass);
checkCG(expectedCG, nc);
}
@Test
public void testVolumeSimpleConeWithShoulderHollow() {
NoseCone nc = new NoseCone();
final double epsilonPercent = 0.001;
final double aftRadius = 1.0;
final double length = 1.0;
final double thickness = 0.5;
final double density = 2.0;
nc.setLength(1.0);
NoseCone nc = new NoseCone();
nc.setLength(length);
nc.setShapeType(Transition.Shape.CONICAL);
nc.setAftRadius(1.0);
nc.setThickness(0.5);
nc.setAftShoulderRadius(1.0);
nc.setAftShoulderLength(1.0);
nc.setAftShoulderThickness(0.5);
nc.setAftRadius(aftRadius);
nc.setThickness(thickness);
nc.setAftShoulderRadius(aftRadius);
nc.setAftShoulderLength(length);
nc.setAftShoulderThickness(thickness);
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
Coordinate cg = nc.getCG();
final Coordinate expectedConeCG = calculateConicalTransitionCG(length, 0, aftRadius, thickness);
final Coordinate expectedShoulderCG = calculateShoulderCG(length, length, aftRadius, thickness);
final Coordinate expectedCG = expectedConeCG.average(expectedShoulderCG);
double volume = Math.PI / 3.0; // outer volume
// manually projected Thickness of 0.5 on to radius to determine
// the innerConeDimen. Since the outer cone is "square" (height = radius),
// we only need to compute this one dimension in order to compute the
// volume of the inner cone.
double innerConeDimen = 1.0 - Math.sqrt(2.0) / 2.0;
double innerVolume = Math.PI / 3.0 * innerConeDimen * innerConeDimen * innerConeDimen;
volume -= innerVolume;
volume += Math.PI - Math.PI * 0.5 * 0.5;
double mass = density * volume;
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
assertEquals(1.2719, cg.x, epsilonPercent * 1.2719);
assertEquals(mass, cg.weight, epsilonPercent * mass);
checkCG(expectedCG, nc);
}
@Test
public void testVolumeSimpleTransitionFilled() {
Transition nc = new Transition();
final double epsilonPercent = 0.001;
final double length = 4.0;
final double foreRadius = 1.0;
final double aftRadius = 2.0;
final double density = 2.0;
nc.setLength(4.0);
Transition nc = new Transition();
nc.setLength(length);
nc.setFilled(true);
nc.setShapeType(Transition.Shape.CONICAL);
nc.setForeRadius(1.0);
nc.setAftRadius(2.0);
nc.setForeRadius(foreRadius);
nc.setAftRadius(aftRadius);
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
Coordinate cg = nc.getCG();
double volume = Math.PI / 3.0 * (2.0 * 2.0 + 2.0 * 1.0 + 1.0 * 1.0) * 4.0;
double mass = density * volume;
Coordinate expectedCG = calculateConicalTransitionCG(length, foreRadius, aftRadius, aftRadius);
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
assertEquals(2.4285, cg.x, epsilonPercent * 2.4285);
assertEquals(mass, cg.weight, epsilonPercent * mass);
checkCG(expectedCG, nc);
}
@Test
public void testVolumeSimpleTransitionWithShouldersFilled() {
Transition nc = new Transition();
final double epsilonPercent = 0.001;
final double transLength = 4.0;
final double foreRadius = 1.0;
final double foreShoulderLength = 1.0;
final double aftRadius = 2.0;
final double aftShoulderLength = 1.0;
final double density = 2.0;
nc.setLength(4.0);
Transition nc = new Transition();
nc.setLength(transLength);
nc.setFilled(true);
nc.setShapeType(Transition.Shape.CONICAL);
nc.setForeRadius(1.0);
nc.setAftRadius(2.0);
nc.setAftShoulderLength(1.0);
nc.setAftShoulderRadius(2.0);
nc.setAftShoulderThickness(2.0);
nc.setForeShoulderLength(1.0);
nc.setForeShoulderRadius(1.0);
nc.setForeShoulderThickness(1.0);
nc.setForeRadius(foreRadius);
nc.setAftRadius(aftRadius);
nc.setAftShoulderLength(aftShoulderLength);
nc.setAftShoulderRadius(aftRadius);
nc.setAftShoulderThickness(aftRadius);
nc.setForeShoulderLength(foreShoulderLength);
nc.setForeShoulderRadius(foreRadius);
nc.setForeShoulderThickness(foreRadius);
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
Coordinate cg = nc.getCG();
final Coordinate foreShoulderCG = calculateShoulderCG(-foreShoulderLength, foreShoulderLength, foreRadius, foreRadius);
final Coordinate transCG = calculateConicalTransitionCG(transLength, foreRadius, aftRadius, aftRadius);
final Coordinate aftShoulderCG = calculateShoulderCG(transLength, aftShoulderLength, aftRadius, aftRadius);
final Coordinate expectedCG = combineCG(foreShoulderCG, transCG, aftShoulderCG);
double volume = Math.PI / 3.0 * (2.0 * 2.0 + 2.0 * 1.0 + 1.0 * 1.0) * 4.0;
// plus aft shoulder:
volume += Math.PI * 1.0 * 2.0 * 2.0;
// plus fore shoulder:
volume += Math.PI * 1.0 * 1.0 * 1.0;
double mass = density * volume;
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
assertEquals(2.8023, cg.x, epsilonPercent * 2.8023);
assertEquals(mass, cg.weight, epsilonPercent * mass);
checkCG(expectedCG, nc);
}
@Test
public void testVolumeSimpleTransitionHollow1() {
Transition nc = new Transition();
final double epsilonPercent = 0.001;
final double length = 1.0;
final double foreRadius = 0.5;
final double aftRadius = 0.5;
final double thickness = 0.5;
final double density = 2.0;
nc.setLength(1.0);
Transition nc = new Transition();
nc.setLength(length);
nc.setShapeType(Transition.Shape.CONICAL);
nc.setForeRadius(0.5);
nc.setAftRadius(1.0);
nc.setThickness(0.5);
nc.setForeRadius(foreRadius);
nc.setAftRadius(aftRadius);
nc.setThickness(thickness);
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
final Coordinate expectedCG = calculateConicalTransitionCG(length, foreRadius, aftRadius, thickness);
Coordinate cg = nc.getCG();
// Volume of filled transition =
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
// magic 2D cad drawing...
//
// Since the thickness >= fore radius, the
// hollowed out portion of the transition
// forms a cone.
// the dimensions of this cone were determined
// using a 2d cad tool.
double innerConeRadius = 0.441;
double innerConeLength = 0.882;
double innerVolume = Math.PI / 3.0 * innerConeLength * innerConeRadius * innerConeRadius;
double volume = filledVolume - innerVolume;
double mass = density * volume;
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
assertEquals(0.5884, cg.x, epsilonPercent * 0.5884);
assertEquals(mass, cg.weight, epsilonPercent * mass);
checkCG(expectedCG, nc);
}
@Test
public void testVolumeSimpleTransitionWithShouldersHollow1() {
Transition nc = new Transition();
final double epsilonPercent = 0.001;
final double length = 1.0; // length of transition itself and each shoulder
final double foreRadius = 0.5;
final double aftRadius = 1.0;
final double thickness = 0.5;
final double density = 2.0;
nc.setLength(1.0);
Transition nc = new Transition();
nc.setLength(length);
nc.setShapeType(Transition.Shape.CONICAL);
nc.setForeRadius(0.5);
nc.setAftRadius(1.0);
nc.setThickness(0.5);
nc.setAftShoulderLength(1.0);
nc.setAftShoulderRadius(1.0);
nc.setAftShoulderThickness(0.5);
nc.setForeShoulderLength(1.0);
nc.setForeShoulderRadius(0.5);
nc.setForeShoulderThickness(0.5); // note this means fore shoulder is filled.
nc.setForeRadius(foreRadius);
nc.setAftRadius(aftRadius);
nc.setThickness(thickness);
nc.setAftShoulderLength(length);
nc.setAftShoulderRadius(aftRadius);
nc.setAftShoulderThickness(thickness);
nc.setForeShoulderLength(length);
nc.setForeShoulderRadius(foreRadius);
nc.setForeShoulderThickness(thickness); // note this means fore shoulder is filled.
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
Coordinate cg = nc.getCG();
final Coordinate foreShoulderCG = calculateShoulderCG(-length, length, foreRadius, thickness);
final Coordinate transitionCG = calculateConicalTransitionCG(length, foreRadius, aftRadius, thickness);
final Coordinate aftShoulderCG = calculateShoulderCG(length, length, aftRadius, thickness);
final Coordinate expectedCG = combineCG(foreShoulderCG, transitionCG, aftShoulderCG);
// Volume of filled transition =
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
// magic 2D cad drawing...
//
// Since the thickness >= fore radius, the
// hollowed out portion of the transition
// forms a cone.
// the dimensions of this cone were determined
// using a 2d cad tool.
double innerConeRadius = 0.441;
double innerConeLength = 0.882;
double innerVolume = Math.PI / 3.0 * innerConeLength * innerConeRadius * innerConeRadius;
double volume = filledVolume - innerVolume;
// Now add aft shoulder
volume += Math.PI * 1.0 * 1.0 * 1.0 - Math.PI * 1.0 * 0.5 * 0.5;
// Now add fore shoulder
volume += Math.PI * 1.0 * 0.5 * 0.5;
double mass = density * volume;
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
assertEquals(0.8581, cg.x, epsilonPercent * 0.8581);
assertEquals(mass, cg.weight, epsilonPercent * mass);
checkCG(expectedCG, nc);
}
@Test
public void testVolumeSimpleTransitionHollow2() {
Transition nc = new Transition();
final double epsilonPercent = 0.001;
final double length = 1.0; // length of transition itself and each shoulder
final double foreRadius = 0.5;
final double aftRadius = 1.0;
final double thickness = 0.25;
final double density = 2.0;
nc.setLength(1.0);
Transition nc = new Transition();
nc.setLength(length);
nc.setShapeType(Transition.Shape.CONICAL);
nc.setForeRadius(0.5);
nc.setAftRadius(1.0);
nc.setThickness(0.25);
nc.setForeRadius(foreRadius);
nc.setAftRadius(aftRadius);
nc.setThickness(thickness);
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
Coordinate cg = nc.getCG();
final Coordinate expectedCG = calculateConicalTransitionCG(length, foreRadius, aftRadius, thickness);
// Volume of filled transition =
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
// magic 2D cad drawing...
//
// Since the thickness < fore radius, the
// hollowed out portion of the transition
// forms a transition.
// the dimensions of this transition were determined
// using a 2d cad tool.
double innerTransitionAftRadius = 0.7205;
double innerTransitionForeRadius = 0.2205;
double innerVolume = Math.PI / 3.0
* (innerTransitionAftRadius * innerTransitionAftRadius + innerTransitionAftRadius * innerTransitionForeRadius + innerTransitionForeRadius * innerTransitionForeRadius);
double volume = filledVolume - innerVolume;
double mass = density * volume;
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
assertEquals(0.56827, cg.x, epsilonPercent * 0.56827);
assertEquals(mass, cg.weight, epsilonPercent * mass);
checkCG(expectedCG, nc);
}
@Test
public void testVolumeSimpleTransitionWithShouldersHollow2() {
Transition nc = new Transition();
final double epsilonPercent = 0.001;
final double length = 1.0;
final double foreRadius = 0.5;
final double aftRadius = 1.0;
final double thickness = 0.25;
final double density = 2.0;
nc.setLength(1.0);
Transition nc = new Transition();
nc.setLength(length);
nc.setShapeType(Transition.Shape.CONICAL);
nc.setForeRadius(0.5);
nc.setAftRadius(1.0);
nc.setThickness(0.25);
nc.setAftShoulderLength(1.0);
nc.setAftShoulderRadius(1.0);
nc.setAftShoulderThickness(0.25);
nc.setForeShoulderLength(1.0);
nc.setForeShoulderRadius(0.5);
nc.setForeShoulderThickness(0.25);
nc.setForeRadius(foreRadius);
nc.setAftRadius(aftRadius);
nc.setThickness(thickness);
nc.setAftShoulderLength(length);
nc.setAftShoulderRadius(aftRadius);
nc.setAftShoulderThickness(thickness);
nc.setForeShoulderLength(length);
nc.setForeShoulderRadius(foreRadius);
nc.setForeShoulderThickness(thickness);
nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
Coordinate cg = nc.getCG();
final Coordinate foreShoulderCG = calculateShoulderCG(-length, length, foreRadius, thickness);
final Coordinate transitionCG = calculateConicalTransitionCG(length, foreRadius, aftRadius, thickness);
final Coordinate aftShoulderCG = calculateShoulderCG(length, length, aftRadius, thickness);
final Coordinate expectedCG = combineCG(foreShoulderCG, transitionCG, aftShoulderCG);
// Volume of filled transition =
double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
// magic 2D cad drawing...
//
// Since the thickness < fore radius, the
// hollowed out portion of the transition
// forms a transition.
// the dimensions of this transition were determined
// using a 2d cad tool.
double innerTransitionAftRadius = 0.7205;
double innerTransitionForeRadius = 0.2205;
double innerVolume = Math.PI / 3.0
* (innerTransitionAftRadius * innerTransitionAftRadius + innerTransitionAftRadius * innerTransitionForeRadius + innerTransitionForeRadius * innerTransitionForeRadius);
double volume = filledVolume - innerVolume;
// now add aft shoulder
volume += Math.PI * 1.0 * 1.0 * 1.0 - Math.PI * 1.0 * 0.75 * 0.75;
// now add fore shoulder
volume += Math.PI * 1.0 * 0.5 * 0.5 - Math.PI * 1.0 * 0.25 * 0.25;
double mass = density * volume;
assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
assertEquals(mass, nc.getMass(), epsilonPercent * mass);
assertEquals(0.7829, cg.x, epsilonPercent * 0.7829);
assertEquals(mass, cg.weight, epsilonPercent * mass);
checkCG(expectedCG, nc);
}
@Test
public void testTransitionVsTubeFilled() {
// BodyTubes use closed form solutions for mass properties, while Transitions use
// numerical integration from SymmetricComponent. Properties should agree.
final double radius = 1.0;
final double length = 10.0;
BodyTube bt1 = new BodyTube(length, radius, true);
Transition trans1 = new Transition();
trans1.setFilled(true);
trans1.setLength(length);
trans1.setForeRadius(radius, true);
trans1.setAftRadius(radius, true);
trans1.setShapeType(Transition.Shape.CONICAL);
assertEquals("Length is incorrect", bt1.getLength(), trans1.getLength(), EPSILON);
assertEquals("Forward radius is incorrect", bt1.getRadius(0), trans1.getRadius(0), EPSILON);
assertEquals("Aft radius is incorrect", bt1.getRadius(bt1.getLength()), trans1.getRadius(trans1.getLength()), EPSILON);
assertEquals("Volume is incorrect", bt1.getComponentVolume(), trans1.getComponentVolume(), EPSILON);
assertEquals("CG is incorrect", bt1.getComponentCG().x, trans1.getComponentCG().x, EPSILON);
assertEquals("Longitudinal moment of inertia is incorrect", bt1.getLongitudinalUnitInertia(), trans1.getLongitudinalUnitInertia(), EPSILON);
assertEquals("Rotational moment of inertia is incorrect", bt1.getRotationalUnitInertia(), trans1.getRotationalUnitInertia(), EPSILON);
assertEquals("Wetted area is incorrect", bt1.getComponentWetArea(), trans1.getComponentWetArea(), EPSILON);
assertEquals("Planform area is incorrect", bt1.getComponentPlanformArea(), trans1.getComponentPlanformArea(), EPSILON);
assertEquals("Planform centroid is incorrect", bt1.getComponentPlanformCenter(), trans1.getComponentPlanformCenter(), EPSILON);
}
@Test
public void testTransitionVsTubeHollow() {
final double radius = 1.0;
final double innerRadius = 0.1;
final double length = 10.0;
BodyTube bt2 = new BodyTube(length, radius, false);
bt2.setInnerRadius(innerRadius);
Transition trans2 = new Transition();
trans2.setFilled(false);
trans2.setLength(length);
trans2.setForeRadius(radius, true);
trans2.setAftRadius(radius, true);
trans2.setShapeType(Transition.Shape.CONICAL);
trans2.setThickness(radius - innerRadius, true);
assertEquals("Volume is incorrect", bt2.getComponentVolume(), trans2.getComponentVolume(), EPSILON);
assertEquals("CG is incorrect", bt2.getComponentCG().x, trans2.getComponentCG().x, EPSILON);
assertEquals("Longitudinal unit moment of inertia is incorrect", bt2.getLongitudinalUnitInertia(), trans2.getLongitudinalUnitInertia(), EPSILON);
assertEquals("Rotational unit moment of inertia is incorrect", bt2.getRotationalUnitInertia(), trans2.getRotationalUnitInertia(), EPSILON);
assertEquals("Wetted area is incorrect", bt2.getComponentWetArea(), trans2.getComponentWetArea(), EPSILON);
assertEquals("Planform area is incorrect", bt2.getComponentPlanformArea(), trans2.getComponentPlanformArea(), EPSILON);
assertEquals("Planform centroid is incorrect", bt2.getComponentPlanformCenter(), trans2.getComponentPlanformCenter(), EPSILON);
}
}