JSBSim Flight Dynamics Model 1.3.3 (16 Oct 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
 
FGTable & operator<< (const double x)
 
void operator<< (std::istream &)
 Read the table in.
 
FGTable & operator= (const FGTable &)
 Copy assignment constructor.
 
void Print ()
 
void Print (FGLogging &out)
 
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.
 

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 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 CelsiusToRankine (double celsius)
 Converts from degrees Celsius to degrees Rankine.
 
static constexpr double Constrain (double min, double value, double max)
 Constrain a value between a minimum and a maximum value.
 
static bool EqualToRoundoff (double a, double b)
 Finite precision comparison.
 
static bool EqualToRoundoff (double a, float b)
 Finite precision comparison.
 
static bool EqualToRoundoff (float a, double b)
 Finite precision comparison.
 
static bool EqualToRoundoff (float a, float b)
 Finite precision comparison.
 
static constexpr double FahrenheitToCelsius (double fahrenheit)
 Converts from degrees Fahrenheit to degrees Celsius.
 
static constexpr double FeetToMeters (double measure)
 Converts from feet to meters.
 
static const std::string & GetVersion (void)
 Returns the version number of JSBSim.
 
static constexpr double KelvinToCelsius (double kelvin)
 Converts from degrees Kelvin to degrees Celsius.
 
static constexpr double KelvinToFahrenheit (double kelvin)
 Converts from degrees Kelvin to degrees Fahrenheit.
 
static constexpr double KelvinToRankine (double kelvin)
 Converts from degrees Kelvin to degrees Rankine.
 
static constexpr double RankineToCelsius (double rankine)
 Converts from degrees Rankine to degrees Celsius.
 
static constexpr double RankineToKelvin (double rankine)
 Converts from degrees Rankine to degrees Kelvin.
 
static constexpr double sign (double num)
 
- Static Public Attributes inherited from FGJSBBase
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 degtorad = M_PI / 180.
 
static constexpr double fpstokts = 1.0 / ktstofps
 
static constexpr double fttom = 0.3048
 
static constexpr double hptoftlbssec = 550.0
 
static constexpr double in3tom3 = inchtoft*inchtoft*inchtoft/m3toft3
 
static constexpr double inchtoft = 1.0/12.0
 
static constexpr double inhgtopa = 3386.38
 
static const std::string JSBSim_version = JSBSIM_VERSION " " __DATE__ " " __TIME__
 
static constexpr double kgtolb = 2.20462
 
static constexpr double kgtoslug = 0.06852168
 
static constexpr double ktstofps = 1852./(3600*fttom)
 
static constexpr double lbtoslug = 1.0/slugtolb
 
static constexpr double m3toft3 = 1.0/(fttom*fttom*fttom)
 
static const std::string needed_cfg_version = "2.0"
 
static constexpr double psftoinhg = 0.014138
 
static constexpr double psftopa = 47.88
 
static constexpr double radtodeg = 180. / M_PI
 
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.
 

Constructor & Destructor Documentation

◆ ~FGTable()

~FGTable ( )

Destructor.

Definition at line 523 of file FGTable.cpp.

524{
525 // Untie the bound property so that it makes no further reference to this
526 // instance of FGTable after the destruction is completed.
527 if (!Name.empty() && !internal) {
528 string tmp = PropertyManager->mkPropertyName(Name, false);
529 SGPropertyNode* node = PropertyManager->GetNode(tmp);
530 if (node && node->isTied())
531 PropertyManager->Untie(node);
532 }
533
534 Debug(1);
535}
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 224 of file FGTable.cpp.

225 : PropertyManager(t.PropertyManager)
226{
227 Type = t.Type;
228 nRows = t.nRows;
229 nCols = t.nCols;
230 nDims = t.nDims;
231 internal = t.internal;
232 Name = t.Name;
233 lookupProperty = t.lookupProperty;
234
235 // Deep copy of t.Tables
236 Tables.reserve(t.Tables.size());
237 for(const auto& table: t.Tables)
238 Tables.push_back(std::make_unique<FGTable>(*table));
239
240 lookupPropertyValues.resize(nDims);
241 Data = t.Data;
242}
FGTable(const FGTable &table)
This is the very important copy constructor.
Definition FGTable.cpp:224

◆ FGTable() [2/4]

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

The constructor for a table.

Definition at line 246 of file FGTable.cpp.

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

◆ FGTable() [3/4]

FGTable ( int  NRows)

Definition at line 201 of file FGTable.cpp.

202 : nRows(NRows), nCols(1u), nDims(1u)
203{
204 Type = tt1D;
205 // Fill unused elements with NaNs to detect illegal access.
206 Data.push_back(std::numeric_limits<double>::quiet_NaN());
207 Data.push_back(std::numeric_limits<double>::quiet_NaN());
208 Debug(0);
209}

◆ FGTable() [4/4]

FGTable ( int  NRows,
int  NCols 
)

Definition at line 213 of file FGTable.cpp.

214 : nRows(NRows), nCols(NCols), nDims(2u)
215{
216 Type = tt2D;
217 // Fill unused elements with NaNs to detect illegal access.
218 Data.push_back(std::numeric_limits<double>::quiet_NaN());
219 Debug(0);
220}

Member Function Documentation

◆ GetElement()

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

Definition at line 539 of file FGTable.cpp.

540{
541 assert(r <= nRows && c <= nCols);
542 if (Type == ttND) {
543 assert(Data.size() == nRows+1);
544 return Data[r];
545 }
546 assert(Data.size() == (nCols+1)*(nRows+1));
547 return Data[r*(nCols+1)+c];
548}

◆ GetMinValue()

double GetMinValue ( void  ) const

Definition at line 728 of file FGTable.cpp.

729{
730 assert(Type == tt1D);
731 assert(Data.size() == 2*nRows+2);
732
733 double minValue = HUGE_VAL;
734
735 for(unsigned int i=1; i<=nRows; ++i)
736 minValue = std::min(minValue, Data[2*i+1]);
737
738 return minValue;
739}

◆ GetName()

std::string GetName ( void  ) const
inlinevirtual

Implements FGParameter.

Definition at line 417 of file FGTable.h.

417{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 579 of file FGTable.cpp.

580{
581 if (keys.size() < nDims) {
582 // If we do not throw here then we will segfault in FGTable::GetValue(const double*)
583 LogException err;
584 err << "Keys size does not match the table dimensions.\n";
585 throw err;
586 }
587
588 return GetValue(keys.data());
589}
double GetValue(void) const
Get the current table value.
Definition FGTable.cpp:552

◆ GetValue() [2/8]

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

Definition at line 700 of file FGTable.cpp.

701{
702 const double keys[4] = {a1, a2, a3, a4};
703 assert(nDims == 4);
704 return GetValue(keys);
705}

◆ GetValue() [3/8]

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

Definition at line 709 of file FGTable.cpp.

710{
711 const double keys[5] = {a1, a2, a3, a4, a5};
712 assert(nDims == 5);
713 return GetValue(keys);
714}

◆ GetValue() [4/8]

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

Definition at line 718 of file FGTable.cpp.

720{
721 const double keys[6] = {a1, a2, a3, a4, a5, a6};
722 assert(nDims == 6);
723 return GetValue(keys);
724}

◆ 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 630 of file FGTable.cpp.

631{
632 assert((Type == tt1D) || (Type == tt2D && nCols == 1));
633 assert(Data.size() == 2*nRows+2);
634 // If the key is off the end (or before the beginning) of the table, just
635 // return the boundary-table value, do not extrapolate.
636 if (key <= Data[2])
637 return Data[3];
638 else if (key >= Data[2*nRows])
639 return Data[2*nRows+1];
640
641 // Search for the right breakpoint.
642 // This is a linear search, the algorithm is O(n).
643 unsigned int r = 2;
644 while (Data[2*r] < key) r++;
645
646 double x0 = Data[2*r-2];
647 double Span = Data[2*r] - x0;
648 assert(Span > 0.0);
649 double Factor = (key - x0) / Span;
650 assert(Factor >= 0.0 && Factor <= 1.0);
651
652 double y0 = Data[2*r-1];
653 return Factor*(Data[2*r+1] - y0) + y0;
654}

◆ 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 658 of file FGTable.cpp.

659{
660 assert(Type == tt2D);
661 assert(Data.size() == (nCols+1)*(nRows+1));
662
663 if (nCols == 1) return GetValue(rowKey);
664
665 unsigned int c = 2;
666 while(Data[c] < colKey && c < nCols) c++;
667 double x0 = Data[c-1];
668 double Span = Data[c] - x0;
669 assert(Span > 0.0);
670 double cFactor = Constrain(0.0, (colKey - x0) / Span, 1.0);
671
672 if (nRows == 1) {
673 double y0 = Data[(nCols+1)+c-1];
674 return cFactor*(Data[(nCols+1)+c] - y0) + y0;
675 }
676
677 size_t r = 2;
678 while(Data[r*(nCols+1)] < rowKey && r < nRows) r++;
679 x0 = Data[(r-1)*(nCols+1)];
680 Span = Data[r*(nCols+1)] - x0;
681 assert(Span > 0.0);
682 double rFactor = Constrain(0.0, (rowKey - x0) / Span, 1.0);
683 double col1temp = rFactor*Data[r*(nCols+1)+c-1]+(1.0-rFactor)*Data[(r-1)*(nCols+1)+c-1];
684 double col2temp = rFactor*Data[r*(nCols+1)+c]+(1.0-rFactor)*Data[(r-1)*(nCols+1)+c];
685
686 return cFactor*(col2temp-col1temp)+col1temp;
687}
static constexpr double Constrain(double min, double value, double max)
Constrain a value between a minimum and a maximum value.
Definition FGJSBBase.h:258
+ 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 691 of file FGTable.cpp.

692{
693 const double keys[3] = {rowKey, colKey, tableKey};
694 assert(nDims == 3);
695 return GetValue(keys);
696}
+ 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 552 of file FGTable.cpp.

553{
554 assert(!internal);
555 assert(nDims > 0u);
556
557 switch(Type) {
558 case tt1D:
559 return GetValue(lookupProperty[eRow]->getDoubleValue());
560 case tt2D:
561 return GetValue(lookupProperty[eRow]->getDoubleValue(),
562 lookupProperty[eColumn]->getDoubleValue());
563 case ttND:
564 {
565 for (unsigned int axis=0u; axis<nDims; ++axis) {
566 assert(HasLookupProperty(axis));
567 lookupPropertyValues[axis] = lookupProperty[axis]->getDoubleValue();
568 }
569
570 return GetValue(lookupPropertyValues.data());
571 }
572 default:
573 UNREACHABLE("invalid table type") // Should never be called
574 }
575}
+ 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 757 of file FGTable.cpp.

758{
759 assert(Type != ttND);
760 Data.push_back(x);
761
762 // Check column is monotically increasing
763 size_t n = Data.size();
764 if (Type == tt2D && nCols > 1 && n >= 3 && n <= nCols+1) {
765 if (Data.at(n-1) <= Data.at(n-2))
766 throw BaseException("FGTable: column lookup is not monotonically increasing");
767 }
768
769 // Check row is monotically increasing
770 size_t row = (n-1) / (nCols+1);
771 if (row >=2 && row*(nCols+1) == n-1) {
772 if (Data.at(row*(nCols+1)) <= Data.at((row-1)*(nCols+1)))
773 throw BaseException("FGTable: row lookup is not monotonically increasing");
774 }
775
776 return *this;
777}

◆ 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 743 of file FGTable.cpp.

744{
745 double x;
746 assert(Type != ttND);
747
748 in_stream >> x;
749 while(in_stream) {
750 Data.push_back(x);
751 in_stream >> x;
752 }
753}

◆ Print() [1/2]

void Print ( )

Definition at line 781 of file FGTable.cpp.

782{
783 FGLogging out(LogLevel::STDOUT);
784 Print(out);
785}

◆ Print() [2/2]

void Print ( FGLogging &  out)

Definition at line 787 of file FGTable.cpp.

788{
789 out << std::setprecision(4);
790
791 switch(Type) {
792 case tt1D:
793 out << " 1 dimensional table with " << nRows << " rows.\n";
794 break;
795 case tt2D:
796 out << " 2 dimensional table with " << nRows << " rows, " << nCols << " columns.\n";
797 break;
798 case ttND:
799 out << " " << nDims << " dimensional table with " << nRows
800 << " breakpoints, " << Tables.size() << " subtables.\n";
801 break;
802 }
803 unsigned int startCol=1, startRow=1;
804 unsigned int p = 1;
805
806 if (Type == tt1D) {
807 startCol = 0;
808 p = 2;
809 }
810 if (Type == tt2D) startRow = 0;
811
812 for (unsigned int r=startRow; r<=nRows; r++) {
813 out << "\t";
814 if (Type == tt2D) {
815 if (r == startRow)
816 out << "\t";
817 else
818 startCol = 0;
819 }
820
821 for (unsigned int c=startCol; c<=nCols; c++) {
822 out << Data[p++] << "\t";
823 if (Type == ttND) {
824 out << "\n";
825 Tables[r-1]->Print(out);
826 }
827 }
828 out << "\n";
829 }
830 out << std::fixed;
831}

◆ 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: