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 "input_output/FGXMLElement.h"
53 #include "models/FGPropulsion.h"
54 #include "input_output/FGXMLParse.h"
55 #include "math/FGQuaternion.h"
64 static const char *IdSrc = "$Id$";
65 static const char *IdHdr = ID_INITIALCONDITION;
67 //******************************************************************************
69 FGInitialCondition::FGInitialCondition(FGFDMExec *FDMExec) : fdmex(FDMExec)
73 if(FDMExec != NULL ) {
74 fdmex->GetPropagate()->SetAltitudeASL(altitudeASL);
75 fdmex->GetAtmosphere()->Run();
76 PropertyManager=fdmex->GetPropertyManager();
81 cout << "FGInitialCondition: This class requires a pointer to a valid FGFDMExec object" << endl;
87 //******************************************************************************
89 FGInitialCondition::~FGInitialCondition()
94 //******************************************************************************
96 void FGInitialCondition::ResetIC(double u0, double v0, double w0,
97 double p0, double q0, double r0,
98 double alpha0, double beta0,
99 double phi0, double theta0, double psi0,
100 double latRad0, double lonRad0, double altAGLFt0,
105 u = u0; v = v0; w = w0;
106 p = p0; q = q0; r = r0;
107 alpha = alpha0; beta = beta0;
108 phi = phi0; theta = theta0; psi = psi0;
113 SetAltitudeAGLFtIC(altAGLFt0);
115 cphi = cos(phi); sphi = sin(phi); // phi, rad
116 ctheta = cos(theta); stheta = sin(theta); // theta, rad
117 cpsi = cos(psi); spsi = sin(psi); // psi, rad
119 FGQuaternion Quat( phi, theta, psi );
122 const FGMatrix33& _Tl2b = Quat.GetT(); // local to body frame
123 const FGMatrix33& _Tb2l = Quat.GetTInv(); // body to local
125 FGColumnVector3 _vUVW_BODY(u,v,w);
126 FGColumnVector3 _vUVW_NED = _Tb2l * _vUVW_BODY;
127 FGColumnVector3 _vWIND_NED(wnorth,weast,wdown);
128 // FGColumnVector3 _vUVWAero = _Tl2b * ( _vUVW_NED + _vWIND_NED );
130 uw=_vWIND_NED(1); vw=_vWIND_NED(2); ww=_vWIND_NED(3);
134 //******************************************************************************
136 void FGInitialCondition::InitializeIC(void)
143 latitude=longitude=0;
147 vnorth=veast=vdown=0;
148 wnorth=weast=wdown=0;
153 radius_to_vehicle = sea_level_radius = fdmex->GetInertial()->GetRefRadius();
154 terrain_elevation = 0;
158 salpha=sbeta=stheta=sphi=spsi=sgamma=0;
159 calpha=cbeta=ctheta=cphi=cpsi=cgamma=1;
162 //******************************************************************************
164 void FGInitialCondition::WriteStateFile(int num)
166 if (Constructing) return;
168 string filename = fdmex->GetFullAircraftPath();
170 if (filename.empty())
171 filename = "initfile.xml";
173 filename.append("/initfile.xml");
175 ofstream outfile(filename.c_str());
176 FGPropagate* Propagate = fdmex->GetPropagate();
178 if (outfile.is_open()) {
179 outfile << "<?xml version=\"1.0\"?>" << endl;
180 outfile << "<initialize name=\"reset00\">" << endl;
181 outfile << " <ubody unit=\"FT/SEC\"> " << Propagate->GetUVW(eX) << " </ubody> " << endl;
182 outfile << " <vbody unit=\"FT/SEC\"> " << Propagate->GetUVW(eY) << " </vbody> " << endl;
183 outfile << " <wbody unit=\"FT/SEC\"> " << Propagate->GetUVW(eZ) << " </wbody> " << endl;
184 outfile << " <phi unit=\"DEG\"> " << Propagate->GetEuler(ePhi) << " </phi>" << endl;
185 outfile << " <theta unit=\"DEG\"> " << Propagate->GetEuler(eTht) << " </theta>" << endl;
186 outfile << " <psi unit=\"DEG\"> " << Propagate->GetEuler(ePsi) << " </psi>" << endl;
187 outfile << " <longitude unit=\"DEG\"> " << Propagate->GetLongitudeDeg() << " </longitude>" << endl;
188 outfile << " <latitude unit=\"DEG\"> " << Propagate->GetLatitudeDeg() << " </latitude>" << endl;
189 outfile << " <altitude unit=\"FT\"> " << Propagate->GetAltitudeASL() << " </altitude>" << endl;
190 outfile << "</initialize>" << endl;
193 cerr << "Could not open and/or write the state to the initial conditions file: " << filename << endl;
197 //******************************************************************************
199 void FGInitialCondition::SetVcalibratedKtsIC(double tt) {
201 if(getMachFromVcas(&mach,tt*ktstofps)) {
202 //cout << "Mach: " << mach << endl;
205 vt=mach*fdmex->GetAtmosphere()->GetSoundSpeed();
206 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
207 //cout << "Vt: " << vt*fpstokts << " Vc: " << vc*fpstokts << endl;
210 cout << "Failed to get Mach number for given Vc and altitude, Vc unchanged." << endl;
211 cout << "Please mail the set of initial conditions used to apeden@earthlink.net" << endl;
215 //******************************************************************************
217 void FGInitialCondition::SetVequivalentKtsIC(double tt) {
220 vt=ve*1/sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
221 mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
225 //******************************************************************************
227 void FGInitialCondition::SetVgroundFpsIC(double tt) {
233 vnorth = vg*cos(psi); veast = vg*sin(psi); vdown = 0;
235 ua = u + uw; va = v + vw; wa = w + ww;
236 vt = sqrt( ua*ua + va*va + wa*wa );
238 vxz = sqrt( u*u + w*w );
239 if( w != 0 ) alpha = atan2( w, u );
240 if( vxz != 0 ) beta = atan2( v, vxz );
241 mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
243 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
246 //******************************************************************************
248 void FGInitialCondition::SetVtrueFpsIC(double tt) {
251 mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
253 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
256 //******************************************************************************
258 void FGInitialCondition::SetMachIC(double tt) {
260 lastSpeedSet=setmach;
261 vt=mach*fdmex->GetAtmosphere()->GetSoundSpeed();
263 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
264 //cout << "Vt: " << vt*fpstokts << " Vc: " << vc*fpstokts << endl;
267 //******************************************************************************
269 void FGInitialCondition::SetClimbRateFpmIC(double tt) {
270 SetClimbRateFpsIC(tt/60.0);
273 //******************************************************************************
275 void FGInitialCondition::SetClimbRateFpsIC(double tt) {
280 sgamma=sin(gamma); cgamma=cos(gamma);
284 //******************************************************************************
286 void FGInitialCondition::SetFlightPathAngleRadIC(double tt) {
288 sgamma=sin(gamma); cgamma=cos(gamma);
293 //******************************************************************************
295 void FGInitialCondition::SetAlphaRadIC(double tt) {
297 salpha=sin(alpha); calpha=cos(alpha);
301 //******************************************************************************
303 void FGInitialCondition::SetThetaRadIC(double tt) {
305 stheta=sin(theta); ctheta=cos(theta);
309 //******************************************************************************
311 void FGInitialCondition::SetBetaRadIC(double tt) {
313 sbeta=sin(beta); cbeta=cos(beta);
318 //******************************************************************************
320 void FGInitialCondition::SetPhiRadIC(double tt) {
322 sphi=sin(phi); cphi=cos(phi);
326 //******************************************************************************
328 void FGInitialCondition::SetPsiRadIC(double tt) {
330 spsi=sin(psi); cpsi=cos(psi);
334 //******************************************************************************
336 void FGInitialCondition::SetUBodyFpsIC(double tt) {
338 vt=sqrt(u*u + v*v + w*w);
342 //******************************************************************************
344 void FGInitialCondition::SetVBodyFpsIC(double tt) {
346 vt=sqrt(u*u + v*v + w*w);
350 //******************************************************************************
352 void FGInitialCondition::SetWBodyFpsIC(double tt) {
354 vt=sqrt( u*u + v*v + w*w );
359 //******************************************************************************
361 void FGInitialCondition::SetVNorthFpsIC(double tt) {
366 ua = u + uw; va = v + vw; wa = w + ww;
367 vt = sqrt( ua*ua + va*va + wa*wa );
369 vxz = sqrt( u*u + w*w );
370 if( w != 0 ) alpha = atan2( w, u );
371 if( vxz != 0 ) beta = atan2( v, vxz );
372 mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
374 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
378 //******************************************************************************
380 void FGInitialCondition::SetVEastFpsIC(double tt) {
385 ua = u + uw; va = v + vw; wa = w + ww;
386 vt = sqrt( ua*ua + va*va + wa*wa );
388 vxz = sqrt( u*u + w*w );
389 if( w != 0 ) alpha = atan2( w, u );
390 if( vxz != 0 ) beta = atan2( v, vxz );
391 mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
393 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
397 //******************************************************************************
399 void FGInitialCondition::SetVDownFpsIC(double tt) {
404 ua = u + uw; va = v + vw; wa = w + ww;
405 vt = sqrt( ua*ua + va*va + wa*wa );
407 vxz = sqrt( u*u + w*w );
408 if( w != 0 ) alpha = atan2( w, u );
409 if( vxz != 0 ) beta = atan2( v, vxz );
410 mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
412 ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
413 SetClimbRateFpsIC(-1*vdown);
417 //******************************************************************************
419 double FGInitialCondition::GetUBodyFpsIC(void) const {
420 if (lastSpeedSet == setvg || lastSpeedSet == setned)
423 return vt*calpha*cbeta - uw;
426 //******************************************************************************
428 double FGInitialCondition::GetVBodyFpsIC(void) const {
429 if (lastSpeedSet == setvg || lastSpeedSet == setned)
432 return vt*sbeta - vw;
436 //******************************************************************************
438 double FGInitialCondition::GetWBodyFpsIC(void) const {
439 if (lastSpeedSet == setvg || lastSpeedSet == setned)
442 return vt*salpha*cbeta -ww;
445 //******************************************************************************
447 void FGInitialCondition::SetWindNEDFpsIC(double wN, double wE, double wD ) {
448 wnorth = wN; weast = wE; wdown = wD;
449 lastWindSet = setwned;
451 if(lastSpeedSet == setvg)
455 //******************************************************************************
457 void FGInitialCondition::SetCrossWindKtsIC(double cross){
458 wcross=cross*ktstofps;
461 if(lastSpeedSet == setvg)
466 //******************************************************************************
468 // positive from left
469 void FGInitialCondition::SetHeadWindKtsIC(double head){
473 if(lastSpeedSet == setvg)
478 //******************************************************************************
480 void FGInitialCondition::SetWindDownKtsIC(double wD) {
483 if(lastSpeedSet == setvg)
487 //******************************************************************************
489 void FGInitialCondition::SetWindMagKtsIC(double mag) {
493 if(lastSpeedSet == setvg)
497 //******************************************************************************
499 void FGInitialCondition::SetWindDirDegIC(double dir) {
503 if(lastSpeedSet == setvg)
508 //******************************************************************************
510 void FGInitialCondition::calcWindUVW(void) {
512 switch(lastWindSet) {
514 wnorth=wmag*cos(wdir);
515 weast=wmag*sin(wdir);
518 wnorth=whead*cos(psi) + wcross*cos(psi+M_PI/2);
519 weast=whead*sin(psi) + wcross*sin(psi+M_PI/2);
524 uw=wnorth*ctheta*cpsi +
527 vw=wnorth*( sphi*stheta*cpsi - cphi*spsi ) +
528 weast*( sphi*stheta*spsi + cphi*cpsi ) +
530 ww=wnorth*(cphi*stheta*cpsi + sphi*spsi) +
531 weast*(cphi*stheta*spsi - sphi*cpsi) +
535 /* cout << "FGInitialCondition::calcWindUVW: wnorth, weast, wdown "
536 << wnorth << ", " << weast << ", " << wdown << endl;
537 cout << "FGInitialCondition::calcWindUVW: theta, phi, psi "
538 << theta << ", " << phi << ", " << psi << endl;
539 cout << "FGInitialCondition::calcWindUVW: uw, vw, ww "
540 << uw << ", " << vw << ", " << ww << endl; */
544 //******************************************************************************
546 void FGInitialCondition::SetAltitudeASLFtIC(double tt)
549 fdmex->GetPropagate()->SetAltitudeASL(altitudeASL);
550 fdmex->GetAtmosphere()->Run();
551 //lets try to make sure the user gets what they intended
553 switch(lastSpeedSet) {
557 SetVtrueKtsIC(vt*fpstokts);
560 SetVcalibratedKtsIC(vc*fpstokts);
563 SetVequivalentKtsIC(ve*fpstokts);
574 //******************************************************************************
576 void FGInitialCondition::SetAltitudeAGLFtIC(double tt)
578 SetAltitudeASLFtIC(terrain_elevation + tt);
581 //******************************************************************************
583 void FGInitialCondition::SetSeaLevelRadiusFtIC(double tt)
585 sea_level_radius = tt;
588 //******************************************************************************
590 void FGInitialCondition::SetTerrainElevationFtIC(double tt)
592 terrain_elevation=tt;
595 //******************************************************************************
597 void FGInitialCondition::calcUVWfromNED(void)
599 u=vnorth*ctheta*cpsi +
602 v=vnorth*( sphi*stheta*cpsi - cphi*spsi ) +
603 veast*( sphi*stheta*spsi + cphi*cpsi ) +
605 w=vnorth*( cphi*stheta*cpsi + sphi*spsi ) +
606 veast*( cphi*stheta*spsi - sphi*cpsi ) +
610 //******************************************************************************
612 bool FGInitialCondition::getMachFromVcas(double *Mach,double vcas) {
618 sfunc=&FGInitialCondition::calcVcas;
619 if(findInterval(vcas,guess)) {
620 if(solve(&mach,vcas))
626 //******************************************************************************
628 bool FGInitialCondition::getAlpha(void) {
630 double guess=theta-gamma;
632 if(vt < 0.01) return 0;
635 xmin=fdmex->GetAerodynamics()->GetAlphaCLMin();
636 xmax=fdmex->GetAerodynamics()->GetAlphaCLMax();
637 sfunc=&FGInitialCondition::GammaEqOfAlpha;
638 if(findInterval(0,guess)){
649 //******************************************************************************
651 bool FGInitialCondition::getTheta(void) {
653 double guess=alpha+gamma;
655 if(vt < 0.01) return 0;
659 sfunc=&FGInitialCondition::GammaEqOfTheta;
660 if(findInterval(0,guess)){
671 //******************************************************************************
673 double FGInitialCondition::GammaEqOfTheta(double Theta) {
675 double sTheta,cTheta;
677 //theta=Theta; stheta=sin(theta); ctheta=cos(theta);
678 sTheta=sin(Theta); cTheta=cos(Theta);
680 a=wdown + vt*calpha*cbeta + uw;
681 b=vt*sphi*sbeta + vw*sphi;
682 c=vt*cphi*salpha*cbeta + ww*cphi;
683 return vt*sgamma - ( a*sTheta - (b+c)*cTheta);
686 //******************************************************************************
688 double FGInitialCondition::GammaEqOfAlpha(double Alpha) {
690 double sAlpha,cAlpha;
691 sAlpha=sin(Alpha); cAlpha=cos(Alpha);
692 a=wdown + vt*cAlpha*cbeta + uw;
693 b=vt*sphi*sbeta + vw*sphi;
694 c=vt*cphi*sAlpha*cbeta + ww*cphi;
696 return vt*sgamma - ( a*stheta - (b+c)*ctheta );
699 //******************************************************************************
701 double FGInitialCondition::calcVcas(double Mach) {
703 double p=fdmex->GetAtmosphere()->GetPressure();
704 double psl=fdmex->GetAtmosphere()->GetPressureSL();
705 double rhosl=fdmex->GetAtmosphere()->GetDensitySL();
706 double pt,A,B,D,vcas;
708 if(Mach < 1) //calculate total pressure assuming isentropic flow
709 pt=p*pow((1 + 0.2*Mach*Mach),3.5);
711 // shock in front of pitot tube, we'll assume its normal and use
712 // the Rayleigh Pitot Tube Formula, i.e. the ratio of total
713 // pressure behind the shock to the static pressure in front
716 //the normal shock assumption should not be a bad one -- most supersonic
717 //aircraft place the pitot probe out front so that it is the forward
718 //most point on the aircraft. The real shock would, of course, take
719 //on something like the shape of a rounded-off cone but, here again,
720 //the assumption should be good since the opening of the pitot probe
721 //is very small and, therefore, the effects of the shock curvature
722 //should be small as well. AFAIK, this approach is fairly well accepted
723 //within the aerospace community
725 B = 5.76*Mach*Mach/(5.6*Mach*Mach - 0.8);
727 // The denominator above is zero for Mach ~ 0.38, for which
728 // we'll never be here, so we're safe
730 D = (2.8*Mach*Mach-0.4)*0.4167;
734 A = pow(((pt-p)/psl+1),0.28571);
735 vcas = sqrt(7*psl/rhosl*(A-1));
736 //cout << "calcVcas: vcas= " << vcas*fpstokts << " mach= " << Mach << " pressure: " << pt << endl;
740 //******************************************************************************
742 bool FGInitialCondition::findInterval(double x,double guess) {
743 //void find_interval(inter_params &ip,eqfunc f,double y,double constant, int &flag){
747 double flo,fhi,fguess;
750 fguess=(this->*sfunc)(guess)-x;
756 if(lo < xmin) lo=xmin;
757 if(hi > xmax) hi=xmax;
759 flo=(this->*sfunc)(lo)-x;
760 fhi=(this->*sfunc)(hi)-x;
761 if(flo*fhi <=0) { //found interval with root
763 if(flo*fguess <= 0) { //narrow interval down a bit
764 hi=lo+step; //to pass solver interval that is as
767 else if(fhi*fguess <= 0) {
771 //cout << "findInterval: i=" << i << " Lo= " << lo << " Hi= " << hi << endl;
773 while((found == 0) && (i <= 100));
779 //******************************************************************************
781 bool FGInitialCondition::solve(double *y,double x)
783 double x1,x2,x3,f1,f2,f3,d,d0;
785 double const relax =0.9;
793 f1=(this->*sfunc)(x1)-x;
794 f3=(this->*sfunc)(x3)-x;
799 while ((fabs(d) > eps) && (i < 100)) {
801 x2 = x1-d*d0*f1/(f3-f1);
803 f2=(this->*sfunc)(x2)-x;
804 //cout << "solve x1,x2,x3: " << x1 << "," << x2 << "," << x3 << endl;
805 //cout << " " << f1 << "," << f2 << "," << f3 << endl;
807 if(fabs(f2) <= 0.001) {
809 } else if(f1*f2 <= 0.0) {
813 } else if(f2*f3 <= 0) {
826 //cout << "Success= " << success << " Vcas: " << vcas*fpstokts << " Mach: " << x2 << endl;
830 //******************************************************************************
832 double FGInitialCondition::GetWindDirDegIC(void) const {
834 return atan2(weast,wnorth)*radtodeg;
841 //******************************************************************************
843 bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
848 if( useStoredPath ) {
849 init_file_name = fdmex->GetFullAircraftPath() + sep + rstfile + ".xml";
851 init_file_name = rstfile;
854 document = LoadXMLDocument(init_file_name);
856 // Make sure that the document is valid
858 cerr << "File: " << init_file_name << " could not be read." << endl;
862 if (document->GetName() != string("initialize")) {
863 cerr << "File: " << init_file_name << " is not a reset file." << endl;
867 if (document->FindElement("latitude"))
868 SetLatitudeDegIC(document->FindElementValueAsNumberConvertTo("latitude", "DEG"));
869 if (document->FindElement("longitude"))
870 SetLongitudeDegIC(document->FindElementValueAsNumberConvertTo("longitude", "DEG"));
871 if (document->FindElement("elevation"))
872 SetTerrainElevationFtIC(document->FindElementValueAsNumberConvertTo("elevation", "FT"));
874 if (document->FindElement("altitude")) // This is feet above ground level
875 SetAltitudeAGLFtIC(document->FindElementValueAsNumberConvertTo("altitude", "FT"));
876 else if (document->FindElement("altitudeAGL")) // This is feet above ground level
877 SetAltitudeAGLFtIC(document->FindElementValueAsNumberConvertTo("altitudeAGL", "FT"));
878 else if (document->FindElement("altitudeMSL")) // This is feet above sea level
879 SetAltitudeASLFtIC(document->FindElementValueAsNumberConvertTo("altitudeMSL", "FT"));
881 if (document->FindElement("ubody"))
882 SetUBodyFpsIC(document->FindElementValueAsNumberConvertTo("ubody", "FT/SEC"));
883 if (document->FindElement("vbody"))
884 SetVBodyFpsIC(document->FindElementValueAsNumberConvertTo("vbody", "FT/SEC"));
885 if (document->FindElement("wbody"))
886 SetWBodyFpsIC(document->FindElementValueAsNumberConvertTo("wbody", "FT/SEC"));
887 if (document->FindElement("vnorth"))
888 SetVNorthFpsIC(document->FindElementValueAsNumberConvertTo("vnorth", "FT/SEC"));
889 if (document->FindElement("veast"))
890 SetVEastFpsIC(document->FindElementValueAsNumberConvertTo("veast", "FT/SEC"));
891 if (document->FindElement("vdown"))
892 SetVDownFpsIC(document->FindElementValueAsNumberConvertTo("vdown", "FT/SEC"));
893 if (document->FindElement("winddir"))
894 SetWindDirDegIC(document->FindElementValueAsNumberConvertTo("winddir", "DEG"));
895 if (document->FindElement("vwind"))
896 SetWindMagKtsIC(document->FindElementValueAsNumberConvertTo("vwind", "KTS"));
897 if (document->FindElement("hwind"))
898 SetHeadWindKtsIC(document->FindElementValueAsNumberConvertTo("hwind", "KTS"));
899 if (document->FindElement("xwind"))
900 SetCrossWindKtsIC(document->FindElementValueAsNumberConvertTo("xwind", "KTS"));
901 if (document->FindElement("vc"))
902 SetVcalibratedKtsIC(document->FindElementValueAsNumberConvertTo("vc", "KTS"));
903 if (document->FindElement("vt"))
904 SetVtrueKtsIC(document->FindElementValueAsNumberConvertTo("vt", "KTS"));
905 if (document->FindElement("mach"))
906 SetMachIC(document->FindElementValueAsNumber("mach"));
907 if (document->FindElement("phi"))
908 SetPhiDegIC(document->FindElementValueAsNumberConvertTo("phi", "DEG"));
909 if (document->FindElement("theta"))
910 SetThetaDegIC(document->FindElementValueAsNumberConvertTo("theta", "DEG"));
911 if (document->FindElement("psi"))
912 SetPsiDegIC(document->FindElementValueAsNumberConvertTo("psi", "DEG"));
913 if (document->FindElement("alpha"))
914 SetAlphaDegIC(document->FindElementValueAsNumberConvertTo("alpha", "DEG"));
915 if (document->FindElement("beta"))
916 SetBetaDegIC(document->FindElementValueAsNumberConvertTo("beta", "DEG"));
917 if (document->FindElement("gamma"))
918 SetFlightPathAngleDegIC(document->FindElementValueAsNumberConvertTo("gamma", "DEG"));
919 if (document->FindElement("roc"))
920 SetClimbRateFpsIC(document->FindElementValueAsNumberConvertTo("roc", "FT/SEC"));
921 if (document->FindElement("vground"))
922 SetVgroundKtsIC(document->FindElementValueAsNumberConvertTo("vground", "KTS"));
923 if (document->FindElement("targetNlf"))
925 SetTargetNlfIC(document->FindElementValueAsNumber("targetNlf"));
928 // Check to see if any engines are specified to be initialized in a running state
929 FGPropulsion* propulsion = fdmex->GetPropulsion();
930 Element* running_elements = document->FindElement("running");
931 while (running_elements) {
932 n = int(running_elements->GetDataAsNumber());
933 propulsion->InitRunning(n);
934 running_elements = document->FindNextElement("running");
942 //******************************************************************************
944 void FGInitialCondition::bind(void){
945 PropertyManager->Tie("ic/vc-kts", this,
946 &FGInitialCondition::GetVcalibratedKtsIC,
947 &FGInitialCondition::SetVcalibratedKtsIC,
949 PropertyManager->Tie("ic/ve-kts", this,
950 &FGInitialCondition::GetVequivalentKtsIC,
951 &FGInitialCondition::SetVequivalentKtsIC,
953 PropertyManager->Tie("ic/vg-kts", this,
954 &FGInitialCondition::GetVgroundKtsIC,
955 &FGInitialCondition::SetVgroundKtsIC,
957 PropertyManager->Tie("ic/vt-kts", this,
958 &FGInitialCondition::GetVtrueKtsIC,
959 &FGInitialCondition::SetVtrueKtsIC,
961 PropertyManager->Tie("ic/mach", this,
962 &FGInitialCondition::GetMachIC,
963 &FGInitialCondition::SetMachIC,
965 PropertyManager->Tie("ic/roc-fpm", this,
966 &FGInitialCondition::GetClimbRateFpmIC,
967 &FGInitialCondition::SetClimbRateFpmIC,
969 PropertyManager->Tie("ic/gamma-deg", this,
970 &FGInitialCondition::GetFlightPathAngleDegIC,
971 &FGInitialCondition::SetFlightPathAngleDegIC,
973 PropertyManager->Tie("ic/alpha-deg", this,
974 &FGInitialCondition::GetAlphaDegIC,
975 &FGInitialCondition::SetAlphaDegIC,
977 PropertyManager->Tie("ic/beta-deg", this,
978 &FGInitialCondition::GetBetaDegIC,
979 &FGInitialCondition::SetBetaDegIC,
981 PropertyManager->Tie("ic/theta-deg", this,
982 &FGInitialCondition::GetThetaDegIC,
983 &FGInitialCondition::SetThetaDegIC,
985 PropertyManager->Tie("ic/phi-deg", this,
986 &FGInitialCondition::GetPhiDegIC,
987 &FGInitialCondition::SetPhiDegIC,
989 PropertyManager->Tie("ic/psi-true-deg", this,
990 &FGInitialCondition::GetPsiDegIC );
991 PropertyManager->Tie("ic/lat-gc-deg", this,
992 &FGInitialCondition::GetLatitudeDegIC,
993 &FGInitialCondition::SetLatitudeDegIC,
995 PropertyManager->Tie("ic/long-gc-deg", this,
996 &FGInitialCondition::GetLongitudeDegIC,
997 &FGInitialCondition::SetLongitudeDegIC,
999 PropertyManager->Tie("ic/h-sl-ft", this,
1000 &FGInitialCondition::GetAltitudeASLFtIC,
1001 &FGInitialCondition::SetAltitudeASLFtIC,
1003 PropertyManager->Tie("ic/h-agl-ft", this,
1004 &FGInitialCondition::GetAltitudeAGLFtIC,
1005 &FGInitialCondition::SetAltitudeAGLFtIC,
1007 PropertyManager->Tie("ic/sea-level-radius-ft", this,
1008 &FGInitialCondition::GetSeaLevelRadiusFtIC,
1009 &FGInitialCondition::SetSeaLevelRadiusFtIC,
1011 PropertyManager->Tie("ic/terrain-elevation-ft", this,
1012 &FGInitialCondition::GetTerrainElevationFtIC,
1013 &FGInitialCondition::SetTerrainElevationFtIC,
1015 PropertyManager->Tie("ic/vg-fps", this,
1016 &FGInitialCondition::GetVgroundFpsIC,
1017 &FGInitialCondition::SetVgroundFpsIC,
1019 PropertyManager->Tie("ic/vt-fps", this,
1020 &FGInitialCondition::GetVtrueFpsIC,
1021 &FGInitialCondition::SetVtrueFpsIC,
1023 PropertyManager->Tie("ic/vw-bx-fps", this,
1024 &FGInitialCondition::GetWindUFpsIC);
1025 PropertyManager->Tie("ic/vw-by-fps", this,
1026 &FGInitialCondition::GetWindVFpsIC);
1027 PropertyManager->Tie("ic/vw-bz-fps", this,
1028 &FGInitialCondition::GetWindWFpsIC);
1029 PropertyManager->Tie("ic/vw-north-fps", this,
1030 &FGInitialCondition::GetWindNFpsIC);
1031 PropertyManager->Tie("ic/vw-east-fps", this,
1032 &FGInitialCondition::GetWindEFpsIC);
1033 PropertyManager->Tie("ic/vw-down-fps", this,
1034 &FGInitialCondition::GetWindDFpsIC);
1035 PropertyManager->Tie("ic/vw-mag-fps", this,
1036 &FGInitialCondition::GetWindFpsIC);
1037 PropertyManager->Tie("ic/vw-dir-deg", this,
1038 &FGInitialCondition::GetWindDirDegIC,
1039 &FGInitialCondition::SetWindDirDegIC,
1042 PropertyManager->Tie("ic/roc-fps", this,
1043 &FGInitialCondition::GetClimbRateFpsIC,
1044 &FGInitialCondition::SetClimbRateFpsIC,
1046 PropertyManager->Tie("ic/u-fps", this,
1047 &FGInitialCondition::GetUBodyFpsIC,
1048 &FGInitialCondition::SetUBodyFpsIC,
1050 PropertyManager->Tie("ic/v-fps", this,
1051 &FGInitialCondition::GetVBodyFpsIC,
1052 &FGInitialCondition::SetVBodyFpsIC,
1054 PropertyManager->Tie("ic/w-fps", this,
1055 &FGInitialCondition::GetWBodyFpsIC,
1056 &FGInitialCondition::SetWBodyFpsIC,
1058 PropertyManager->Tie("ic/vn-fps", this,
1059 &FGInitialCondition::GetVNorthFpsIC,
1060 &FGInitialCondition::SetVNorthFpsIC,
1062 PropertyManager->Tie("ic/ve-fps", this,
1063 &FGInitialCondition::GetVEastFpsIC,
1064 &FGInitialCondition::SetVEastFpsIC,
1066 PropertyManager->Tie("ic/vd-fps", this,
1067 &FGInitialCondition::GetVDownFpsIC,
1068 &FGInitialCondition::SetVDownFpsIC,
1070 PropertyManager->Tie("ic/gamma-rad", this,
1071 &FGInitialCondition::GetFlightPathAngleRadIC,
1072 &FGInitialCondition::SetFlightPathAngleRadIC,
1074 PropertyManager->Tie("ic/alpha-rad", this,
1075 &FGInitialCondition::GetAlphaRadIC,
1076 &FGInitialCondition::SetAlphaRadIC,
1078 PropertyManager->Tie("ic/theta-rad", this,
1079 &FGInitialCondition::GetThetaRadIC,
1080 &FGInitialCondition::SetThetaRadIC,
1082 PropertyManager->Tie("ic/beta-rad", this,
1083 &FGInitialCondition::GetBetaRadIC,
1084 &FGInitialCondition::SetBetaRadIC,
1086 PropertyManager->Tie("ic/phi-rad", this,
1087 &FGInitialCondition::GetPhiRadIC,
1088 &FGInitialCondition::SetPhiRadIC,
1090 PropertyManager->Tie("ic/psi-true-rad", this,
1091 &FGInitialCondition::GetPsiRadIC);
1092 PropertyManager->Tie("ic/lat-gc-rad", this,
1093 &FGInitialCondition::GetLatitudeRadIC,
1094 &FGInitialCondition::SetLatitudeRadIC,
1096 PropertyManager->Tie("ic/long-gc-rad", this,
1097 &FGInitialCondition::GetLongitudeRadIC,
1098 &FGInitialCondition::SetLongitudeRadIC,
1100 PropertyManager->Tie("ic/p-rad_sec", this,
1101 &FGInitialCondition::GetPRadpsIC,
1102 &FGInitialCondition::SetPRadpsIC,
1104 PropertyManager->Tie("ic/q-rad_sec", this,
1105 &FGInitialCondition::GetQRadpsIC,
1106 &FGInitialCondition::SetQRadpsIC,
1108 PropertyManager->Tie("ic/r-rad_sec", this,
1109 &FGInitialCondition::GetRRadpsIC,
1110 &FGInitialCondition::SetRRadpsIC,
1113 typedef int (FGInitialCondition::*iPMF)(void) const;
1114 PropertyManager->Tie("simulation/write-state-file",
1117 &FGInitialCondition::WriteStateFile);
1121 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1122 // The bitmasked value choices are as follows:
1123 // unset: In this case (the default) JSBSim would only print
1124 // out the normally expected messages, essentially echoing
1125 // the config files as they are read. If the environment
1126 // variable is not set, debug_lvl is set to 1 internally
1127 // 0: This requests JSBSim not to output any messages
1129 // 1: This value explicity requests the normal JSBSim
1131 // 2: This value asks for a message to be printed out when
1132 // a class is instantiated
1133 // 4: When this value is set, a message is displayed when a
1134 // FGModel object executes its Run() method
1135 // 8: When this value is set, various runtime state variables
1136 // are printed out periodically
1137 // 16: When set various parameters are sanity checked and
1138 // a message is printed out when they go out of bounds
1140 void FGInitialCondition::Debug(int from)
1142 if (debug_lvl <= 0) return;
1144 if (debug_lvl & 1) { // Standard console startup message output
1146 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
1147 if (from == 0) cout << "Instantiated: FGInitialCondition" << endl;
1148 if (from == 1) cout << "Destroyed: FGInitialCondition" << endl;
1150 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
1152 if (debug_lvl & 8 ) { // Runtime state variables
1154 if (debug_lvl & 16) { // Sanity checking
1156 if (debug_lvl & 64) {
1157 if (from == 0) { // Constructor
1158 cout << IdSrc << endl;
1159 cout << IdHdr << endl;