JSBSim Flight Dynamics Model 1.3.1 (17 May 2026)
An Open Source Flight Dynamics and Control Software Library in C++
Loading...
Searching...
No Matches
FGTable Class Reference

Detailed Description

Lookup table class.

Models a one or more dimensional lookup table for use in aerodynamics and function definitions.

The legacy 1D/2D/3D XML syntax is preserved. For 4D and higher, add independent variables with lookup="axis4", lookup="axis5", ... and nest <tableData breakPoint="..."> elements.

For a single "vector" lookup table, the format is as follows:

<table name="property_name">
<independentVar lookup="row"> property_name </independentVar>
<tableData>
key_1 value_1
key_2 value_2
... ...
key_n value_n
</tableData>
</table>

The lookup="row" attribute in the independentVar element is option in this case; it is assumed that the independentVar is a row variable.

A "real life" example is as shown here:

<table>
<independentVar lookup="row"> aero/alpha-rad </independentVar>
<tableData>
-1.57 1.500
-0.26 0.033
0.00 0.025
0.26 0.033
1.57 1.500
</tableData>
</table>

The first column in the data table represents the lookup index (or "key"). In this case, the lookup index is aero/alpha-rad (angle of attack in radians). If alpha is 0.26 radians, the value returned from the lookup table would be 0.033.

The definition for a 2D table, is as follows:

<table name="property_name">
<independentVar lookup="row"> property_name </independentVar>
<independentVar lookup="column"> property_name </independentVar>
<tableData>
{col_1_key col_2_key ... col_n_key }
{row_1_key} {col_1_data col_2_data ... col_n_data}
{row_2_key} {... ... ... ... }
{ ... } {... ... ... ... }
{row_n_key} {... ... ... ... }
</tableData>
</table>

The data is in a gridded format.

A "real life" example is as shown below. Alpha in radians is the row lookup (alpha breakpoints are arranged in the first column) and flap position in degrees is

<table>
<independentVar lookup="row">aero/alpha-rad</independentVar>
<independentVar lookup="column">fcs/flap-pos-deg</independentVar>
<tableData>
0.0 10.0 20.0 30.0
-0.0523599 8.96747e-05 0.00231942 0.0059252 0.00835082
-0.0349066 0.000313268 0.00567451 0.0108461 0.0140545
-0.0174533 0.00201318 0.0105059 0.0172432 0.0212346
0.0 0.0051894 0.0168137 0.0251167 0.0298909
0.0174533 0.00993967 0.0247521 0.0346492 0.0402205
0.0349066 0.0162201 0.0342207 0.0457119 0.0520802
0.0523599 0.0240308 0.0452195 0.0583047 0.0654701
0.0698132 0.0333717 0.0577485 0.0724278 0.0803902
0.0872664 0.0442427 0.0718077 0.088081 0.0968405
</tableData>
</table>

The definition for a 3D table in a coefficient would be (for example):

<table name="property_name">
<independentVar lookup="row"> property_name </independentVar>
<independentVar lookup="column"> property_name </independentVar>
<tableData breakpoint="table_1_key">
{col_1_key col_2_key ... col_n_key }
{row_1_key} {col_1_data col_2_data ... col_n_data}
{row_2_key} {... ... ... ... }
{ ... } {... ... ... ... }
{row_n_key} {... ... ... ... }
</tableData>
<tableData breakpoint="table_2_key">
{col_1_key col_2_key ... col_n_key }
{row_1_key} {col_1_data col_2_data ... col_n_data}
{row_2_key} {... ... ... ... }
{ ... } {... ... ... ... }
{row_n_key} {... ... ... ... }
</tableData>
...
<tableData breakpoint="table_n_key">
{col_1_key col_2_key ... col_n_key }
{row_1_key} {col_1_data col_2_data ... col_n_data}
{row_2_key} {... ... ... ... }
{ ... } {... ... ... ... }
{row_n_key} {... ... ... ... }
</tableData>
</table>

[Note the "breakpoint" attribute in the tableData element, above.]

Here's an example:

<table>
<independentVar lookup="row">fcs/row-value</independentVar>
<independentVar lookup="column">fcs/column-value</independentVar>
<independentVar lookup="table">fcs/table-value</independentVar>
<tableData breakPoint="-1.0">
-1.0 1.0
0.0 1.0000 2.0000
1.0 3.0000 4.0000
</tableData>
<tableData breakPoint="0.0000">
0.0 10.0
2.0 1.0000 2.0000
3.0 3.0000 4.0000
</tableData>
<tableData breakPoint="1.0">
0.0 10.0 20.0
2.0 1.0000 2.0000 3.0000
3.0 4.0000 5.0000 6.0000
10.0 7.0000 8.0000 9.0000
</tableData>
</table>

Example of a 4D table (outer axis is axis4, then axis3/table, row, column):

<table>
<independentVar lookup="row">fcs/row-value</independentVar>
<independentVar lookup="column">fcs/column-value</independentVar>
<independentVar lookup="table">fcs/table-value</independentVar>
<independentVar lookup="axis4">fcs/axis4-value</independentVar>
<tableData breakPoint="-1.0">
<tableData breakPoint="0.0">
0.0 10.0
0.0 1.0 2.0
1.0 3.0 4.0
</tableData>
<tableData breakPoint="1.0">
0.0 10.0
0.0 2.0 3.0
1.0 4.0 5.0
</tableData>
</tableData>
<tableData breakPoint="1.0">
<tableData breakPoint="0.0">
0.0 10.0
0.0 6.0 7.0
1.0 8.0 9.0
</tableData>
<tableData breakPoint="1.0">
0.0 10.0
0.0 7.0 8.0
1.0 9.0 10.0
</tableData>
</tableData>
</table>

Example of a 5D table (outer axis is axis5, then axis4, axis3/table, row, column):

<table>
<independentVar lookup="row">fcs/row-value</independentVar>
<independentVar lookup="column">fcs/column-value</independentVar>
<independentVar lookup="table">fcs/table-value</independentVar>
<independentVar lookup="axis4">fcs/axis4-value</independentVar>
<independentVar lookup="axis5">fcs/axis5-value</independentVar>
<tableData breakPoint="100.0"> <!-- axis5 -->
<tableData breakPoint="-1.0"> <!-- axis4 -->
<tableData breakPoint="0.0"> <!-- axis3/table -->
0.0 10.0
0.0 1.0 2.0
1.0 3.0 4.0
</tableData>
<tableData breakPoint="1.0">
0.0 10.0
0.0 2.0 3.0
1.0 4.0 5.0
</tableData>
</tableData>
<tableData breakPoint="1.0">
<tableData breakPoint="0.0">
0.0 10.0
0.0 6.0 7.0
1.0 8.0 9.0
</tableData>
<tableData breakPoint="1.0">
0.0 10.0
0.0 7.0 8.0
1.0 9.0 10.0
</tableData>
</tableData>
</tableData>
<tableData breakPoint="200.0"> <!-- axis5 -->
<tableData breakPoint="-1.0"> <!-- axis4 -->
<tableData breakPoint="0.0">
0.0 10.0
0.0 11.0 12.0
1.0 13.0 14.0
</tableData>
</tableData>
</tableData>
</table>

In addition to using a Table for something like a coefficient, where all the row and column elements are read in from a file, a Table could be created and populated completely within program code:

// First column is thi, second is neta (combustion efficiency)
Lookup_Combustion_Efficiency = new FGTable(12);
*Lookup_Combustion_Efficiency << 0.00 << 0.980;
*Lookup_Combustion_Efficiency << 0.90 << 0.980;
*Lookup_Combustion_Efficiency << 1.00 << 0.970;
*Lookup_Combustion_Efficiency << 1.05 << 0.950;
*Lookup_Combustion_Efficiency << 1.10 << 0.900;
*Lookup_Combustion_Efficiency << 1.15 << 0.850;
*Lookup_Combustion_Efficiency << 1.20 << 0.790;
*Lookup_Combustion_Efficiency << 1.30 << 0.700;
*Lookup_Combustion_Efficiency << 1.40 << 0.630;
*Lookup_Combustion_Efficiency << 1.50 << 0.570;
*Lookup_Combustion_Efficiency << 1.60 << 0.525;
*Lookup_Combustion_Efficiency << 2.00 << 0.345;
Lookup table class.
Definition FGTable.h:331

The first column in the table, above, is thi (the lookup index, or key). The second column is the output data - in this case, "neta" (the Greek letter referring to combustion efficiency). Later on, the table is used like this:

combustion_efficiency = Lookup_Combustion_Efficiency->GetValue(equivalence_ratio);
Author
Jon S. Berndt

Definition at line 330 of file FGTable.h.

#include <FGTable.h>

+ Inheritance diagram for FGTable:
+ Collaboration diagram for FGTable:

Public Member Functions

 FGTable (const FGTable &table)
 This is the very important copy constructor.
 
 FGTable (int)
 
 FGTable (int, int)
 
 FGTable (std::shared_ptr< FGPropertyManager > propMan, Element *el, const std::string &prefix="")
 The constructor for a table.
 
 ~FGTable ()
 Destructor.
 
double GetElement (unsigned int r, unsigned int c) const
 
double GetMinValue (double colKey) const
 
double GetMinValue (double colKey, double TableKey) const
 
double GetMinValue (void) const
 
std::string GetName (void) const
 
unsigned int GetNumRows () const
 
double GetValue (const std::vector< double > &keys) const
 
double GetValue (double a1, double a2, double a3, double a4) const
 
double GetValue (double a1, double a2, double a3, double a4, double a5) const
 
double GetValue (double a1, double a2, double a3, double a4, double a5, double a6) const
 
double GetValue (double key) const
 Get a value from a 1D internal table.
 
double GetValue (double rowKey, double colKey) const
 Get a value from a 2D internal table.
 
double GetValue (double rowKey, double colKey, double TableKey) const
 Get a value from a 3D internal table.
 
double GetValue (void) const
 Get the current table value.
 
double operator() (unsigned int r, unsigned int c) const
 
FGTableoperator<< (const double x)
 
void operator<< (std::istream &)
 Read the table in.
 
FGTableoperator= (const FGTable &)
 Copy assignment constructor.
 
void Print (void)
 
void SetColumnIndexProperty (SGPropertyNode *node)
 
void SetRowIndexProperty (SGPropertyNode *node)
 
- Public Member Functions inherited from FGParameter
double getDoubleValue (void) const
 
virtual bool IsConstant (void) const
 
- Public Member Functions inherited from FGJSBBase
 FGJSBBase ()
 Constructor for FGJSBBase.
 
virtual ~FGJSBBase ()
 Destructor for FGJSBBase.
 
void disableHighLighting (void)
 Disables highlighting in the console output.
 

Additional Inherited Members

- Public Types inherited from FGJSBBase
enum  { eL = 1 , eM , eN }
 Moments L, M, N. More...
 
enum  { eP = 1 , eQ , eR }
 Rates P, Q, R. More...
 
enum  { eU = 1 , eV , eW }
 Velocities U, V, W. More...
 
enum  { eX = 1 , eY , eZ }
 Positions X, Y, Z. More...
 
enum  { ePhi = 1 , eTht , ePsi }
 Euler angles Phi, Theta, Psi. More...
 
enum  { eDrag = 1 , eSide , eLift }
 Stability axis forces, Drag, Side force, Lift. More...
 
enum  { eRoll = 1 , ePitch , eYaw }
 Local frame orientation Roll, Pitch, Yaw. More...
 
enum  { eNorth = 1 , eEast , eDown }
 Local frame position North, East, Down. More...
 
enum  { eLat = 1 , eLong , eRad }
 Locations Radius, Latitude, Longitude. More...
 
enum  {
  inNone = 0 , inDegrees , inRadians , inMeters ,
  inFeet
}
 Conversion specifiers. More...
 
- Static Public Member Functions inherited from FGJSBBase
static const std::string & GetVersion (void)
 Returns the version number of JSBSim.
 
static constexpr double KelvinToFahrenheit (double kelvin)
 Converts from degrees Kelvin to degrees Fahrenheit.
 
static constexpr double CelsiusToRankine (double celsius)
 Converts from degrees Celsius to degrees Rankine.
 
static constexpr double RankineToCelsius (double rankine)
 Converts from degrees Rankine to degrees Celsius.
 
static constexpr double KelvinToRankine (double kelvin)
 Converts from degrees Kelvin to degrees Rankine.
 
static constexpr double RankineToKelvin (double rankine)
 Converts from degrees Rankine to degrees Kelvin.
 
static constexpr double FahrenheitToCelsius (double fahrenheit)
 Converts from degrees Fahrenheit to degrees Celsius.
 
static constexpr double CelsiusToFahrenheit (double celsius)
 Converts from degrees Celsius to degrees Fahrenheit.
 
static constexpr double CelsiusToKelvin (double celsius)
 Converts from degrees Celsius to degrees Kelvin.
 
static constexpr double KelvinToCelsius (double kelvin)
 Converts from degrees Kelvin to degrees Celsius.
 
static constexpr double FeetToMeters (double measure)
 Converts from feet to meters.
 
static bool EqualToRoundoff (double a, double b)
 Finite precision comparison.
 
static bool EqualToRoundoff (float a, float b)
 Finite precision comparison.
 
static bool EqualToRoundoff (float a, double b)
 Finite precision comparison.
 
static bool EqualToRoundoff (double a, float b)
 Finite precision comparison.
 
static constexpr double Constrain (double min, double value, double max)
 Constrain a value between a minimum and a maximum value.
 
static constexpr double sign (double num)
 
- Static Public Attributes inherited from FGJSBBase
static char highint [5] = {27, '[', '1', 'm', '\0' }
 highlights text
 
static char halfint [5] = {27, '[', '2', 'm', '\0' }
 low intensity text
 
static char normint [6] = {27, '[', '2', '2', 'm', '\0' }
 normal intensity text
 
static char reset [5] = {27, '[', '0', 'm', '\0' }
 resets text properties
 
static char underon [5] = {27, '[', '4', 'm', '\0' }
 underlines text
 
static char underoff [6] = {27, '[', '2', '4', 'm', '\0' }
 underline off
 
static char fgblue [6] = {27, '[', '3', '4', 'm', '\0' }
 blue text
 
static char fgcyan [6] = {27, '[', '3', '6', 'm', '\0' }
 cyan text
 
static char fgred [6] = {27, '[', '3', '1', 'm', '\0' }
 red text
 
static char fggreen [6] = {27, '[', '3', '2', 'm', '\0' }
 green text
 
static char fgdef [6] = {27, '[', '3', '9', 'm', '\0' }
 default text
 
static short debug_lvl = 1
 
- Static Protected Member Functions inherited from FGJSBBase
static std::string CreateIndexedPropertyName (const std::string &Property, int index)
 
- Static Protected Attributes inherited from FGJSBBase
static constexpr double radtodeg = 180. / M_PI
 
static constexpr double degtorad = M_PI / 180.
 
static constexpr double hptoftlbssec = 550.0
 
static constexpr double psftoinhg = 0.014138
 
static constexpr double psftopa = 47.88
 
static constexpr double fttom = 0.3048
 
static constexpr double ktstofps = 1852./(3600*fttom)
 
static constexpr double fpstokts = 1.0 / ktstofps
 
static constexpr double inchtoft = 1.0/12.0
 
static constexpr double m3toft3 = 1.0/(fttom*fttom*fttom)
 
static constexpr double in3tom3 = inchtoft*inchtoft*inchtoft/m3toft3
 
static constexpr double inhgtopa = 3386.38
 
static constexpr double slugtolb = 32.174049
 Note that definition of lbtoslug by the inverse of slugtolb and not to a different constant you can also get from some tables will make lbtoslug*slugtolb == 1 up to the magnitude of roundoff.
 
static constexpr double lbtoslug = 1.0/slugtolb
 
static constexpr double kgtolb = 2.20462
 
static constexpr double kgtoslug = 0.06852168
 
static const std::string needed_cfg_version = "2.0"
 
static const std::string JSBSim_version = JSBSIM_VERSION " " __DATE__ " " __TIME__
 

Constructor & Destructor Documentation

◆ ~FGTable()

~FGTable ( )

Destructor.

Definition at line 491 of file FGTable.cpp.

492{
493 // Untie the bound property so that it makes no further reference to this
494 // instance of FGTable after the destruction is completed.
495 if (!Name.empty() && !internal) {
496 string tmp = PropertyManager->mkPropertyName(Name, false);
497 SGPropertyNode* node = PropertyManager->GetNode(tmp);
498 if (node && node->isTied())
499 PropertyManager->Untie(node);
500 }
501
502 Debug(1);
503}
A node in a property tree.
Definition props.hxx:747
bool isTied() const
Test whether this node is bound to an external data source.
Definition props.hxx:1349
+ Here is the call graph for this function:

◆ FGTable() [1/4]

FGTable ( const FGTable table)

This is the very important copy constructor.

Parameters
tablea const reference to a table.

Definition at line 195 of file FGTable.cpp.

196 : PropertyManager(t.PropertyManager)
197{
198 Type = t.Type;
199 nRows = t.nRows;
200 nCols = t.nCols;
201 nDims = t.nDims;
202 internal = t.internal;
203 Name = t.Name;
204 lookupProperty = t.lookupProperty;
205
206 // Deep copy of t.Tables
207 Tables.reserve(t.Tables.size());
208 for(const auto& table: t.Tables)
209 Tables.push_back(std::make_unique<FGTable>(*table));
210
211 lookupPropertyValues.resize(nDims);
212 Data = t.Data;
213}
FGTable(const FGTable &table)
This is the very important copy constructor.
Definition FGTable.cpp:195

◆ FGTable() [2/4]

FGTable ( std::shared_ptr< FGPropertyManager >  propMan,
Element el,
const std::string &  prefix = "" 
)

The constructor for a table.

Definition at line 217 of file FGTable.cpp.

219 : PropertyManager(pm)
220{
221 // Is this an internal lookup table?
222
223 Name = el->GetAttributeValue("name"); // Allow this table to be named with a property
224 const string call_type = el->GetAttributeValue("type");
225 if (call_type == "internal") {
226 internal = true;
227 } else if (!call_type.empty()) {
228 XMLLogException err(el);
229 err << " An unknown table type attribute is listed: " << call_type << "\n";
230 throw err;
231 }
232
233 // Determine and store the lookup properties for this table unless this table
234 // is part of a higher-dimensional table, in which case its independentVar
235 // property indexes will be set by a call from the owning table during creation
236
237 unsigned int declared_dimension = 0u;
238
239 Element* axisElement = el->FindElement("independentVar");
240 if (axisElement) {
241
242 // The 'internal' attribute of the table element cannot be specified
243 // at the same time that independentVars are specified.
244 if (internal) {
245 FGXMLLogging log(el, LogLevel::ERROR);
246 log << LogFormat::RED << " This table specifies both 'internal' call type\n"
247 << " and specific lookup properties via the 'independentVar' element.\n"
248 << " These are mutually exclusive specifications. The 'internal'\n"
249 << " attribute will be ignored.\n" << LogFormat::DEFAULT;
250 internal = false;
251 }
252
253 while (axisElement) {
254 string property_string = axisElement->GetDataLine();
255 if (property_string.find("#") != string::npos && is_number(Prefix))
256 property_string = replace(property_string, "#", Prefix);
257
258 FGPropertyValue_ptr node = new FGPropertyValue(property_string,
259 PropertyManager, axisElement);
260
261 const std::string lookup_axis = axisElement->GetAttributeValue("lookup");
262 const std::optional<unsigned int> axis = ParseLookupAxis(lookup_axis);
263
264 if (!axis.has_value()) {
265 XMLLogException err(axisElement);
266 err << "FGTable: lookup axis specification not understood: " << lookup_axis <<"\n";
267 throw err;
268 }
269
270 if (HasLookupProperty(*axis)) {
271 XMLLogException err(axisElement);
272 err << "FGTable: duplicate lookup axis \"" << LookupAxisName(*axis) << "\"\n";
273 throw err;
274 }
275
276 SetLookupProperty(*axis, node);
277 declared_dimension = std::max(declared_dimension, *axis + 1u);
278 axisElement = el->FindNextElement("independentVar");
279 }
280
281 // Check that the lookup axes match the declared dimension of the table.
282 for (unsigned int axis=0u; axis<declared_dimension; ++axis) {
283 if (!HasLookupProperty(axis)) {
284 XMLLogException err(el);
285 err << "FGTable: missing lookup axis \"" << LookupAxisName(axis) << "\"\n";
286 throw err;
287 }
288 }
289
290 } else if (!internal && el->GetName() != "tableData") {
291 // no independentVars found, and table is not marked as internal, nor is it
292 // a nested sub-table
293 XMLLogException err(el);
294 err << "No independentVars found, and table is not marked as internal,"
295 << " nor is it a nested sub-table.\n";
296 throw err;
297 }
298 // end lookup property code
299
300 Element* leafData = nullptr;
301
302 const unsigned int nChildTableData = el->GetNumElements("tableData");
303
304 if (el->GetName() == "tableData" && nChildTableData == 0u) {
305 // This is a leaf <tableData> element with numeric content
306 leafData = el;
307 } else if (el->GetName() != "tableData" && nChildTableData == 1u) {
308 // 1D and 2D tables
309 leafData = el->FindElement("tableData");
310 } else if (nChildTableData > 1u) {
311 // N-dimensional table: multiple <tableData> children (3D+), or a container
312 // <tableData> with nested <tableData> children (4D+)
313 Type = ttND;
314 // Fill unused elements with NaNs to detect illegal access.
315 Data.push_back(std::numeric_limits<double>::quiet_NaN());
316 nCols = 1u;
317
318 Element* child = el->FindElement("tableData");
319
320 while (child) {
321 const string brkpt_string = child->GetAttributeValue("breakPoint");
322 if (brkpt_string.empty()) {
323 XMLLogException err(child);
324 err << "FGTable: missing breakPoint on <tableData>\n";
325 throw err;
326 }
327
328 auto subtable = std::make_unique<FGTable>(PropertyManager, child);
329
330 if (nDims == 0u) {
331 nDims = subtable->nDims + 1u;
332 if (nDims < 3u) {
333 XMLLogException err(child);
334 err << "FGTable: nested tables must contain at least 2D subtables\n";
335 throw err;
336 }
337 } else if (subtable->nDims + 1u != nDims) {
338 XMLLogException err(child);
339 err << "FGTable: inconsistent sub-table dimensionality in nested table\n";
340 throw err;
341 }
342
343 Data.push_back(child->GetAttributeValueAsNumber("breakPoint"));
344 Tables.push_back(std::move(subtable));
345 child = el->FindNextElement("tableData");
346 }
347
348 nRows = static_cast<unsigned int>(Tables.size());
349 } else {
350 XMLLogException err(el);
351 err << "FGTable: <tableData> elements are missing\n";
352 throw err;
353 }
354
355 if (leafData) {
356 stringstream buf;
357 AppendNumericData(leafData, buf);
358
359 nDims = InferLeafDimension(leafData);
360
361 switch (nDims) {
362 case 1u:
363 nRows = leafData->GetNumDataLines();
364 nCols = 1u;
365 Type = tt1D;
366 // Fill unused elements with NaNs to detect illegal access.
367 Data.push_back(std::numeric_limits<double>::quiet_NaN());
368 Data.push_back(std::numeric_limits<double>::quiet_NaN());
369 *this << buf;
370 break;
371 case 2u:
372 nRows = leafData->GetNumDataLines()-1u;
373 nCols = FindNumColumns(leafData->GetDataLine(0));
374 Type = tt2D;
375 // Fill unused elements with NaNs to detect illegal access.
376 Data.push_back(std::numeric_limits<double>::quiet_NaN());
377 *this << buf;
378 break;
379 default:
380 assert(false); // Should never be called
381 break;
382 }
383 }
384
385 if (declared_dimension != 0u && declared_dimension != nDims) {
386 XMLLogException err(el);
387 err << "FGTable: " << declared_dimension
388 << " lookup axes were declared, but the tableData nesting implies a "
389 << nDims << "D table.\n";
390 throw err;
391 }
392
393 Debug(0);
394
395 // Sanity checks: lookup indices must be increasing monotonically
396
397 // find next xml element containing a name attribute
398 // to indicate where the error occured
399 Element* nameel = el;
400 while (nameel && nameel->GetAttributeValue("name") == "")
401 nameel=nameel->GetParent();
402
403 // check breakpoints, if applicable
404 if (Type == ttND) {
405 for (unsigned int b=2; b<=Tables.size(); ++b) {
406 if (Data[b] <= Data[b-1]) {
407 XMLLogException err(el);
408 err << LogFormat::RED << LogFormat::BOLD
409 << " FGTable: breakpoint lookup is not monotonically increasing\n"
410 << " in breakpoint " << b;
411 if (nameel) err << " of table in " << nameel->GetAttributeValue("name");
412 err << ":\n" << LogFormat::RESET
413 << " " << Data[b] << "<=" << Data[b-1] << "\n";
414 throw err;
415 }
416 }
417 }
418
419 // check columns, if applicable
420 if (Type == tt2D) {
421 for (unsigned int c=2; c<=nCols; ++c) {
422 if (Data[c] <= Data[c-1]) {
423 XMLLogException err(el);
424 err << LogFormat::RED << LogFormat::BOLD
425 << " FGTable: column lookup is not monotonically increasing\n"
426 << " in column " << c;
427 if (nameel != 0) err << " of table in " << nameel->GetAttributeValue("name");
428 err << ":\n" << LogFormat::RESET
429 << " " << Data[c] << "<=" << Data[c-1] << "\n";
430 throw err;
431 }
432 }
433 }
434
435 // check rows
436 if (Type != ttND) { // in ND tables, check only rows of subtables
437 for (size_t r=2; r<=nRows; ++r) {
438 if (Data[r*(nCols+1)]<=Data[(r-1)*(nCols+1)]) {
439 XMLLogException err(el);
440 err << LogFormat::RED << LogFormat::BOLD
441 << " FGTable: row lookup is not monotonically increasing\n"
442 << " in row " << r;
443 if (nameel != 0) err << " of table in " << nameel->GetAttributeValue("name");
444 err << ":\n" << LogFormat::RESET
445 << " " << Data[r*(nCols+1)] << "<=" << Data[(r-1)*(nCols+1)] << "\n";
446 throw err;
447 }
448 }
449 }
450
451 // Check the table has been entirely populated.
452 switch (Type) {
453 case tt1D:
454 if (Data.size() != 2*nRows+2) missingData(el, 2*nRows, Data.size()-2);
455 break;
456 case tt2D:
457 if (Data.size() != static_cast<size_t>(nRows+1)*(nCols+1))
458 missingData(el, (nRows+1)*(nCols+1)-1, Data.size()-1);
459 break;
460 case ttND:
461 if (Data.size() != nRows+1) missingData(el, nRows, Data.size()-1);
462 break;
463 default:
464 assert(false); // Should never be called
465 break;
466 }
467
468 lookupPropertyValues.resize(nDims);
469
470 bind(el, Prefix);
471
472 if (debug_lvl & 1) Print();
473}
+ Here is the call graph for this function:

◆ FGTable() [3/4]

FGTable ( int  NRows)

Definition at line 172 of file FGTable.cpp.

173 : nRows(NRows), nCols(1u), nDims(1u)
174{
175 Type = tt1D;
176 // Fill unused elements with NaNs to detect illegal access.
177 Data.push_back(std::numeric_limits<double>::quiet_NaN());
178 Data.push_back(std::numeric_limits<double>::quiet_NaN());
179 Debug(0);
180}

◆ FGTable() [4/4]

FGTable ( int  NRows,
int  NCols 
)

Definition at line 184 of file FGTable.cpp.

185 : nRows(NRows), nCols(NCols), nDims(2u)
186{
187 Type = tt2D;
188 // Fill unused elements with NaNs to detect illegal access.
189 Data.push_back(std::numeric_limits<double>::quiet_NaN());
190 Debug(0);
191}

Member Function Documentation

◆ GetElement()

double GetElement ( unsigned int  r,
unsigned int  c 
) const

Definition at line 507 of file FGTable.cpp.

508{
509 assert(r <= nRows && c <= nCols);
510 if (Type == ttND) {
511 assert(Data.size() == nRows+1);
512 return Data[r];
513 }
514 assert(Data.size() == (nCols+1)*(nRows+1));
515 return Data[r*(nCols+1)+c];
516}

◆ GetMinValue()

double GetMinValue ( void  ) const

Definition at line 696 of file FGTable.cpp.

697{
698 assert(Type == tt1D);
699 assert(Data.size() == 2*nRows+2);
700
701 double minValue = HUGE_VAL;
702
703 for(unsigned int i=1; i<=nRows; ++i)
704 minValue = std::min(minValue, Data[2*i+1]);
705
706 return minValue;
707}

◆ GetName()

std::string GetName ( void  ) const
inlinevirtual

Implements FGParameter.

Definition at line 416 of file FGTable.h.

416{return Name;}

◆ GetNumRows()

unsigned int GetNumRows ( ) const
inline

Definition at line 412 of file FGTable.h.

412{return nRows;}

◆ GetValue() [1/8]

double GetValue ( const std::vector< double > &  keys) const

Definition at line 547 of file FGTable.cpp.

548{
549 if (keys.size() < nDims) {
550 // If we do not throw here then we will segfault in FGTable::GetValue(const double*)
551 LogException err;
552 err << "Keys size does not match the table dimensions.\n";
553 throw err;
554 }
555
556 return GetValue(keys.data());
557}
double GetValue(void) const
Get the current table value.
Definition FGTable.cpp:520

◆ GetValue() [2/8]

double GetValue ( double  a1,
double  a2,
double  a3,
double  a4 
) const

Definition at line 668 of file FGTable.cpp.

669{
670 const double keys[4] = {a1, a2, a3, a4};
671 assert(nDims == 4);
672 return GetValue(keys);
673}

◆ GetValue() [3/8]

double GetValue ( double  a1,
double  a2,
double  a3,
double  a4,
double  a5 
) const

Definition at line 677 of file FGTable.cpp.

678{
679 const double keys[5] = {a1, a2, a3, a4, a5};
680 assert(nDims == 5);
681 return GetValue(keys);
682}

◆ GetValue() [4/8]

double GetValue ( double  a1,
double  a2,
double  a3,
double  a4,
double  a5,
double  a6 
) const

Definition at line 686 of file FGTable.cpp.

688{
689 const double keys[6] = {a1, a2, a3, a4, a5, a6};
690 assert(nDims == 6);
691 return GetValue(keys);
692}

◆ GetValue() [5/8]

double GetValue ( double  key) const

Get a value from a 1D internal table.

Parameters
keyRow coordinate at which the value must be interpolated
Returns
The interpolated value

Definition at line 598 of file FGTable.cpp.

599{
600 assert((Type == tt1D) || (Type == tt2D && nCols == 1));
601 assert(Data.size() == 2*nRows+2);
602 // If the key is off the end (or before the beginning) of the table, just
603 // return the boundary-table value, do not extrapolate.
604 if (key <= Data[2])
605 return Data[3];
606 else if (key >= Data[2*nRows])
607 return Data[2*nRows+1];
608
609 // Search for the right breakpoint.
610 // This is a linear search, the algorithm is O(n).
611 unsigned int r = 2;
612 while (Data[2*r] < key) r++;
613
614 double x0 = Data[2*r-2];
615 double Span = Data[2*r] - x0;
616 assert(Span > 0.0);
617 double Factor = (key - x0) / Span;
618 assert(Factor >= 0.0 && Factor <= 1.0);
619
620 double y0 = Data[2*r-1];
621 return Factor*(Data[2*r+1] - y0) + y0;
622}

◆ GetValue() [6/8]

double GetValue ( double  rowKey,
double  colKey 
) const

Get a value from a 2D internal table.

Parameters
rowKeyRow coordinate at which the value must be interpolated
colKeyColumn coordinate at which the value must be interpolated
Returns
The interpolated value

Definition at line 626 of file FGTable.cpp.

627{
628 assert(Type == tt2D);
629 assert(Data.size() == (nCols+1)*(nRows+1));
630
631 if (nCols == 1) return GetValue(rowKey);
632
633 unsigned int c = 2;
634 while(Data[c] < colKey && c < nCols) c++;
635 double x0 = Data[c-1];
636 double Span = Data[c] - x0;
637 assert(Span > 0.0);
638 double cFactor = Constrain(0.0, (colKey - x0) / Span, 1.0);
639
640 if (nRows == 1) {
641 double y0 = Data[(nCols+1)+c-1];
642 return cFactor*(Data[(nCols+1)+c] - y0) + y0;
643 }
644
645 size_t r = 2;
646 while(Data[r*(nCols+1)] < rowKey && r < nRows) r++;
647 x0 = Data[(r-1)*(nCols+1)];
648 Span = Data[r*(nCols+1)] - x0;
649 assert(Span > 0.0);
650 double rFactor = Constrain(0.0, (rowKey - x0) / Span, 1.0);
651 double col1temp = rFactor*Data[r*(nCols+1)+c-1]+(1.0-rFactor)*Data[(r-1)*(nCols+1)+c-1];
652 double col2temp = rFactor*Data[r*(nCols+1)+c]+(1.0-rFactor)*Data[(r-1)*(nCols+1)+c];
653
654 return cFactor*(col2temp-col1temp)+col1temp;
655}
static constexpr double Constrain(double min, double value, double max)
Constrain a value between a minimum and a maximum value.
Definition FGJSBBase.h:289
+ Here is the call graph for this function:

◆ GetValue() [7/8]

double GetValue ( double  rowKey,
double  colKey,
double  TableKey 
) const

Get a value from a 3D internal table.

Parameters
rowKeyRow coordinate at which the value must be interpolated
colKeyColumn coordinate at which the value must be interpolated
TableKeyTable coordinate at which the value must be interpolated
Returns
The interpolated value

Definition at line 659 of file FGTable.cpp.

660{
661 const double keys[3] = {rowKey, colKey, tableKey};
662 assert(nDims == 3);
663 return GetValue(keys);
664}
+ Here is the call graph for this function:

◆ GetValue() [8/8]

double GetValue ( void  ) const
virtual

Get the current table value.

Implements FGParameter.

Definition at line 520 of file FGTable.cpp.

521{
522 assert(!internal);
523 assert(nDims > 0u);
524
525 switch(Type) {
526 case tt1D:
527 return GetValue(lookupProperty[eRow]->getDoubleValue());
528 case tt2D:
529 return GetValue(lookupProperty[eRow]->getDoubleValue(),
530 lookupProperty[eColumn]->getDoubleValue());
531 case ttND:
532 {
533 for (unsigned int axis=0u; axis<nDims; ++axis) {
534 assert(HasLookupProperty(axis));
535 lookupPropertyValues[axis] = lookupProperty[axis]->getDoubleValue();
536 }
537
538 return GetValue(lookupPropertyValues.data());
539 }
540 default:
541 assert(false);
542 }
543}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ operator()()

double operator() ( unsigned int  r,
unsigned int  c 
) const
inline

Definition at line 404 of file FGTable.h.

405 { return GetElement(r, c); }

◆ operator<<() [1/2]

FGTable & operator<< ( const double  x)

Definition at line 725 of file FGTable.cpp.

726{
727 assert(Type != ttND);
728 Data.push_back(x);
729
730 // Check column is monotically increasing
731 size_t n = Data.size();
732 if (Type == tt2D && nCols > 1 && n >= 3 && n <= nCols+1) {
733 if (Data.at(n-1) <= Data.at(n-2))
734 throw BaseException("FGTable: column lookup is not monotonically increasing");
735 }
736
737 // Check row is monotically increasing
738 size_t row = (n-1) / (nCols+1);
739 if (row >=2 && row*(nCols+1) == n-1) {
740 if (Data.at(row*(nCols+1)) <= Data.at((row-1)*(nCols+1)))
741 throw BaseException("FGTable: row lookup is not monotonically increasing");
742 }
743
744 return *this;
745}

◆ operator<<() [2/2]

void operator<< ( std::istream &  in_stream)

Read the table in.

Data in the config file should be in matrix format with the row independents as the first column and the column independents in the first row. The implication of this layout is that there should be no value in the upper left corner of the matrix e.g:

     0  10  20 30 ...
-5   1  2   3  4  ...
 ...
 

For multiple-table (i.e. 3D) data sets there is an additional number key in the table definition. For example:

 0.0
     0  10  20 30 ...
-5   1  2   3  4  ...
 ...
 

Definition at line 711 of file FGTable.cpp.

712{
713 double x;
714 assert(Type != ttND);
715
716 in_stream >> x;
717 while(in_stream) {
718 Data.push_back(x);
719 in_stream >> x;
720 }
721}

◆ Print()

void Print ( void  )

Definition at line 749 of file FGTable.cpp.

750{
751 FGLogging out(LogLevel::STDOUT);
752 out << std::setprecision(4);
753
754 switch(Type) {
755 case tt1D:
756 out << " 1 dimensional table with " << nRows << " rows.\n";
757 break;
758 case tt2D:
759 out << " 2 dimensional table with " << nRows << " rows, " << nCols << " columns.\n";
760 break;
761 case ttND:
762 out << " " << nDims << " dimensional table with " << nRows
763 << " breakpoints, " << Tables.size() << " subtables.\n";
764 break;
765 }
766 unsigned int startCol=1, startRow=1;
767 unsigned int p = 1;
768
769 if (Type == tt1D) {
770 startCol = 0;
771 p = 2;
772 }
773 if (Type == tt2D) startRow = 0;
774
775 for (unsigned int r=startRow; r<=nRows; r++) {
776 out << "\t";
777 if (Type == tt2D) {
778 if (r == startRow)
779 out << "\t";
780 else
781 startCol = 0;
782 }
783
784 for (unsigned int c=startCol; c<=nCols; c++) {
785 out << Data[p++] << "\t";
786 if (Type == ttND) {
787 out << "\n";
788 Tables[r-1]->Print();
789 }
790 }
791 out << "\n";
792 }
793 out << std::fixed;
794}

◆ SetColumnIndexProperty()

void SetColumnIndexProperty ( SGPropertyNode node)
inline

Definition at line 409 of file FGTable.h.

410 { SetLookupProperty(eColumn, new FGPropertyValue(node)); }

◆ SetRowIndexProperty()

void SetRowIndexProperty ( SGPropertyNode node)
inline

Definition at line 407 of file FGTable.h.

408 { SetLookupProperty(eRow, new FGPropertyValue(node)); }

The documentation for this class was generated from the following files: