1 package com.billkuker.rocketry.motorsim.fuel;
\r
4 import java.util.HashMap;
\r
5 import java.util.Map;
\r
6 import java.util.NoSuchElementException;
\r
7 import java.util.SortedMap;
\r
8 import java.util.TreeMap;
\r
10 import javax.measure.quantity.Dimensionless;
\r
11 import javax.measure.quantity.Pressure;
\r
12 import javax.measure.quantity.Velocity;
\r
13 import javax.measure.quantity.VolumetricDensity;
\r
14 import javax.measure.unit.SI;
\r
16 import org.apache.log4j.Logger;
\r
17 import org.jscience.physics.amount.Amount;
\r
19 import com.billkuker.rocketry.motorsim.Fuel;
\r
20 import com.billkuker.rocketry.motorsim.visual.Chart;
\r
22 public class PiecewiseLinearFuel implements Fuel{
\r
23 private static final Logger log = Logger.getLogger(PiecewiseLinearFuel.class);
\r
24 private static final Amount<Pressure> ZERO_PRESSURE =Amount.valueOf(0, SI.PASCAL);
\r
25 private static final Amount<Velocity> ZERO_VELOCITY =Amount.valueOf(0, SI.METERS_PER_SECOND);
\r
27 private static class Entry implements Comparable<Entry>{
\r
28 Amount<Pressure> pressure;
\r
29 Amount<Velocity> burnRate;
\r
31 public int compareTo(Entry o) {
\r
32 if ( o.pressure.approximates(pressure) )
\r
34 return o.pressure.isGreaterThan(pressure)?-1:1;
\r
39 private String name = "New Linear Fuel";
\r
41 private double combustionEfficiency = .97;
\r
42 private double densityRatio = .96;
\r
43 private Amount<VolumetricDensity> density = Amount.valueOf(1889, 0, SI.KILOGRAM.divide(SI.METER.pow(3))).to(VolumetricDensity.UNIT);
\r
46 private EditableCombustionProduct product = new EditableCombustionProduct();
\r
47 private SortedMap<Amount<Pressure>, Entry> entries ;
\r
49 public PiecewiseLinearFuel(){
\r
52 public void add(final Amount<Pressure> p, final Amount<Velocity> r){
\r
53 entries.put(p, new Entry(){{pressure = p; burnRate = r;}});
\r
57 public Amount<Velocity> burnRate(final Amount<Pressure> pressure) {
\r
58 if ( pressure.isLessThan(ZERO_PRESSURE) )
\r
59 return ZERO_VELOCITY;
\r
61 if ( entries.size() == 1 ){
\r
62 return entries.get(entries.firstKey()).burnRate;
\r
65 if ( entries.containsKey(pressure) ){
\r
66 return entries.get(pressure).burnRate;
\r
70 low = entries.get(entries.headMap(pressure).lastKey());
\r
73 high = entries.get(entries.tailMap(pressure).firstKey());
\r
74 } catch ( NoSuchElementException e ){
\r
75 log.warn("Pressure " + pressure + " is outside of expiermental range for " + this.getName());
\r
77 low = entries.get(entries.headMap(low.pressure).lastKey());
\r
80 Amount<Pressure> lowToHigh = high.pressure.minus(low.pressure);
\r
81 Amount<Pressure> lowToTarget = pressure.minus(low.pressure);
\r
82 Amount<Dimensionless> frac = lowToTarget.divide(lowToHigh).to(Dimensionless.UNIT);
\r
84 Amount<Velocity> vdiff = high.burnRate.minus(low.burnRate);
\r
85 Amount<Velocity> ret = low.burnRate.plus(vdiff.times(frac));
\r
87 if ( ret.isLessThan(ZERO_VELOCITY) )
\r
88 return ZERO_VELOCITY;
\r
94 public void clear(){
\r
95 entries = new TreeMap<Amount<Pressure>, Entry>();
\r
96 add(Amount.valueOf(0,SI.MEGA(SI.PASCAL)), Amount.valueOf(0, SI.METERS_PER_SECOND));
\r
100 public double getCombustionEfficiency() {
\r
101 return combustionEfficiency;
\r
105 public void setCombustionEfficiency(double combustionEfficiency) {
\r
106 this.combustionEfficiency = combustionEfficiency;
\r
110 public EditableCombustionProduct getCombustionProduct(){
\r
114 public void setCombustionProduct(final EditableCombustionProduct product){
\r
115 this.product = product;
\r
119 public double getDensityRatio() {
\r
120 return densityRatio;
\r
123 public void setDensityRatio(double densityRatio) {
\r
124 this.densityRatio = densityRatio;
\r
128 public Amount<VolumetricDensity> getIdealDensity() {
\r
132 public void setIdealDensity(Amount<VolumetricDensity> density) {
\r
133 this.density = density;
\r
137 public String getName() {
\r
141 public void setName(String name) {
\r
146 public URI getURI() {
\r
152 public Map<Amount<Pressure>, Amount<Velocity>> getEntries() {
\r
153 HashMap<Amount<Pressure>, Amount<Velocity>> ret = new HashMap<Amount<Pressure>, Amount<Velocity>>();
\r
154 for ( Entry e : entries.values() )
\r
155 ret.put(e.pressure, e.burnRate);
\r
159 public void setEntries(Map<Amount<Pressure>, Amount<Velocity>> in) {
\r
161 for ( Map.Entry<Amount<Pressure>, Amount<Velocity>> e : in.entrySet()){
\r
162 add( e.getKey(), e.getValue());
\r
168 public static void main( String args[]) throws Exception{
\r
169 PiecewiseLinearFuel f = new PiecewiseLinearFuel();
\r
170 f.add(Amount.valueOf(0,SI.MEGA(SI.PASCAL)), Amount.valueOf(2, SI.METERS_PER_SECOND));
\r
171 //f.add(Amount.valueOf(2,SI.MEGA(SI.PASCAL)), Amount.valueOf(2, SI.METERS_PER_SECOND));
\r
172 //f.add(Amount.valueOf(4,SI.MEGA(SI.PASCAL)), Amount.valueOf(1, SI.METERS_PER_SECOND));
\r
173 //f.add(Amount.valueOf(10,SI.MEGA(SI.PASCAL)), Amount.valueOf(3, SI.METERS_PER_SECOND));
\r
174 //f.add(Amount.valueOf(20,SI.MEGA(SI.PASCAL)), Amount.valueOf(4, SI.METERS_PER_SECOND));
\r
175 Chart<Pressure, Velocity> burnRate = new Chart<Pressure, Velocity>(
\r
176 SI.MEGA(SI.PASCAL),
\r
177 SI.METERS_PER_SECOND,
\r
180 burnRate.setDomain(
\r
181 burnRate.new IntervalDomain(
\r
182 Amount.valueOf(0, SI.MEGA(SI.PASCAL)),
\r
183 Amount.valueOf(11, SI.MEGA(SI.PASCAL)),
\r