JSBSim Flight Dynamics Model 1.3.0 (09 Apr 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, two, or three dimensional lookup table for use in aerodynamics and function definitions.

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>

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

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 233 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 (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 436 of file FGTable.cpp.

437{
438 // Untie the bound property so that it makes no further reference to this
439 // instance of FGTable after the destruction is completed.
440 if (!Name.empty() && !internal) {
441 string tmp = PropertyManager->mkPropertyName(Name, false);
442 SGPropertyNode* node = PropertyManager->GetNode(tmp);
443 if (node && node->isTied())
444 PropertyManager->Untie(node);
445 }
446
447 Debug(1);
448}
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 77 of file FGTable.cpp.

78 : PropertyManager(t.PropertyManager)
79{
80 Type = t.Type;
81 nRows = t.nRows;
82 nCols = t.nCols;
83 internal = t.internal;
84 Name = t.Name;
85 lookupProperty[0] = t.lookupProperty[0];
86 lookupProperty[1] = t.lookupProperty[1];
87 lookupProperty[2] = t.lookupProperty[2];
88
89 // Deep copy of t.Tables
90 Tables.reserve(t.Tables.size());
91 for(const auto &t: t.Tables)
92 Tables.push_back(std::make_unique<FGTable>(*t));
93
94 Data = t.Data;
95}
FGTable(const FGTable &table)
This is the very important copy constructor.
Definition FGTable.cpp:77

◆ FGTable() [2/4]

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

The constructor for a table.

Definition at line 113 of file FGTable.cpp.

115 : PropertyManager(pm)
116{
117 string brkpt_string;
118 Element *tableData = nullptr;
119
120 // Is this an internal lookup table?
121
122 Name = el->GetAttributeValue("name"); // Allow this table to be named with a property
123 string call_type = el->GetAttributeValue("type");
124 if (call_type == "internal") {
125 internal = true;
126 } else if (!call_type.empty()) {
127 XMLLogException err(el);
128 err <<" An unknown table type attribute is listed: " << call_type << "\n";
129 throw err;
130 }
131
132 // Determine and store the lookup properties for this table unless this table
133 // is part of a 3D table, in which case its independentVar property indexes
134 // will be set by a call from the owning table during creation
135
136 unsigned int dimension = 0;
137
138 Element* axisElement = el->FindElement("independentVar");
139 if (axisElement) {
140
141 // The 'internal' attribute of the table element cannot be specified
142 // at the same time that independentVars are specified.
143 if (internal) {
144 FGXMLLogging log(el, LogLevel::ERROR);
145 log << LogFormat::RED << " This table specifies both 'internal' call type\n"
146 << " and specific lookup properties via the 'independentVar' element.\n"
147 << " These are mutually exclusive specifications. The 'internal'\n"
148 << " attribute will be ignored.\n" << LogFormat::DEFAULT;
149 internal = false;
150 }
151
152 while (axisElement) {
153 string property_string = axisElement->GetDataLine();
154 if (property_string.find("#") != string::npos) {
155 if (is_number(Prefix)) {
156 property_string = replace(property_string,"#",Prefix);
157 }
158 }
159
160 FGPropertyValue_ptr node = new FGPropertyValue(property_string,
161 PropertyManager, axisElement);
162 string lookup_axis = axisElement->GetAttributeValue("lookup");
163 if (lookup_axis == string("row")) {
164 lookupProperty[eRow] = node;
165 dimension = std::max(dimension, 1u);
166 } else if (lookup_axis == string("column")) {
167 lookupProperty[eColumn] = node;
168 dimension = std::max(dimension, 2u);
169 } else if (lookup_axis == string("table")) {
170 lookupProperty[eTable] = node;
171 dimension = std::max(dimension, 3u);
172 } else if (!lookup_axis.empty()) {
173 throw BaseException("Lookup table axis specification not understood: " + lookup_axis);
174 } else { // assumed single dimension table; row lookup
175 lookupProperty[eRow] = node;
176 dimension = std::max(dimension, 1u);
177 }
178 axisElement = el->FindNextElement("independentVar");
179 }
180
181 } else if (internal) { // This table is an internal table
182
183 // determine how many rows, columns, and tables in this table (dimension).
184
185 if (el->GetNumElements("tableData") > 1) {
186 dimension = 3; // this is a 3D table
187 } else {
188 tableData = el->FindElement("tableData");
189 if (tableData) {
190 unsigned int nLines = tableData->GetNumDataLines();
191 unsigned int nColumns = FindNumColumns(tableData->GetDataLine(0));
192 if (nLines > 1) {
193 unsigned int nColumns1 = FindNumColumns(tableData->GetDataLine(1));
194 if (nColumns1 == nColumns + 1) {
195 dimension = 2;
196 nColumns = nColumns1;
197 }
198 else
199 dimension = 1;
200
201 // Check that every line (but the header line) has the same number of
202 // columns.
203 for(unsigned int i=1; i<nLines; ++i) {
204 if (FindNumColumns(tableData->GetDataLine(i)) != nColumns) {
205 XMLLogException err(tableData);
206 err << "Invalid number of columns in line "
207 << tableData->GetLineNumber()+i << "\n";
208 throw err;
209 }
210 }
211 }
212 else
213 dimension = 1;
214
215 if (dimension == 1 && nColumns != 2) {
216 XMLLogException err(tableData);
217 err << "Too many columns for a 1D table\n";
218 throw err;
219 }
220 }
221 }
222
223 } else {
224 brkpt_string = el->GetAttributeValue("breakPoint");
225 if (brkpt_string.empty()) {
226 // no independentVars found, and table is not marked as internal, nor is it
227 // a 3D table
228 XMLLogException err(el);
229 err << "No independentVars found, and table is not marked as internal,"
230 << " nor is it a 3D table.\n";
231 throw err;
232 }
233 }
234 // end lookup property code
235
236 if (brkpt_string.empty()) { // Not a 3D table "table element"
237 // Force the dimension to 3 if there are several instances of <tableData>.
238 // This is needed for sanity checks.
239 if (el->GetNumElements("tableData") > 1) dimension = 3;
240 tableData = el->FindElement("tableData");
241 } else { // This is a table in a 3D table
242 tableData = el;
243 dimension = 2; // Currently, infers 2D table
244 }
245
246 if (!tableData) {
247 XMLLogException err(el);
248 err << "FGTable: <tableData> elements are missing\n";
249 throw err;
250 }
251 else if (tableData->GetNumDataLines() == 0) {
252 XMLLogException err(tableData);
253 err << "<tableData> is empty.\n";
254 throw err;
255 }
256
257 // Check that the lookup axes match the declared dimension of the table.
258 if (!internal && brkpt_string.empty()) {
259 switch (dimension) {
260 case 3u:
261 if (!lookupProperty[eTable]) {
262 XMLLogException err(el);
263 err << "FGTable: missing lookup axis \"table\"\n";
264 throw err;
265 }
266 // Don't break as we want to investigate the other lookup axes as well.
267 case 2u:
268 if (!lookupProperty[eColumn]) {
269 XMLLogException err(el);
270 err << "FGTable: missing lookup axis \"column\"\n";
271 throw err;
272 }
273 // Don't break as we want to investigate the last lookup axes as well.
274 case 1u:
275 if (!lookupProperty[eRow]) {
276 XMLLogException err(el);
277 err << "FGTable: missing lookup axis \"row\"\n";
278 throw err;
279 }
280 break;
281 default:
282 assert(false); // Should never be called
283 break;
284 }
285 }
286
287 stringstream buf;
288
289 for (unsigned int i=0; i<tableData->GetNumDataLines(); i++) {
290 string line = tableData->GetDataLine(i);
291 if (line.find_first_not_of("0123456789.-+eE \t\n") != string::npos) {
292 XMLLogException err(tableData);
293 err << " Illegal character found in line "
294 << tableData->GetLineNumber() + i + 1 << ": \n" << line << "\n";
295 throw err;
296 }
297 buf << line << " ";
298 }
299
300 switch (dimension) {
301 case 1:
302 nRows = tableData->GetNumDataLines();
303 nCols = 1;
304 Type = tt1D;
305 // Fill unused elements with NaNs to detect illegal access.
306 Data.push_back(std::numeric_limits<double>::quiet_NaN());
307 Data.push_back(std::numeric_limits<double>::quiet_NaN());
308 *this << buf;
309 break;
310 case 2:
311 nRows = tableData->GetNumDataLines()-1;
312 nCols = FindNumColumns(tableData->GetDataLine(0));
313 Type = tt2D;
314 // Fill unused elements with NaNs to detect illegal access.
315 Data.push_back(std::numeric_limits<double>::quiet_NaN());
316 *this << buf;
317 break;
318 case 3:
319 nRows = el->GetNumElements("tableData");
320 nCols = 1;
321 Type = tt3D;
322 // Fill unused elements with NaNs to detect illegal access.
323 Data.push_back(std::numeric_limits<double>::quiet_NaN());
324
325 tableData = el->FindElement("tableData");
326 while (tableData) {
327 Tables.push_back(std::make_unique<FGTable>(PropertyManager, tableData));
328 Data.push_back(tableData->GetAttributeValueAsNumber("breakPoint"));
329 Tables.back()->lookupProperty[eRow] = lookupProperty[eRow];
330 Tables.back()->lookupProperty[eColumn] = lookupProperty[eColumn];
331 tableData = el->FindNextElement("tableData");
332 }
333
334 break;
335 default:
336 assert(false); // Should never be called
337 break;
338 }
339
340 Debug(0);
341
342 // Sanity checks: lookup indices must be increasing monotonically
343
344 // find next xml element containing a name attribute
345 // to indicate where the error occured
346 Element* nameel = el;
347 while (nameel && nameel->GetAttributeValue("name") == "")
348 nameel=nameel->GetParent();
349
350 // check breakpoints, if applicable
351 if (Type == tt3D) {
352 for (unsigned int b=2; b<=Tables.size(); ++b) {
353 if (Data[b] <= Data[b-1]) {
354 XMLLogException err(el);
355 err << LogFormat::RED << LogFormat::BOLD
356 << " FGTable: breakpoint lookup is not monotonically increasing\n"
357 << " in breakpoint " << b;
358 if (nameel) err << " of table in " << nameel->GetAttributeValue("name");
359 err << ":\n" << LogFormat::RESET
360 << " " << Data[b] << "<=" << Data[b-1] << "\n";
361 throw err;
362 }
363 }
364 }
365
366 // check columns, if applicable
367 if (Type == tt2D) {
368 for (unsigned int c=2; c<=nCols; ++c) {
369 if (Data[c] <= Data[c-1]) {
370 XMLLogException err(el);
371 err << LogFormat::RED << LogFormat::BOLD
372 << " FGTable: column lookup is not monotonically increasing\n"
373 << " in column " << c;
374 if (nameel != 0) err << " of table in " << nameel->GetAttributeValue("name");
375 err << ":\n" << LogFormat::RESET
376 << " " << Data[c] << "<=" << Data[c-1] << "\n";
377 throw err;
378 }
379 }
380 }
381
382 // check rows
383 if (Type != tt3D) { // in 3D tables, check only rows of subtables
384 for (size_t r=2; r<=nRows; ++r) {
385 if (Data[r*(nCols+1)]<=Data[(r-1)*(nCols+1)]) {
386 XMLLogException err(el);
387 err << LogFormat::RED << LogFormat::BOLD
388 << " FGTable: row lookup is not monotonically increasing\n"
389 << " in row " << r;
390 if (nameel != 0) err << " of table in " << nameel->GetAttributeValue("name");
391 err << ":\n" << LogFormat::RESET
392 << " " << Data[r*(nCols+1)] << "<=" << Data[(r-1)*(nCols+1)] << "\n";
393 throw err;
394 }
395 }
396 }
397
398 // Check the table has been entirely populated.
399 switch (Type) {
400 case tt1D:
401 if (Data.size() != 2*nRows+2) missingData(el, 2*nRows, Data.size()-2);
402 break;
403 case tt2D:
404 if (Data.size() != static_cast<size_t>(nRows+1)*(nCols+1))
405 missingData(el, (nRows+1)*(nCols+1)-1, Data.size()-1);
406 break;
407 case tt3D:
408 if (Data.size() != nRows+1) missingData(el, nRows, Data.size()-1);
409 break;
410 default:
411 assert(false); // Should never be called
412 break;
413 }
414
415 bind(el, Prefix);
416
417 if (debug_lvl & 1) Print();
418}
+ Here is the call graph for this function:

◆ FGTable() [3/4]

FGTable ( int  NRows)

Definition at line 54 of file FGTable.cpp.

55 : nRows(NRows), nCols(1)
56{
57 Type = tt1D;
58 // Fill unused elements with NaNs to detect illegal access.
59 Data.push_back(std::numeric_limits<double>::quiet_NaN());
60 Data.push_back(std::numeric_limits<double>::quiet_NaN());
61 Debug(0);
62}

◆ FGTable() [4/4]

FGTable ( int  NRows,
int  NCols 
)

Definition at line 66 of file FGTable.cpp.

67 : nRows(NRows), nCols(NCols)
68{
69 Type = tt2D;
70 // Fill unused elements with NaNs to detect illegal access.
71 Data.push_back(std::numeric_limits<double>::quiet_NaN());
72 Debug(0);
73}

Member Function Documentation

◆ GetElement()

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

Definition at line 452 of file FGTable.cpp.

453{
454 assert(r <= nRows && c <= nCols);
455 if (Type == tt3D) {
456 assert(Data.size() == nRows+1);
457 return Data[r];
458 }
459 assert(Data.size() == (nCols+1)*(nRows+1));
460 return Data[r*(nCols+1)+c];
461}

◆ GetMinValue()

double GetMinValue ( void  ) const

Definition at line 582 of file FGTable.cpp.

583{
584 assert(Type == tt1D);
585 assert(Data.size() == 2*nRows+2);
586
587 double minValue = HUGE_VAL;
588
589 for(unsigned int i=1; i<=nRows; ++i)
590 minValue = std::min(minValue, Data[2*i+1]);
591
592 return minValue;
593}

◆ GetName()

std::string GetName ( void  ) const
inlinevirtual

Implements FGParameter.

Definition at line 314 of file FGTable.h.

314{return Name;}

◆ GetNumRows()

unsigned int GetNumRows ( ) const
inline

Definition at line 310 of file FGTable.h.

310{return nRows;}

◆ GetValue() [1/4]

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

494{
495 assert(nCols == 1);
496 assert(Data.size() == 2*nRows+2);
497 // If the key is off the end (or before the beginning) of the table, just
498 // return the boundary-table value, do not extrapolate.
499 if (key <= Data[2])
500 return Data[3];
501 else if (key >= Data[2*nRows])
502 return Data[2*nRows+1];
503
504 // Search for the right breakpoint.
505 // This is a linear search, the algorithm is O(n).
506 unsigned int r = 2;
507 while (Data[2*r] < key) r++;
508
509 double x0 = Data[2*r-2];
510 double Span = Data[2*r] - x0;
511 assert(Span > 0.0);
512 double Factor = (key - x0) / Span;
513 assert(Factor >= 0.0 && Factor <= 1.0);
514
515 double y0 = Data[2*r-1];
516 return Factor*(Data[2*r+1] - y0) + y0;
517}

◆ GetValue() [2/4]

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

522{
523 if (nCols == 1) return GetValue(rowKey);
524
525 assert(Type == tt2D);
526 assert(Data.size() == (nCols+1)*(nRows+1));
527
528 unsigned int c = 2;
529 while(Data[c] < colKey && c < nCols) c++;
530 double x0 = Data[c-1];
531 double Span = Data[c] - x0;
532 assert(Span > 0.0);
533 double cFactor = Constrain(0.0, (colKey - x0) / Span, 1.0);
534
535 if (nRows == 1) {
536 double y0 = Data[(nCols+1)+c-1];
537 return cFactor*(Data[(nCols+1)+c] - y0) + y0;
538 }
539
540 size_t r = 2;
541 while(Data[r*(nCols+1)] < rowKey && r < nRows) r++;
542 x0 = Data[(r-1)*(nCols+1)];
543 Span = Data[r*(nCols+1)] - x0;
544 assert(Span > 0.0);
545 double rFactor = Constrain(0.0, (rowKey - x0) / Span, 1.0);
546 double col1temp = rFactor*Data[r*(nCols+1)+c-1]+(1.0-rFactor)*Data[(r-1)*(nCols+1)+c-1];
547 double col2temp = rFactor*Data[r*(nCols+1)+c]+(1.0-rFactor)*Data[(r-1)*(nCols+1)+c];
548
549 return cFactor*(col2temp-col1temp)+col1temp;
550}
static constexpr double Constrain(double min, double value, double max)
Constrain a value between a minimum and a maximum value.
Definition FGJSBBase.h:289
double GetValue(void) const
Get the current table value.
Definition FGTable.cpp:465
+ Here is the call graph for this function:

◆ GetValue() [3/4]

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

555{
556 assert(Type == tt3D);
557 assert(Data.size() == nRows+1);
558 // If the key is off the end (or before the beginning) of the table, just
559 // return the boundary-table value, do not extrapolate.
560 if(tableKey <= Data[1])
561 return Tables[0]->GetValue(rowKey, colKey);
562 else if (tableKey >= Data[nRows])
563 return Tables[nRows-1]->GetValue(rowKey, colKey);
564
565 // Search for the right breakpoint.
566 // This is a linear search, the algorithm is O(n).
567 unsigned int r = 2;
568 while (Data[r] < tableKey) r++;
569
570 double x0 = Data[r-1];
571 double Span = Data[r] - x0;
572 assert(Span > 0.0);
573 double Factor = (tableKey - x0) / Span;
574 assert(Factor >= 0.0 && Factor <= 1.0);
575
576 double y0 = Tables[r-2]->GetValue(rowKey, colKey);
577 return Factor*(Tables[r-1]->GetValue(rowKey, colKey) - y0) + y0;
578}

◆ GetValue() [4/4]

double GetValue ( void  ) const
virtual

Get the current table value.

Implements FGParameter.

Definition at line 465 of file FGTable.cpp.

466{
467 assert(!internal);
468
469 switch (Type) {
470 case tt1D:
471 assert(lookupProperty[eRow]);
472 return GetValue(lookupProperty[eRow]->getDoubleValue());
473 case tt2D:
474 assert(lookupProperty[eRow]);
475 assert(lookupProperty[eColumn]);
476 return GetValue(lookupProperty[eRow]->getDoubleValue(),
477 lookupProperty[eColumn]->getDoubleValue());
478 case tt3D:
479 assert(lookupProperty[eRow]);
480 assert(lookupProperty[eColumn]);
481 assert(lookupProperty[eTable]);
482 return GetValue(lookupProperty[eRow]->getDoubleValue(),
483 lookupProperty[eColumn]->getDoubleValue(),
484 lookupProperty[eTable]->getDoubleValue());
485 default:
486 assert(false); // Should never be called
487 return std::numeric_limits<double>::quiet_NaN();
488 }
489}
+ 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 302 of file FGTable.h.

303 { return GetElement(r, c); }

◆ operator<<() [1/2]

FGTable & operator<< ( const double  x)

Definition at line 611 of file FGTable.cpp.

612{
613 assert(Type != tt3D);
614 Data.push_back(x);
615
616 // Check column is monotically increasing
617 size_t n = Data.size();
618 if (Type == tt2D && nCols > 1 && n >= 3 && n <= nCols+1) {
619 if (Data.at(n-1) <= Data.at(n-2))
620 throw BaseException("FGTable: column lookup is not monotonically increasing");
621 }
622
623 // Check row is monotically increasing
624 size_t row = (n-1) / (nCols+1);
625 if (row >=2 && row*(nCols+1) == n-1) {
626 if (Data.at(row*(nCols+1)) <= Data.at((row-1)*(nCols+1)))
627 throw BaseException("FGTable: row lookup is not monotonically increasing");
628 }
629
630 return *this;
631}

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

598{
599 double x;
600 assert(Type != tt3D);
601
602 in_stream >> x;
603 while(in_stream) {
604 Data.push_back(x);
605 in_stream >> x;
606 }
607}

◆ Print()

void Print ( void  )

Definition at line 635 of file FGTable.cpp.

636{
637 FGLogging out(LogLevel::STDOUT);
638 out << std::setprecision(4);
639
640 switch(Type) {
641 case tt1D:
642 out << " 1 dimensional table with " << nRows << " rows.\n";
643 break;
644 case tt2D:
645 out << " 2 dimensional table with " << nRows << " rows, " << nCols << " columns.\n";
646 break;
647 case tt3D:
648 out << " 3 dimensional table with " << nRows << " breakpoints, "
649 << Tables.size() << " tables.\n";
650 break;
651 }
652 unsigned int startCol=1, startRow=1;
653 unsigned int p = 1;
654
655 if (Type == tt1D) {
656 startCol = 0;
657 p = 2;
658 }
659 if (Type == tt2D) startRow = 0;
660
661 for (unsigned int r=startRow; r<=nRows; r++) {
662 out << "\t";
663 if (Type == tt2D) {
664 if (r == startRow)
665 out << "\t";
666 else
667 startCol = 0;
668 }
669
670 for (unsigned int c=startCol; c<=nCols; c++) {
671 out << Data[p++] << "\t";
672 if (Type == tt3D) {
673 out << "\n";
674 Tables[r-1]->Print();
675 }
676 }
677 out << "\n";
678 }
679 out << std::fixed;
680}

◆ SetColumnIndexProperty()

void SetColumnIndexProperty ( SGPropertyNode node)
inline

Definition at line 307 of file FGTable.h.

308 { lookupProperty[eColumn] = new FGPropertyValue(node); }

◆ SetRowIndexProperty()

void SetRowIndexProperty ( SGPropertyNode node)
inline

Definition at line 305 of file FGTable.h.

306 { lookupProperty[eRow] = new FGPropertyValue(node); }

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