1 /*******************************************************************************
3 Header: FGInitialCondition.cpp
7 ------------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) -------------
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 Software
11 Foundation; either version 2 of the License, or (at your option) any later
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
19 You should have received a copy of the GNU Lesser General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21 Place - Suite 330, Boston, MA 02111-1307, USA.
23 Further information about the GNU Lesser General Public License can also be found on
24 the world wide web at http://www.gnu.org.
28 --------------------------------------------------------------------------------
32 FUNCTIONAL DESCRIPTION
33 --------------------------------------------------------------------------------
35 The purpose of this class is to take a set of initial conditions and provide
36 a kinematically consistent set of body axis velocity components, euler
37 angles, and altitude. This class does not attempt to trim the model i.e.
38 the sim will most likely start in a very dynamic state (unless, of course,
39 you have chosen your IC's wisely) even after setting it up with this class.
41 ********************************************************************************
43 *******************************************************************************/
45 #include "FGInitialCondition.h"
46 #include <FGFDMExec.h>
47 #include <models/FGInertial.h>
48 #include <models/FGAtmosphere.h>
49 #include <models/FGAerodynamics.h>
50 #include <models/FGPropagate.h>
51 #include <input_output/FGPropertyManager.h>
52 #include <models/FGPropulsion.h>
53 #include <input_output/FGXMLParse.h>
54 #include <math/FGQuaternion.h>
59 static const char *IdSrc = "$Id$";
60 static const char *IdHdr = ID_INITIALCONDITION;
62 //******************************************************************************
64 FGInitialCondition::FGInitialCondition(FGFDMExec *FDMExec) : fdmex(FDMExec)
68 if(FDMExec != NULL ) {
69 fdmex->GetPropagate()->Seth(altitude);
70 fdmex->GetAtmosphere()->Run();
71 PropertyManager=fdmex->GetPropertyManager();
76 cout << "FGInitialCondition: This class requires a pointer to a valid FGFDMExec object" << endl;
82 //******************************************************************************
84 FGInitialCondition::~FGInitialCondition()
89 //******************************************************************************
91 void FGInitialCondition::ResetIC(double u0, double v0, double w0,
92 double p0, double q0, double r0,
93 double alpha0, double beta0,
94 double phi0, double theta0, double psi0,
95 double latRad0, double lonRad0, double altAGLFt0,
100 u = u0; v = v0; w = w0;
101 p = p0; q = q0; r = r0;
102 alpha = alpha0; beta = beta0;
103 phi = phi0; theta = theta0; psi = psi0;
108 SetAltitudeAGLFtIC(altAGLFt0);
110 cphi = cos(phi); sphi = sin(phi); // phi, rad
111 ctheta = cos(theta); stheta = sin(theta); // theta, rad
112 cpsi = cos(psi); spsi = sin(psi); // psi, rad
114 FGQuaternion Quat( phi, theta, psi );
117 const FGMatrix33& _Tl2b = Quat.GetT(); // local to body frame
118 const FGMatrix33& _Tb2l = Quat.GetTInv(); // body to local
120 FGColumnVector3 _vUVW_BODY(u,v,w);
121 FGColumnVector3 _vUVW_NED = _Tb2l * _vUVW_BODY;
122 FGColumnVector3 _vWIND_NED(wnorth,weast,wdown);
123 FGColumnVector3 _vUVWAero = _Tl2b * ( _vUVW_NED + _vWIND_NED );
125 uw=_vWIND_NED(1); vw=_vWIND_NED(2); ww=_vWIND_NED(3);
129 //******************************************************************************
131 void FGInitialCondition::InitializeIC(void)
138 latitude=longitude=0;
142 vnorth=veast=vdown=0;
143 wnorth=weast=wdown=0;
148 radius_to_vehicle = sea_level_radius = fdmex->GetInertial()->GetRefRadius();
149 terrain_altitude = 0;
153 salpha=sbeta=stheta=sphi=spsi=sgamma=0;
154 calpha=cbeta=ctheta=cphi=cpsi=cgamma=1;
157 //******************************************************************************
159 void FGInitialCondition::WriteStateFile(int num)
161 if (Constructing) return;
163 string filename = fdmex->GetFullAircraftPath();
165 if (filename.empty())
166 filename = "initfile.xml";
168 filename.append("/initfile.xml");
170 ofstream outfile(filename.c_str());
171 FGPropagate* Propagate = fdmex->GetPropagate();
173 if (outfile.is_open()) {
174 outfile << "<?xml version=\"1.0\"?>" << endl;
175 outfile << "<initialize name=\"reset00\">" << endl;
176 outfile << " <ubody unit=\"FT/SEC\"> " << Propagate->GetUVW(eX) << " </ubody> " << endl;
177 outfile << " <vbody unit=\"FT/SEC\"> " << Propagate->GetUVW(eY) << " </vbody> " << endl;
178 outfile << " <wbody unit=\"FT/SEC\"> " << Propagate->GetUVW(eZ) << " </wbody> " << endl;
179 outfile << " <phi unit=\"DEG\"> " << Propagate->GetEuler(ePhi) << " </phi>" << endl;
180 outfile << " <theta unit=\"DEG\"> " << Propagate->GetEuler(eTht) << " </theta>" << endl;
181 outfile << " <psi unit=\"DEG\"> " << Propagate->GetEuler(ePsi) << " </psi>" << endl;
182 outfile << " <longitude unit=\"DEG\"> " << Propagate->GetLongitudeDeg() << " </longitude>" << endl;
183 outfile << " <latitude unit=\"DEG\"> " << Propagate->GetLatitudeDeg() << " </latitude>" << endl;
184 outfile << " <altitude unit=\"FT\"> " << Propagate->Geth() << " </altitude>" << endl;
185 outfile << "</initialize>" << endl;
188 cerr << "Could not open and/or write the state to the initial conditions file: " << filename << endl;
192 //******************************************************************************
194 void FGInitialCondition::SetVcalibratedKtsIC(double tt) {
196 if(getMachFromVcas(&mach,tt*ktstofps)) {
197 //cout << "Mach: " << mach << endl;
200 vt=mach*fdmex->GetAtmosphere()->GetSoundSpeed();
201 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
202 //cout << "Vt: " << vt*fpstokts << " Vc: " << vc*fpstokts << endl;
205 cout << "Failed to get Mach number for given Vc and altitude, Vc unchanged." << endl;
206 cout << "Please mail the set of initial conditions used to apeden@earthlink.net" << endl;
210 //******************************************************************************
212 void FGInitialCondition::SetVequivalentKtsIC(double tt) {
215 vt=ve*1/sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
216 mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
220 //******************************************************************************
222 void FGInitialCondition::SetVgroundFpsIC(double tt) {
228 vnorth = vg*cos(psi); veast = vg*sin(psi); vdown = 0;
230 ua = u + uw; va = v + vw; wa = w + ww;
231 vt = sqrt( ua*ua + va*va + wa*wa );
233 vxz = sqrt( u*u + w*w );
234 if( w != 0 ) alpha = atan2( w, u );
235 if( vxz != 0 ) beta = atan2( v, vxz );
236 mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
238 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
241 //******************************************************************************
243 void FGInitialCondition::SetVtrueFpsIC(double tt) {
246 mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
248 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
251 //******************************************************************************
253 void FGInitialCondition::SetMachIC(double tt) {
255 lastSpeedSet=setmach;
256 vt=mach*fdmex->GetAtmosphere()->GetSoundSpeed();
258 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
259 //cout << "Vt: " << vt*fpstokts << " Vc: " << vc*fpstokts << endl;
262 //******************************************************************************
264 void FGInitialCondition::SetClimbRateFpmIC(double tt) {
265 SetClimbRateFpsIC(tt/60.0);
268 //******************************************************************************
270 void FGInitialCondition::SetClimbRateFpsIC(double tt) {
275 sgamma=sin(gamma); cgamma=cos(gamma);
279 //******************************************************************************
281 void FGInitialCondition::SetFlightPathAngleRadIC(double tt) {
283 sgamma=sin(gamma); cgamma=cos(gamma);
288 //******************************************************************************
290 void FGInitialCondition::SetAlphaRadIC(double tt) {
292 salpha=sin(alpha); calpha=cos(alpha);
296 //******************************************************************************
298 void FGInitialCondition::SetThetaRadIC(double tt) {
300 stheta=sin(theta); ctheta=cos(theta);
304 //******************************************************************************
306 void FGInitialCondition::SetBetaRadIC(double tt) {
308 sbeta=sin(beta); cbeta=cos(beta);
313 //******************************************************************************
315 void FGInitialCondition::SetPhiRadIC(double tt) {
317 sphi=sin(phi); cphi=cos(phi);
321 //******************************************************************************
323 void FGInitialCondition::SetPsiRadIC(double tt) {
325 spsi=sin(psi); cpsi=cos(psi);
329 //******************************************************************************
331 void FGInitialCondition::SetUBodyFpsIC(double tt) {
333 vt=sqrt(u*u + v*v + w*w);
337 //******************************************************************************
339 void FGInitialCondition::SetVBodyFpsIC(double tt) {
341 vt=sqrt(u*u + v*v + w*w);
345 //******************************************************************************
347 void FGInitialCondition::SetWBodyFpsIC(double tt) {
349 vt=sqrt( u*u + v*v + w*w );
354 //******************************************************************************
356 void FGInitialCondition::SetVNorthFpsIC(double tt) {
361 ua = u + uw; va = v + vw; wa = w + ww;
362 vt = sqrt( ua*ua + va*va + wa*wa );
364 vxz = sqrt( u*u + w*w );
365 if( w != 0 ) alpha = atan2( w, u );
366 if( vxz != 0 ) beta = atan2( v, vxz );
367 mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
369 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
373 //******************************************************************************
375 void FGInitialCondition::SetVEastFpsIC(double tt) {
380 ua = u + uw; va = v + vw; wa = w + ww;
381 vt = sqrt( ua*ua + va*va + wa*wa );
383 vxz = sqrt( u*u + w*w );
384 if( w != 0 ) alpha = atan2( w, u );
385 if( vxz != 0 ) beta = atan2( v, vxz );
386 mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
388 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
392 //******************************************************************************
394 void FGInitialCondition::SetVDownFpsIC(double tt) {
399 ua = u + uw; va = v + vw; wa = w + ww;
400 vt = sqrt( ua*ua + va*va + wa*wa );
402 vxz = sqrt( u*u + w*w );
403 if( w != 0 ) alpha = atan2( w, u );
404 if( vxz != 0 ) beta = atan2( v, vxz );
405 mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
407 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
408 SetClimbRateFpsIC(-1*vdown);
412 //******************************************************************************
414 double FGInitialCondition::GetUBodyFpsIC(void) const {
415 if (lastSpeedSet == setvg || lastSpeedSet == setned)
418 return vt*calpha*cbeta - uw;
421 //******************************************************************************
423 double FGInitialCondition::GetVBodyFpsIC(void) const {
424 if (lastSpeedSet == setvg || lastSpeedSet == setned)
427 return vt*sbeta - vw;
431 //******************************************************************************
433 double FGInitialCondition::GetWBodyFpsIC(void) const {
434 if (lastSpeedSet == setvg || lastSpeedSet == setned)
437 return vt*salpha*cbeta -ww;
440 //******************************************************************************
442 void FGInitialCondition::SetWindNEDFpsIC(double wN, double wE, double wD ) {
443 wnorth = wN; weast = wE; wdown = wD;
444 lastWindSet = setwned;
446 if(lastSpeedSet == setvg)
450 //******************************************************************************
452 void FGInitialCondition::SetCrossWindKtsIC(double cross){
453 wcross=cross*ktstofps;
456 if(lastSpeedSet == setvg)
461 //******************************************************************************
463 // positive from left
464 void FGInitialCondition::SetHeadWindKtsIC(double head){
468 if(lastSpeedSet == setvg)
473 //******************************************************************************
475 void FGInitialCondition::SetWindDownKtsIC(double wD) {
478 if(lastSpeedSet == setvg)
482 //******************************************************************************
484 void FGInitialCondition::SetWindMagKtsIC(double mag) {
488 if(lastSpeedSet == setvg)
492 //******************************************************************************
494 void FGInitialCondition::SetWindDirDegIC(double dir) {
498 if(lastSpeedSet == setvg)
503 //******************************************************************************
505 void FGInitialCondition::calcWindUVW(void) {
507 switch(lastWindSet) {
509 wnorth=wmag*cos(wdir);
510 weast=wmag*sin(wdir);
513 wnorth=whead*cos(psi) + wcross*cos(psi+M_PI/2);
514 weast=whead*sin(psi) + wcross*sin(psi+M_PI/2);
519 uw=wnorth*ctheta*cpsi +
522 vw=wnorth*( sphi*stheta*cpsi - cphi*spsi ) +
523 weast*( sphi*stheta*spsi + cphi*cpsi ) +
525 ww=wnorth*(cphi*stheta*cpsi + sphi*spsi) +
526 weast*(cphi*stheta*spsi - sphi*cpsi) +
530 /* cout << "FGInitialCondition::calcWindUVW: wnorth, weast, wdown "
531 << wnorth << ", " << weast << ", " << wdown << endl;
532 cout << "FGInitialCondition::calcWindUVW: theta, phi, psi "
533 << theta << ", " << phi << ", " << psi << endl;
534 cout << "FGInitialCondition::calcWindUVW: uw, vw, ww "
535 << uw << ", " << vw << ", " << ww << endl; */
539 //******************************************************************************
541 void FGInitialCondition::SetAltitudeFtIC(double tt) {
543 fdmex->GetPropagate()->Seth(altitude);
544 fdmex->GetAtmosphere()->Run();
545 //lets try to make sure the user gets what they intended
547 switch(lastSpeedSet) {
551 SetVtrueKtsIC(vt*fpstokts);
554 SetVcalibratedKtsIC(vc*fpstokts);
557 SetVequivalentKtsIC(ve*fpstokts);
568 //******************************************************************************
570 void FGInitialCondition::SetAltitudeAGLFtIC(double tt) {
571 SetAltitudeFtIC(terrain_altitude + tt);
574 //******************************************************************************
576 void FGInitialCondition::SetSeaLevelRadiusFtIC(double tt) {
577 sea_level_radius = tt;
580 //******************************************************************************
582 void FGInitialCondition::SetTerrainAltitudeFtIC(double tt) {
586 //******************************************************************************
588 void FGInitialCondition::calcUVWfromNED(void) {
589 u=vnorth*ctheta*cpsi +
592 v=vnorth*( sphi*stheta*cpsi - cphi*spsi ) +
593 veast*( sphi*stheta*spsi + cphi*cpsi ) +
595 w=vnorth*( cphi*stheta*cpsi + sphi*spsi ) +
596 veast*( cphi*stheta*spsi - sphi*cpsi ) +
600 //******************************************************************************
602 bool FGInitialCondition::getMachFromVcas(double *Mach,double vcas) {
608 sfunc=&FGInitialCondition::calcVcas;
609 if(findInterval(vcas,guess)) {
610 if(solve(&mach,vcas))
616 //******************************************************************************
618 bool FGInitialCondition::getAlpha(void) {
620 double guess=theta-gamma;
622 if(vt < 0.01) return 0;
625 xmin=fdmex->GetAerodynamics()->GetAlphaCLMin();
626 xmax=fdmex->GetAerodynamics()->GetAlphaCLMax();
627 sfunc=&FGInitialCondition::GammaEqOfAlpha;
628 if(findInterval(0,guess)){
639 //******************************************************************************
641 bool FGInitialCondition::getTheta(void) {
643 double guess=alpha+gamma;
645 if(vt < 0.01) return 0;
649 sfunc=&FGInitialCondition::GammaEqOfTheta;
650 if(findInterval(0,guess)){
661 //******************************************************************************
663 double FGInitialCondition::GammaEqOfTheta(double Theta) {
665 double sTheta,cTheta;
667 //theta=Theta; stheta=sin(theta); ctheta=cos(theta);
668 sTheta=sin(Theta); cTheta=cos(Theta);
670 a=wdown + vt*calpha*cbeta + uw;
671 b=vt*sphi*sbeta + vw*sphi;
672 c=vt*cphi*salpha*cbeta + ww*cphi;
673 return vt*sgamma - ( a*sTheta - (b+c)*cTheta);
676 //******************************************************************************
678 double FGInitialCondition::GammaEqOfAlpha(double Alpha) {
680 double sAlpha,cAlpha;
681 sAlpha=sin(Alpha); cAlpha=cos(Alpha);
682 a=wdown + vt*cAlpha*cbeta + uw;
683 b=vt*sphi*sbeta + vw*sphi;
684 c=vt*cphi*sAlpha*cbeta + ww*cphi;
686 return vt*sgamma - ( a*stheta - (b+c)*ctheta );
689 //******************************************************************************
691 double FGInitialCondition::calcVcas(double Mach) {
693 double p=fdmex->GetAtmosphere()->GetPressure();
694 double psl=fdmex->GetAtmosphere()->GetPressureSL();
695 double rhosl=fdmex->GetAtmosphere()->GetDensitySL();
696 double pt,A,B,D,vcas;
698 if(Mach < 1) //calculate total pressure assuming isentropic flow
699 pt=p*pow((1 + 0.2*Mach*Mach),3.5);
701 // shock in front of pitot tube, we'll assume its normal and use
702 // the Rayleigh Pitot Tube Formula, i.e. the ratio of total
703 // pressure behind the shock to the static pressure in front
706 //the normal shock assumption should not be a bad one -- most supersonic
707 //aircraft place the pitot probe out front so that it is the forward
708 //most point on the aircraft. The real shock would, of course, take
709 //on something like the shape of a rounded-off cone but, here again,
710 //the assumption should be good since the opening of the pitot probe
711 //is very small and, therefore, the effects of the shock curvature
712 //should be small as well. AFAIK, this approach is fairly well accepted
713 //within the aerospace community
715 B = 5.76*Mach*Mach/(5.6*Mach*Mach - 0.8);
717 // The denominator above is zero for Mach ~ 0.38, for which
718 // we'll never be here, so we're safe
720 D = (2.8*Mach*Mach-0.4)*0.4167;
724 A = pow(((pt-p)/psl+1),0.28571);
725 vcas = sqrt(7*psl/rhosl*(A-1));
726 //cout << "calcVcas: vcas= " << vcas*fpstokts << " mach= " << Mach << " pressure: " << pt << endl;
730 //******************************************************************************
732 bool FGInitialCondition::findInterval(double x,double guess) {
733 //void find_interval(inter_params &ip,eqfunc f,double y,double constant, int &flag){
737 double flo,fhi,fguess;
740 fguess=(this->*sfunc)(guess)-x;
746 if(lo < xmin) lo=xmin;
747 if(hi > xmax) hi=xmax;
749 flo=(this->*sfunc)(lo)-x;
750 fhi=(this->*sfunc)(hi)-x;
751 if(flo*fhi <=0) { //found interval with root
753 if(flo*fguess <= 0) { //narrow interval down a bit
754 hi=lo+step; //to pass solver interval that is as
757 else if(fhi*fguess <= 0) {
761 //cout << "findInterval: i=" << i << " Lo= " << lo << " Hi= " << hi << endl;
763 while((found == 0) && (i <= 100));
769 //******************************************************************************
771 bool FGInitialCondition::solve(double *y,double x)
773 double x1,x2,x3,f1,f2,f3,d,d0;
775 double const relax =0.9;
783 f1=(this->*sfunc)(x1)-x;
784 f3=(this->*sfunc)(x3)-x;
789 while ((fabs(d) > eps) && (i < 100)) {
791 x2 = x1-d*d0*f1/(f3-f1);
793 f2=(this->*sfunc)(x2)-x;
794 //cout << "solve x1,x2,x3: " << x1 << "," << x2 << "," << x3 << endl;
795 //cout << " " << f1 << "," << f2 << "," << f3 << endl;
797 if(fabs(f2) <= 0.001) {
799 } else if(f1*f2 <= 0.0) {
803 } else if(f2*f3 <= 0) {
816 //cout << "Success= " << success << " Vcas: " << vcas*fpstokts << " Mach: " << x2 << endl;
820 //******************************************************************************
822 double FGInitialCondition::GetWindDirDegIC(void) const {
824 return atan2(weast,wnorth)*radtodeg;
831 //******************************************************************************
833 bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
838 if( useStoredPath ) {
839 init_file_name = fdmex->GetFullAircraftPath() + sep + rstfile + ".xml";
841 init_file_name = rstfile;
844 document = LoadXMLDocument(init_file_name);
846 // Make sure that the document is valid
848 cerr << "File: " << init_file_name << " could not be read." << endl;
852 if (document->GetName() != string("initialize")) {
853 cerr << "File: " << init_file_name << " is not a reset file." << endl;
857 if (document->FindElement("latitude"))
858 SetLatitudeDegIC(document->FindElementValueAsNumberConvertTo("latitude", "DEG"));
859 if (document->FindElement("longitude"))
860 SetLongitudeDegIC(document->FindElementValueAsNumberConvertTo("longitude", "DEG"));
861 if (document->FindElement("altitude"))
862 SetAltitudeFtIC(document->FindElementValueAsNumberConvertTo("altitude", "FT"));
863 if (document->FindElement("ubody"))
864 SetUBodyFpsIC(document->FindElementValueAsNumberConvertTo("ubody", "FT/SEC"));
865 if (document->FindElement("vbody"))
866 SetVBodyFpsIC(document->FindElementValueAsNumberConvertTo("vbody", "FT/SEC"));
867 if (document->FindElement("wbody"))
868 SetWBodyFpsIC(document->FindElementValueAsNumberConvertTo("wbody", "FT/SEC"));
869 if (document->FindElement("vnorth"))
870 SetVNorthFpsIC(document->FindElementValueAsNumberConvertTo("vnorth", "FT/SEC"));
871 if (document->FindElement("veast"))
872 SetVEastFpsIC(document->FindElementValueAsNumberConvertTo("veast", "FT/SEC"));
873 if (document->FindElement("vdown"))
874 SetVDownFpsIC(document->FindElementValueAsNumberConvertTo("vdown", "FT/SEC"));
875 if (document->FindElement("winddir"))
876 SetWindDirDegIC(document->FindElementValueAsNumberConvertTo("winddir", "DEG"));
877 if (document->FindElement("vwind"))
878 SetWindMagKtsIC(document->FindElementValueAsNumberConvertTo("vwind", "KTS"));
879 if (document->FindElement("hwind"))
880 SetHeadWindKtsIC(document->FindElementValueAsNumberConvertTo("hwind", "KTS"));
881 if (document->FindElement("xwind"))
882 SetCrossWindKtsIC(document->FindElementValueAsNumberConvertTo("xwind", "KTS"));
883 if (document->FindElement("vc"))
884 SetVcalibratedKtsIC(document->FindElementValueAsNumberConvertTo("vc", "KTS"));
885 if (document->FindElement("vt"))
886 SetVtrueKtsIC(document->FindElementValueAsNumberConvertTo("vt", "KTS"));
887 if (document->FindElement("mach"))
888 SetMachIC(document->FindElementValueAsNumber("mach"));
889 if (document->FindElement("phi"))
890 SetPhiDegIC(document->FindElementValueAsNumberConvertTo("phi", "DEG"));
891 if (document->FindElement("theta"))
892 SetThetaDegIC(document->FindElementValueAsNumberConvertTo("theta", "DEG"));
893 if (document->FindElement("psi"))
894 SetPsiDegIC(document->FindElementValueAsNumberConvertTo("psi", "DEG"));
895 if (document->FindElement("alpha"))
896 SetAlphaDegIC(document->FindElementValueAsNumberConvertTo("alpha", "DEG"));
897 if (document->FindElement("beta"))
898 SetBetaDegIC(document->FindElementValueAsNumberConvertTo("beta", "DEG"));
899 if (document->FindElement("gamma"))
900 SetFlightPathAngleDegIC(document->FindElementValueAsNumberConvertTo("gamma", "DEG"));
901 if (document->FindElement("roc"))
902 SetClimbRateFpsIC(document->FindElementValueAsNumberConvertTo("roc", "FT/SEC"));
903 if (document->FindElement("vground"))
904 SetVgroundKtsIC(document->FindElementValueAsNumberConvertTo("vground", "KTS"));
905 if (document->FindElement("targetNlf"))
907 SetTargetNlfIC(document->FindElementValueAsNumber("targetNlf"));
910 // Check to see if any engines are specified to be initialized in a running state
911 FGPropulsion* propulsion = fdmex->GetPropulsion();
912 Element* running_elements = document->FindElement("running");
913 while (running_elements) {
914 n = int(running_elements->GetDataAsNumber());
915 propulsion->InitRunning(n);
916 running_elements = document->FindNextElement("running");
924 //******************************************************************************
926 void FGInitialCondition::bind(void){
927 PropertyManager->Tie("ic/vc-kts", this,
928 &FGInitialCondition::GetVcalibratedKtsIC,
929 &FGInitialCondition::SetVcalibratedKtsIC,
931 PropertyManager->Tie("ic/ve-kts", this,
932 &FGInitialCondition::GetVequivalentKtsIC,
933 &FGInitialCondition::SetVequivalentKtsIC,
935 PropertyManager->Tie("ic/vg-kts", this,
936 &FGInitialCondition::GetVgroundKtsIC,
937 &FGInitialCondition::SetVgroundKtsIC,
939 PropertyManager->Tie("ic/vt-kts", this,
940 &FGInitialCondition::GetVtrueKtsIC,
941 &FGInitialCondition::SetVtrueKtsIC,
943 PropertyManager->Tie("ic/mach", this,
944 &FGInitialCondition::GetMachIC,
945 &FGInitialCondition::SetMachIC,
947 PropertyManager->Tie("ic/roc-fpm", this,
948 &FGInitialCondition::GetClimbRateFpmIC,
949 &FGInitialCondition::SetClimbRateFpmIC,
951 PropertyManager->Tie("ic/gamma-deg", this,
952 &FGInitialCondition::GetFlightPathAngleDegIC,
953 &FGInitialCondition::SetFlightPathAngleDegIC,
955 PropertyManager->Tie("ic/alpha-deg", this,
956 &FGInitialCondition::GetAlphaDegIC,
957 &FGInitialCondition::SetAlphaDegIC,
959 PropertyManager->Tie("ic/beta-deg", this,
960 &FGInitialCondition::GetBetaDegIC,
961 &FGInitialCondition::SetBetaDegIC,
963 PropertyManager->Tie("ic/theta-deg", this,
964 &FGInitialCondition::GetThetaDegIC,
965 &FGInitialCondition::SetThetaDegIC,
967 PropertyManager->Tie("ic/phi-deg", this,
968 &FGInitialCondition::GetPhiDegIC,
969 &FGInitialCondition::SetPhiDegIC,
971 PropertyManager->Tie("ic/psi-true-deg", this,
972 &FGInitialCondition::GetPsiDegIC );
973 PropertyManager->Tie("ic/lat-gc-deg", this,
974 &FGInitialCondition::GetLatitudeDegIC,
975 &FGInitialCondition::SetLatitudeDegIC,
977 PropertyManager->Tie("ic/long-gc-deg", this,
978 &FGInitialCondition::GetLongitudeDegIC,
979 &FGInitialCondition::SetLongitudeDegIC,
981 PropertyManager->Tie("ic/h-sl-ft", this,
982 &FGInitialCondition::GetAltitudeFtIC,
983 &FGInitialCondition::SetAltitudeFtIC,
985 PropertyManager->Tie("ic/h-agl-ft", this,
986 &FGInitialCondition::GetAltitudeAGLFtIC,
987 &FGInitialCondition::SetAltitudeAGLFtIC,
989 PropertyManager->Tie("ic/sea-level-radius-ft", this,
990 &FGInitialCondition::GetSeaLevelRadiusFtIC,
991 &FGInitialCondition::SetSeaLevelRadiusFtIC,
993 PropertyManager->Tie("ic/terrain-altitude-ft", this,
994 &FGInitialCondition::GetTerrainAltitudeFtIC,
995 &FGInitialCondition::SetTerrainAltitudeFtIC,
997 PropertyManager->Tie("ic/vg-fps", this,
998 &FGInitialCondition::GetVgroundFpsIC,
999 &FGInitialCondition::SetVgroundFpsIC,
1001 PropertyManager->Tie("ic/vt-fps", this,
1002 &FGInitialCondition::GetVtrueFpsIC,
1003 &FGInitialCondition::SetVtrueFpsIC,
1005 PropertyManager->Tie("ic/vw-bx-fps", this,
1006 &FGInitialCondition::GetWindUFpsIC);
1007 PropertyManager->Tie("ic/vw-by-fps", this,
1008 &FGInitialCondition::GetWindVFpsIC);
1009 PropertyManager->Tie("ic/vw-bz-fps", this,
1010 &FGInitialCondition::GetWindWFpsIC);
1011 PropertyManager->Tie("ic/vw-north-fps", this,
1012 &FGInitialCondition::GetWindNFpsIC);
1013 PropertyManager->Tie("ic/vw-east-fps", this,
1014 &FGInitialCondition::GetWindEFpsIC);
1015 PropertyManager->Tie("ic/vw-down-fps", this,
1016 &FGInitialCondition::GetWindDFpsIC);
1017 PropertyManager->Tie("ic/vw-mag-fps", this,
1018 &FGInitialCondition::GetWindFpsIC);
1019 PropertyManager->Tie("ic/vw-dir-deg", this,
1020 &FGInitialCondition::GetWindDirDegIC,
1021 &FGInitialCondition::SetWindDirDegIC,
1024 PropertyManager->Tie("ic/roc-fps", this,
1025 &FGInitialCondition::GetClimbRateFpsIC,
1026 &FGInitialCondition::SetClimbRateFpsIC,
1028 PropertyManager->Tie("ic/u-fps", this,
1029 &FGInitialCondition::GetUBodyFpsIC,
1030 &FGInitialCondition::SetUBodyFpsIC,
1032 PropertyManager->Tie("ic/v-fps", this,
1033 &FGInitialCondition::GetVBodyFpsIC,
1034 &FGInitialCondition::SetVBodyFpsIC,
1036 PropertyManager->Tie("ic/w-fps", this,
1037 &FGInitialCondition::GetWBodyFpsIC,
1038 &FGInitialCondition::SetWBodyFpsIC,
1040 PropertyManager->Tie("ic/vn-fps", this,
1041 &FGInitialCondition::GetVNorthFpsIC,
1042 &FGInitialCondition::SetVNorthFpsIC,
1044 PropertyManager->Tie("ic/ve-fps", this,
1045 &FGInitialCondition::GetVEastFpsIC,
1046 &FGInitialCondition::SetVEastFpsIC,
1048 PropertyManager->Tie("ic/vd-fps", this,
1049 &FGInitialCondition::GetVDownFpsIC,
1050 &FGInitialCondition::SetVDownFpsIC,
1052 PropertyManager->Tie("ic/gamma-rad", this,
1053 &FGInitialCondition::GetFlightPathAngleRadIC,
1054 &FGInitialCondition::SetFlightPathAngleRadIC,
1056 PropertyManager->Tie("ic/alpha-rad", this,
1057 &FGInitialCondition::GetAlphaRadIC,
1058 &FGInitialCondition::SetAlphaRadIC,
1060 PropertyManager->Tie("ic/theta-rad", this,
1061 &FGInitialCondition::GetThetaRadIC,
1062 &FGInitialCondition::SetThetaRadIC,
1064 PropertyManager->Tie("ic/beta-rad", this,
1065 &FGInitialCondition::GetBetaRadIC,
1066 &FGInitialCondition::SetBetaRadIC,
1068 PropertyManager->Tie("ic/phi-rad", this,
1069 &FGInitialCondition::GetPhiRadIC,
1070 &FGInitialCondition::SetPhiRadIC,
1072 PropertyManager->Tie("ic/psi-true-rad", this,
1073 &FGInitialCondition::GetPsiRadIC);
1074 PropertyManager->Tie("ic/lat-gc-rad", this,
1075 &FGInitialCondition::GetLatitudeRadIC,
1076 &FGInitialCondition::SetLatitudeRadIC,
1078 PropertyManager->Tie("ic/long-gc-rad", this,
1079 &FGInitialCondition::GetLongitudeRadIC,
1080 &FGInitialCondition::SetLongitudeRadIC,
1082 PropertyManager->Tie("ic/p-rad_sec", this,
1083 &FGInitialCondition::GetPRadpsIC,
1084 &FGInitialCondition::SetPRadpsIC,
1086 PropertyManager->Tie("ic/q-rad_sec", this,
1087 &FGInitialCondition::GetQRadpsIC,
1088 &FGInitialCondition::SetQRadpsIC,
1090 PropertyManager->Tie("ic/r-rad_sec", this,
1091 &FGInitialCondition::GetRRadpsIC,
1092 &FGInitialCondition::SetRRadpsIC,
1095 typedef int (FGInitialCondition::*iPMF)(void) const;
1096 PropertyManager->Tie("simulation/write-state-file",
1099 &FGInitialCondition::WriteStateFile);
1103 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1104 // The bitmasked value choices are as follows:
1105 // unset: In this case (the default) JSBSim would only print
1106 // out the normally expected messages, essentially echoing
1107 // the config files as they are read. If the environment
1108 // variable is not set, debug_lvl is set to 1 internally
1109 // 0: This requests JSBSim not to output any messages
1111 // 1: This value explicity requests the normal JSBSim
1113 // 2: This value asks for a message to be printed out when
1114 // a class is instantiated
1115 // 4: When this value is set, a message is displayed when a
1116 // FGModel object executes its Run() method
1117 // 8: When this value is set, various runtime state variables
1118 // are printed out periodically
1119 // 16: When set various parameters are sanity checked and
1120 // a message is printed out when they go out of bounds
1122 void FGInitialCondition::Debug(int from)
1124 if (debug_lvl <= 0) return;
1126 if (debug_lvl & 1) { // Standard console startup message output
1128 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
1129 if (from == 0) cout << "Instantiated: FGInitialCondition" << endl;
1130 if (from == 1) cout << "Destroyed: FGInitialCondition" << endl;
1132 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
1134 if (debug_lvl & 8 ) { // Runtime state variables
1136 if (debug_lvl & 16) { // Sanity checking
1138 if (debug_lvl & 64) {
1139 if (from == 0) { // Constructor
1140 cout << IdSrc << endl;
1141 cout << IdHdr << endl;