package net.sf.openrocket.optimization.rocketoptimization.parameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
import net.sf.openrocket.aerodynamics.FlightConditions;
import net.sf.openrocket.document.Simulation;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.masscalc.BasicMassCalculator;
import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.masscalc.MassCalculator.MassCalcType;
import net.sf.openrocket.optimization.general.OptimizationException;
import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
import net.sf.openrocket.rocketcomponent.Configuration;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.rocketcomponent.SymmetricComponent;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.util.Coordinate;
import net.sf.openrocket.util.MathUtil;
/**
* An optimization parameter that computes either the absolute or relative stability of a rocket.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public class StabilityParameter implements OptimizableParameter {
private static final Logger log = LoggerFactory.getLogger(StabilityParameter.class);
private static final Translator trans = Application.getTranslator();
private final boolean absolute;
public StabilityParameter(boolean absolute) {
this.absolute = absolute;
}
@Override
public String getName() {
return trans.get("name") + " (" + getUnitGroup().getDefaultUnit().getUnit() + ")";
}
@Override
public double computeValue(Simulation simulation) throws OptimizationException {
Coordinate cp, cg;
double cpx, cgx;
double stability;
log.debug("Calculating stability of simulation, absolute=" + absolute);
/*
* These are instantiated each time because this class must be thread-safe.
* Caching would in any case be inefficient since the rocket changes all the time.
*/
AerodynamicCalculator aerodynamicCalculator = new BarrowmanCalculator();
MassCalculator massCalculator = new BasicMassCalculator();
Configuration configuration = simulation.getConfiguration();
FlightConditions conditions = new FlightConditions(configuration);
conditions.setMach(Application.getPreferences().getDefaultMach());
conditions.setAOA(0);
conditions.setRollRate(0);
cp = aerodynamicCalculator.getWorstCP(configuration, conditions, null);
cg = massCalculator.getCG(configuration, MassCalcType.LAUNCH_MASS);
if (cp.weight > 0.000001)
cpx = cp.x;
else
cpx = Double.NaN;
if (cg.weight > 0.000001)
cgx = cg.x;
else
cgx = Double.NaN;
// Calculate the reference (absolute or relative)
stability = cpx - cgx;
if (!absolute) {
double diameter = 0;
for (RocketComponent c : configuration) {
if (c instanceof SymmetricComponent) {
double d1 = ((SymmetricComponent) c).getForeRadius() * 2;
double d2 = ((SymmetricComponent) c).getAftRadius() * 2;
diameter = MathUtil.max(diameter, d1, d2);
}
}
stability = stability / diameter;
}
log.debug("Resulting stability is " + stability + ", absolute=" + absolute);
return stability;
}
@Override
public UnitGroup getUnitGroup() {
if (absolute) {
return UnitGroup.UNITS_LENGTH;
} else {
return UnitGroup.UNITS_STABILITY_CALIBERS;
}
}
}