Constructor.
The constructor reads in the defining parameters from a configuration file.
52 : TankNumber(tank_number)
53{
54 string token, strFuelName;
55 Element* element;
56 Element* element_Grain;
57 auto PropertyManager = exec->GetPropertyManager();
58 Area = 1.0;
59 Density = 6.6;
60 InitialTemperature = Temperature = -9999.0;
61 Ixx = Iyy = Izz = 0.0;
62 InertiaFactor = 1.0;
63 Radius = Contents = Standpipe = Length = InnerRadius = 0.0;
64 ExternalFlow = 0.0;
65 InitialStandpipe = 0.0;
66 Capacity = 0.00001; UnusableVol = 0.0;
67 Priority = InitialPriority = 1;
68 vXYZ.InitMatrix();
69 vXYZ_drain.InitMatrix();
70 ixx_unit = iyy_unit = izz_unit = 1.0;
71 grainType = gtUNKNOWN;
72
73 string type = el->GetAttributeValue("type");
74 if (type == "FUEL") Type = ttFUEL;
75 else if (type == "OXIDIZER") Type = ttOXIDIZER;
76 else Type = ttUNKNOWN;
77
78 Name = el->GetAttributeValue("name");
79
80 element = el->FindElement("location");
81 if (element) vXYZ = element->FindElementTripletConvertTo("IN");
82 else {
83 FGXMLLogging log(el, LogLevel::ERROR);
84 log << "No location found for this tank.\n";
85 }
86
87 vXYZ_drain = vXYZ;
88
89 element = el->FindElement("drain_location");
90 if (element) {
91 vXYZ_drain = element->FindElementTripletConvertTo("IN");
92 }
93
94 if (el->FindElement("radius"))
95 Radius = el->FindElementValueAsNumberConvertTo("radius", "IN");
96 if (el->FindElement("inertia_factor"))
97 InertiaFactor = el->FindElementValueAsNumber("inertia_factor");
98 if (el->FindElement("capacity"))
99 Capacity = el->FindElementValueAsNumberConvertTo("capacity", "LBS");
100 if (el->FindElement("contents"))
101 InitialContents = Contents = el->FindElementValueAsNumberConvertTo("contents", "LBS");
102 if (el->FindElement("unusable-volume"))
103 UnusableVol = el->FindElementValueAsNumberConvertTo("unusable-volume", "GAL");
104 if (el->FindElement("temperature"))
105 InitialTemperature = Temperature = el->FindElementValueAsNumber("temperature");
106 if (el->FindElement("standpipe"))
107 InitialStandpipe = Standpipe = el->FindElementValueAsNumberConvertTo("standpipe", "LBS");
108 if (el->FindElement("priority"))
109 InitialPriority = Priority = (int)el->FindElementValueAsNumber("priority");
110 if (el->FindElement("density"))
111 Density = el->FindElementValueAsNumberConvertTo("density", "LBS/GAL");
112 if (el->FindElement("type"))
113 strFuelName = el->FindElementValue("type");
114
115
116 SetPriority( InitialPriority );
117
118 if (Capacity == 0) {
119 FGXMLLogging log(el, LogLevel::WARN);
120 log << "Tank capacity must not be zero. Reset to 0.00001 lbs!\n";
121 Capacity = 0.00001;
122 Contents = 0.0;
123 }
125 XMLLogException err(el);
126 err << "Tank capacity (" << Capacity
127 <<
" lbs) is lower than the amount of unusable fuel (" <<
GetUnusable()
128 << " lbs) for tank " << tank_number
129 << "! Did you accidentally swap unusable and capacity?\n";
130 throw err;
131 }
132 if (Contents > Capacity) {
133 XMLLogException err(el);
134 err << "Tank content (" << Contents
135 << " lbs) is greater than tank capacity (" << Capacity
136 << " lbs) for tank " << tank_number
137 << "! Did you accidentally swap contents and capacity?\n";
138 throw err;
139 }
141 FGXMLLogging log(el, LogLevel::ERROR);
142 log << el->ReadFrom() << "Tank content (" << Contents
143 <<
" lbs) is lower than the amount of unusable fuel (" <<
GetUnusable()
144 << " lbs) for tank " << tank_number << "\n";
145 }
146
147 PctFull = 100.0*Contents/Capacity;
148
149
150
151 element_Grain = el->FindElement("grain_config");
152 if (element_Grain) {
153
154 string strGType = element_Grain->GetAttributeValue("type");
155 if (strGType == "CYLINDRICAL") grainType = gtCYLINDRICAL;
156 else if (strGType == "ENDBURNING") grainType = gtENDBURNING;
157 else if (strGType == "FUNCTION") {
158 grainType = gtFUNCTION;
159 if (element_Grain->FindElement("ixx") != 0) {
160 Element* element_ixx = element_Grain->FindElement("ixx");
161 if (element_ixx->GetAttributeValue("unit") == "KG*M2") ixx_unit = 1.0/1.35594;
162 if (element_ixx->FindElement("function") != 0) {
163 function_ixx = new FGFunction(exec, element_ixx->FindElement("function"));
164 }
165 } else {
166 throw("For tank "+to_string(TankNumber)+" and when grain_config is specified an ixx must be specified when the FUNCTION grain type is specified.");
167 }
168
169 if (element_Grain->FindElement("iyy")) {
170 Element* element_iyy = element_Grain->FindElement("iyy");
171 if (element_iyy->GetAttributeValue("unit") == "KG*M2") iyy_unit = 1.0/1.35594;
172 if (element_iyy->FindElement("function") != 0) {
173 function_iyy = new FGFunction(exec, element_iyy->FindElement("function"));
174 }
175 } else {
176 XMLLogException err(element_Grain);
177 err << "For tank " << TankNumber
178 << " and when grain_config is specified an iyy must be specified when the FUNCTION grain type is specified.\n";
179 throw err;
180 }
181
182 if (element_Grain->FindElement("izz")) {
183 Element* element_izz = element_Grain->FindElement("izz");
184 if (element_izz->GetAttributeValue("unit") == "KG*M2") izz_unit = 1.0/1.35594;
185 if (element_izz->FindElement("function") != 0) {
186 function_izz = new FGFunction(exec, element_izz->FindElement("function"));
187 }
188 } else {
189 XMLLogException err(element_Grain);
190 err << "For tank " << TankNumber
191 << " and when grain_config is specified an izz must be specified when the FUNCTION grain type is specified.\n";
192 throw err;
193 }
194 }
195 else {
196 FGXMLLogging log(el, LogLevel::ERROR);
197 log << "Unknown propellant grain type specified\n";
198 }
199
200 if (element_Grain->FindElement("length"))
201 Length = element_Grain->FindElementValueAsNumberConvertTo("length", "IN");
202 if (element_Grain->FindElement("bore_diameter"))
203 InnerRadius = element_Grain->FindElementValueAsNumberConvertTo("bore_diameter", "IN")/2.0;
204
205
206
207 switch (grainType) {
208 case gtCYLINDRICAL:
209 if (Radius <= InnerRadius) {
210 XMLLogException err(element_Grain);
211 err << "The bore diameter should be smaller than the total grain diameter!\n";
212 throw err;
213 }
214 Volume = M_PI * Length * (Radius*Radius - InnerRadius*InnerRadius);
215 break;
216 case gtENDBURNING:
217 Volume = M_PI * Length * Radius * Radius;
218 break;
219 case gtFUNCTION:
220 Volume = 1;
221 break;
222 case gtUNKNOWN:
223 {
224 XMLLogException err(el);
225 err << "Unknown grain type found in this rocket engine definition.\n";
226 throw err;
227 }
228 }
229 Density = (Capacity*lbtoslug)/Volume;
230 }
231
232 CalculateInertias();
233
234 if (Temperature != -9999.0) InitialTemperature = Temperature =
FahrenheitToCelsius(Temperature);
235 Area = 40.0 * pow(Capacity/1975, 0.666666667);
236
237
239
240 bind(PropertyManager.get());
241
242 Debug(0);
243}
static constexpr double FahrenheitToCelsius(double fahrenheit)
Converts from degrees Fahrenheit to degrees Celsius.
double ProcessFuelName(const std::string &name)
Returns the density of a named fuel type.
double GetUnusable(void) const
Returns the amount of unusable fuel in the tank.