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
FGExternalForce.cpp
1/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3 Source: FGExternalForce.cpp
4 Author: Jon Berndt, Dave Culp
5 Date started: 9/21/07
6
7 ------------- Copyright (C) 2007 Jon S. Berndt (jon@jsbsim.org) -------------
8
9 This program is free software; you can redistribute it and/or modify it under
10 the terms of the GNU Lesser General Public License as published by the Free
11 Software Foundation; either version 2 of the License, or (at your option) any
12 later version.
13
14 This program is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17 details.
18
19 You should have received a copy of the GNU Lesser General Public License along
20 with this program; if not, write to the Free Software Foundation, Inc., 59
21 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23 Further information about the GNU Lesser General Public License can also be
24 found on the world wide web at http://www.gnu.org.
25
26 HISTORY
27--------------------------------------------------------------------------------
289/21/07 JB Created
29
30<external_reactions>
31
32 <!-- Interface properties, a.k.a. property declarations -->
33 <property> ... </property>
34
35 <force name="name" frame="BODY|LOCAL|WIND">
36
37 <function> ... </function>
38
39 <location unit="units"> <!-- location -->
40 <x> value </x>
41 <y> value </y>
42 <z> value </z>
43 </location>
44 <direction> <!-- optional for initial direction vector -->
45 <x> value </x>
46 <y> value </y>
47 <z> value </z>
48 </direction>
49 </force>
50
51 <moment name="name" frame="BODY|LOCAL|WIND">
52
53 <function> ... </function>
54
55 <direction> <!-- optional for initial direction vector -->
56 <x> value </x>
57 <y> value </y>
58 <z> value </z>
59 </direction>
60 </force>
61
62</external_reactions>
63
64*/
65
66#include "FGFDMExec.h"
67#include "FGExternalForce.h"
68#include "input_output/FGXMLElement.h"
69#include "input_output/FGLog.h"
70
71using namespace std;
72
73namespace JSBSim {
74
75//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76
77FGPropertyVector3::FGPropertyVector3(FGPropertyManager* pm,
78 const std::string& baseName,
79 const std::string& xcmp,
80 const std::string& ycmp,
81 const std::string& zcmp)
82{
83 data[0] = pm->GetNode(baseName + "/" + xcmp, true);
84 data[1] = pm->GetNode(baseName + "/" + ycmp, true);
85 data[2] = pm->GetNode(baseName + "/" + zcmp, true);
86}
87
88//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89
90FGParameter* FGExternalForce::bind(Element *el, const string& magName,
91 FGPropertyVector3& v)
92{
93 // Set frame (from FGForce).
94 string sFrame = el->GetAttributeValue("frame");
95 if (sFrame.empty()) {
96 FGXMLLogging log(el, LogLevel::WARN);
97 log << "No frame specified for external " << el->GetName() << ", \""
98 << Name << "\".\nFrame set to Body\n";
99 ttype = tNone;
100 } else if (sFrame == "BODY") {
101 ttype = tNone;
102 } else if (sFrame == "LOCAL") {
103 ttype = tLocalBody;
104 } else if (sFrame == "WIND") {
105 ttype = tWindBody;
106 } else if (sFrame == "INERTIAL") {
107 ttype = tInertialBody;
108 } else {
109 FGXMLLogging log(el, LogLevel::WARN);
110 log << "Invalid frame specified for external " << el->GetName() << ", \""
111 << Name << "\".\nFrame set to Body\n";
112 ttype = tNone;
113 }
114
115 Element* direction_element = el->FindElement("direction");
116 if (!direction_element) {
117 FGXMLLogging log(el, LogLevel::WARN);
118 log << "No direction element specified in " << el->GetName()
119 << " object. Default is (0,0,0).\n";
120 } else {
121 FGColumnVector3 direction = direction_element->FindElementTripletConvertTo("IN");
122 direction.Normalize();
123 v = direction;
124 }
125
126 // The value sent to the sim through the external_reactions/{force
127 // name}/magnitude property will be multiplied against the unit vector, which
128 // can come in initially in the direction vector. The frame in which the
129 // vector is defined is specified with the frame attribute. The vector is
130 // normalized to magnitude 1.
131
132 Element* function_element = el->FindElement("function");
133 if (function_element) {
134 return new FGFunction(fdmex, function_element);
135 } else {
136 auto pm = fdmex->GetPropertyManager();
137 SGPropertyNode* node = pm->GetNode(magName, true);
138 return new FGPropertyValue(node);
139 }
140}
141
142//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143
144void FGExternalForce::setForce(Element *el)
145{
146 auto PropertyManager = fdmex->GetPropertyManager();
147 Name = el->GetAttributeValue("name");
148 string BasePropertyName = "external_reactions/" + Name;
149
150 forceDirection = FGPropertyVector3(PropertyManager.get(), BasePropertyName,
151 "x", "y", "z");
152 forceMagnitude = bind(el, BasePropertyName + "/magnitude", forceDirection);
153
154 Element* location_element = el->FindElement("location");
155 if (!location_element) {
156 FGXMLLogging log(el, LogLevel::WARN);
157 log << "No location element specified in force object.\n";
158 } else {
159 FGColumnVector3 location = location_element->FindElementTripletConvertTo("IN");
160 SetLocation(location);
161 }
162 PropertyManager->Tie( BasePropertyName + "/location-x-in", (FGForce*)this,
163 &FGForce::GetLocationX, &FGForce::SetLocationX);
164 PropertyManager->Tie( BasePropertyName + "/location-y-in", (FGForce*)this,
165 &FGForce::GetLocationY, &FGForce::SetLocationY);
166 PropertyManager->Tie( BasePropertyName + "/location-z-in", (FGForce*)this,
167 &FGForce::GetLocationZ, &FGForce::SetLocationZ);
168}
169
170//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
171
172void FGExternalForce::setMoment(Element *el)
173{
174 auto PropertyManager = fdmex->GetPropertyManager();
175 Name = el->GetAttributeValue("name");
176 string BasePropertyName = "external_reactions/" + Name;
177
178 momentDirection = FGPropertyVector3(PropertyManager.get(), BasePropertyName,
179 "l", "m", "n");
180 momentMagnitude = bind(el, BasePropertyName + "/magnitude-lbsft",
181 momentDirection);
182}
183
184//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
185
187{
188 delete forceMagnitude;
189 delete momentMagnitude;
190 Debug(1);
191}
192
193//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194
195const FGColumnVector3& FGExternalForce::GetBodyForces(void)
196{
197 if (forceMagnitude)
198 vFn = forceMagnitude->GetValue() * forceDirection;
199
200 if (momentMagnitude)
201 vMn = Transform() * (momentMagnitude->GetValue() * momentDirection);
202
203 return FGForce::GetBodyForces();
204}
205
206//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
207// The bitmasked value choices are as follows:
208// unset: In this case (the default) JSBSim would only print
209// out the normally expected messages, essentially echoing
210// the config files as they are read. If the environment
211// variable is not set, debug_lvl is set to 1 internally
212// 0: This requests JSBSim not to output any messages
213// whatsoever.
214// 1: This value explicity requests the normal JSBSim
215// startup messages
216// 2: This value asks for a message to be printed out when
217// a class is instantiated
218// 4: When this value is set, a message is displayed when a
219// FGModel object executes its Run() method
220// 8: When this value is set, various runtime state variables
221// are printed out periodically
222// 16: When set various parameters are sanity checked and
223// a message is printed out when they go out of bounds
224
225void FGExternalForce::Debug(int from)
226{
227 if (debug_lvl <= 0) return;
228
229 if (debug_lvl & 1) { // Standard console startup message output
230 if (from == 0) { // Constructor
231 FGLogging log(LogLevel::DEBUG);
232 log << " " << Name;
233 log << "\n Frame: ";
234 switch(ttype) {
235 case tNone:
236 log << "BODY";
237 break;
238 case tLocalBody:
239 log << "LOCAL";
240 break;
241 case tWindBody:
242 log << "WIND";
243 break;
244 case tInertialBody:
245 log << "INERTIAL";
246 break;
247 default:
248 log << "ERROR/UNKNOWN";
249 }
250 log << "\n Location: (" << fixed << vXYZn(eX) << ", " << vXYZn(eY)
251 << ", " << vXYZn(eZ) << ")\n";
252 }
253 }
254 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
255 FGLogging log(LogLevel::DEBUG);
256 if (from == 0) log << "Instantiated: FGExternalForce\n";
257 if (from == 1) log << "Destroyed: FGExternalForce\n";
258 }
259 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
260 }
261 if (debug_lvl & 8 ) { // Runtime state variables
262 }
263 if (debug_lvl & 16) { // Sanity checking
264 }
265 if (debug_lvl & 64) {
266 if (from == 0) { // Constructor
267 }
268 }
269}
270}
This class implements a 3 element column vector.
~FGExternalForce() override
Destructor.
std::shared_ptr< FGPropertyManager > GetPropertyManager(void) const
Returns a pointer to the property manager object.
Definition FGFDMExec.h:422
A node in a property tree.
Definition props.hxx:747
Main namespace for the JSBSim Flight Dynamics Model.
Definition FGFDMExec.cpp:71