From 60ce82687417f0c583b46923f191ca2987033ab9 Mon Sep 17 00:00:00 2001
From: Bertrand Coconnier <bcoconni@users.sf.net>
Date: Sat, 23 Apr 2022 19:18:42 +0200
Subject: [PATCH] Sync'ed with JSBSim v1.1.11

- Output files are now written in the current directory instead of being written in the aircraft folder (issue GH#337)
- A new exception TrimFailureException is now thrown when trim fails. This eases the detection of the trim failure (previously the exception message needed to be checked).
- An exception is thrown when a latitude higher than 90 degrees is supplied to a <waypoint> control element (PR GH#536)
- Fix the sign of the initial NED climb rate (property ic/gamma-deg) (PR #545)
- JSBSim now checks malformed data in <table> elements. Anything different than numbers and spaces/tabs will be rejected.
- Usage of <location> and <orientation> in engines is now officially dropped (PR #559, #561 and #563). These elements were deprecated long ago in favor of the corresponding elements <location> and <orientation> in thrusters. Therefore the code removed is no-op.
- The computation of the initial rotation rates has been fixed (Issue GH#553). Previously, the rotation rates could be initialized with extremely high values when the vehicle was spawned over the Poles. And for a given set of initial conditions, the initial rotation rates could have different values depending on the initial latitude at which the vehicle was initialized. This now fixed.
- The precision with which values are transmitted thru a socket can now be set via the attribute precision such as <output precision="8"> (PR GH#579)
- Added 2 new methods to FGFDMExec: SetOutputPath and GetOutputPath to specify the path to which the output files will be written.
- All JSBSim exceptions now inherit from JSBSim::BaseException. There still exist std::* exceptions thrown by JSBSim. Cleanup is still in progress.
- JSBSim no longer calls exit() or abort(). Exceptions are thrown instead. This gives the calling application an opportunity to gracefully recover.
---
 src/FDM/JSBSim/FGFDMExec.cpp                  | 19 ++--
 src/FDM/JSBSim/FGFDMExec.h                    | 99 +++++++++++++------
 src/FDM/JSBSim/FGJSBBase.h                    | 16 ++-
 .../initialization/FGInitialCondition.cpp     | 48 +++++----
 .../initialization/FGInitialCondition.h       |  2 +-
 src/FDM/JSBSim/input_output/FGOutputFG.cpp    |  4 +-
 src/FDM/JSBSim/input_output/FGOutputFile.h    |  2 +-
 .../JSBSim/input_output/FGOutputSocket.cpp    |  8 +-
 src/FDM/JSBSim/input_output/FGOutputSocket.h  |  1 +
 .../JSBSim/input_output/FGPropertyManager.cpp | 24 +++--
 .../JSBSim/input_output/FGPropertyManager.h   | 14 ++-
 src/FDM/JSBSim/input_output/FGScript.cpp      | 54 +++++-----
 src/FDM/JSBSim/input_output/FGfdmSocket.cpp   |  8 +-
 src/FDM/JSBSim/input_output/FGfdmSocket.h     |  7 +-
 src/FDM/JSBSim/math/FGCondition.cpp           |  2 +-
 src/FDM/JSBSim/math/FGFunction.cpp            |  6 +-
 src/FDM/JSBSim/math/FGMatrix33.cpp            | 46 ++++-----
 src/FDM/JSBSim/math/FGMatrix33.h              | 19 +---
 src/FDM/JSBSim/math/FGTable.cpp               | 74 +++++++-------
 src/FDM/JSBSim/math/FGTable.h                 | 15 ---
 src/FDM/JSBSim/models/FGAerodynamics.cpp      | 52 ++++++----
 src/FDM/JSBSim/models/FGGasCell.cpp           | 66 +++++++------
 src/FDM/JSBSim/models/FGInput.cpp             |  9 +-
 src/FDM/JSBSim/models/FGLGear.cpp             |  7 +-
 src/FDM/JSBSim/models/FGMassBalance.cpp       | 18 ++--
 src/FDM/JSBSim/models/FGOutput.cpp            |  7 +-
 src/FDM/JSBSim/models/FGPropagate.cpp         | 20 ++--
 .../models/flight_control/FGKinemat.cpp       | 23 ++---
 .../models/flight_control/FGWaypoint.cpp      | 20 +++-
 src/FDM/JSBSim/models/propulsion/FGEngine.cpp | 32 ++----
 src/FDM/JSBSim/models/propulsion/FGEngine.h   | 17 ----
 src/FDM/JSBSim/models/propulsion/FGForce.cpp  |  7 +-
 src/FDM/JSBSim/models/propulsion/FGNozzle.cpp |  7 +-
 src/FDM/JSBSim/models/propulsion/FGTank.cpp   | 35 ++++---
 34 files changed, 424 insertions(+), 364 deletions(-)

diff --git a/src/FDM/JSBSim/FGFDMExec.cpp b/src/FDM/JSBSim/FGFDMExec.cpp
index 48a0fd123..66c96504e 100644
--- a/src/FDM/JSBSim/FGFDMExec.cpp
+++ b/src/FDM/JSBSim/FGFDMExec.cpp
@@ -144,9 +144,14 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr)
   // this is to catch errors in binding member functions to the property tree.
   try {
     Allocate();
-  } catch (const string& msg ) {
-    cout << "Caught error: " << msg << endl;
-    exit(1);
+  }
+  catch (const string& msg) {
+    cerr << endl << "Caught error: " << msg << endl;
+    throw;
+  }
+  catch (const BaseException& e) {
+    cout << endl << "Caught error: " << e.what() << endl;
+    throw;
   }
 
   trim_status = false;
@@ -1093,8 +1098,10 @@ bool FGFDMExec::ReadChild(Element* el)
   if (location) {
     child->Loc = location->FindElementTripletConvertTo("IN");
   } else {
-    cerr << endl << highint << fgred << "  No location was found for this child object!" << reset << endl;
-    exit(-1);
+    const string s("  No location was found for this child object!");
+    cerr << el->ReadFrom() << endl << highint << fgred
+         << s << reset << endl;
+    throw BaseException(s);
   }
 
   Element* orientation = el->FindElement("orient");
@@ -1165,7 +1172,7 @@ void FGFDMExec::DoTrim(int mode)
     trim.Report();
 
   if (!success)
-    throw("Trim Failed");
+    throw TrimFailureException("Trim Failed");
 
   trim_completed = 1;
 }
diff --git a/src/FDM/JSBSim/FGFDMExec.h b/src/FDM/JSBSim/FGFDMExec.h
index 2d9d934a5..5e91686a8 100644
--- a/src/FDM/JSBSim/FGFDMExec.h
+++ b/src/FDM/JSBSim/FGFDMExec.h
@@ -72,6 +72,11 @@ class FGPropulsion;
 class FGMassBalance;
 class FGTrim;
 
+class TrimFailureException : public BaseException {
+  public:
+    TrimFailureException(const std::string& msg) : BaseException(msg) {}
+};
+
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 CLASS DOCUMENTATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
@@ -194,7 +199,7 @@ class FGFDMExec : public FGJSBBase
       mated = true;
       internal = false;
     }
-    
+
     void Run(void) {exec->Run();}
     void AssignState(FGPropagate* source_prop) {
       exec->GetPropagate()->SetVState(source_prop->GetVState());
@@ -283,44 +288,65 @@ public:
       @return true if successful*/
   bool LoadModel(const std::string& model, bool addModelToPath = true);
 
-  /** Loads a script
+  /** Load a script
       @param Script The full path name and file name for the script to be loaded.
-      @param deltaT The simulation integration step size, if given.  If no value is supplied
-                    then 0.0 is used and the value is expected to be supplied in
-                    the script file itself.
-      @param initfile The initialization file that will override the initialization file
-                      specified in the script file. If no file name is given on the command line,
-                      the file specified in the script will be used. If an initialization file 
-                      is not given in either place, an error will result.
+      @param deltaT The simulation integration step size, if given.  If no value
+                    is supplied then 0.0 is used and the value is expected to be
+                    supplied in the script file itself.
+      @param initfile The initialization file that will override the
+                      initialization file specified in the script file. If no
+                      file name is given on the command line, the file specified
+                      in the script will be used. If an initialization file is
+                      not given in either place, an error will result.
       @return true if successfully loads; false otherwise. */
   bool LoadScript(const SGPath& Script, double deltaT=0.0,
                   const SGPath& initfile=SGPath());
 
-  /** Sets the path to the engine config file directories.
-      @param path path to the directory under which engine config
-      files are kept, for instance "engine"  */
+  /** Set the path to the engine config file directories.
+      Relative paths are taken from the root directory.
+      @param path path to the directory under which engine config files are
+                  kept, for instance "engine".
+      @see SetRootDir
+      @see GetEnginePath */
   bool SetEnginePath(const SGPath& path) {
     EnginePath = GetFullPath(path);
     return true;
   }
 
-  /** Sets the path to the aircraft config file directories.
-      @param path path to the aircraft directory. For instance:
-      "aircraft". Under aircraft, then, would be directories for various
-      modeled aircraft such as C172/, x15/, etc.  */
+  /** Set the path to the aircraft config file directories.
+      Under this path, then, would be directories for various modeled aircraft
+      such as C172/, x15/, etc.
+      Relative paths are taken from the root directory.
+      @param path path to the aircraft directory, for instance "aircraft".
+      @see SetRootDir
+      @see GetAircraftPath */
   bool SetAircraftPath(const SGPath& path) {
     AircraftPath = GetFullPath(path);
     return true;
   }
-  
-  /** Sets the path to the systems config file directories.
-      @param path path to the directory under which systems config
-      files are kept, for instance "systems"  */
+
+  /** Set the path to the systems config file directories.
+      Relative paths are taken from the root directory.
+      @param path path to the directory under which systems config files are
+                  kept, for instance "systems"
+      @see SetRootDir
+      @see GetSystemsPath */
   bool SetSystemsPath(const SGPath& path) {
     SystemsPath = GetFullPath(path);
     return true;
   }
-  
+
+  /** Set the directory where the output files will be written.
+      Relative paths are taken from the root directory.
+      @param path path to the directory under which the output files will be
+                  written.
+      @see SetRootDir
+      @see GetOutputPath */
+  bool SetOutputPath(const SGPath& path) {
+    OutputPath = GetFullPath(path);
+    return true;
+  }
+
   /// @name Top-level executive State and Model retrieval mechanism
   ///@{
   /// Returns the FGAtmosphere pointer.
@@ -364,13 +390,15 @@ public:
   ///@}
 
   /// Retrieves the engine path.
-  const SGPath& GetEnginePath(void)    {return EnginePath;}
+  const SGPath& GetEnginePath(void) { return EnginePath; }
   /// Retrieves the aircraft path.
-  const SGPath& GetAircraftPath(void)  {return AircraftPath;}
+  const SGPath& GetAircraftPath(void) { return AircraftPath; }
   /// Retrieves the systems path.
-  const SGPath& GetSystemsPath(void)   {return SystemsPath;}
+  const SGPath& GetSystemsPath(void) { return SystemsPath; }
   /// Retrieves the full aircraft path name.
-  const SGPath& GetFullAircraftPath(void) {return FullAircraftPath;}
+  const SGPath& GetFullAircraftPath(void) { return FullAircraftPath; }
+  /// Retrieves the path to the output files.
+  const SGPath& GetOutputPath(void) { return OutputPath; }
 
   /** Retrieves the value of a property.
       @param property the name of the property
@@ -535,13 +563,23 @@ public:
       @param delta_t the time step in seconds.     */
   void Setdt(double delta_t) { dT = delta_t; }
 
-  /** Sets the root directory where JSBSim starts looking for its system
-      directories.
-      @param rootDir the string containing the root directory. */
+  /** Set the root directory that is used to obtain absolute paths from
+      relative paths.
+      Aircraft, engine, systems and output paths are not updated by this
+      method. You must call each methods (SetAircraftPath(), SetEnginePath(),
+      etc.) individually if you need to update these paths as well.
+      @param rootDir the path to the root directory.
+      @see GetRootDir
+      @see SetAircraftPath
+      @see SetEnginePath
+      @see SetSystemsPath
+      @see SetOutputPath
+       */
   void SetRootDir(const SGPath& rootDir) {RootDir = rootDir;}
 
-  /** Retrieves the Root Directory.
-      @return the string representing the root (base) JSBSim directory. */
+  /** Retrieve the Root Directory.
+      @return the path to the root (base) JSBSim directory.
+      @see SetRootDir */
   const SGPath& GetRootDir(void) const {return RootDir;}
 
   /** Increments the simulation time if not in Holding mode. The Frame counter
@@ -600,6 +638,7 @@ private:
   SGPath FullAircraftPath;
   SGPath EnginePath;
   SGPath SystemsPath;
+  SGPath OutputPath;
   std::string CFGVersion;
   std::string Release;
   SGPath RootDir;
diff --git a/src/FDM/JSBSim/FGJSBBase.h b/src/FDM/JSBSim/FGJSBBase.h
index cc6b6af11..69fbb0014 100644
--- a/src/FDM/JSBSim/FGJSBBase.h
+++ b/src/FDM/JSBSim/FGJSBBase.h
@@ -42,6 +42,7 @@ INCLUDES
 #include <queue>
 #include <string>
 #include <cmath>
+#include <stdexcept>
 
 #include "input_output/string_utilities.h"
 
@@ -55,6 +56,11 @@ FORWARD DECLARATIONS
 
 namespace JSBSim {
 
+class BaseException : public std::runtime_error {
+  public:
+    BaseException(const std::string& msg) : std::runtime_error(msg) {}
+};
+
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 CLASS DOCUMENTATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
@@ -263,7 +269,7 @@ public:
   static double PitotTotalPressure(double mach, double p);
 
   /** Compute the Mach number from the differential pressure (qc) and the
-  *   static pressure. Based on the formulas in the US Air Force Aircraft 
+  *   static pressure. Based on the formulas in the US Air Force Aircraft
   *   Performance Flight Testing Manual (AFFTC-TIH-99-01).
   *   @param qc    The differential/impact pressure
   *   @param p     Pressure in psf
@@ -271,7 +277,7 @@ public:
   static double MachFromImpactPressure(double qc, double p);
 
   /** Calculate the calibrated airspeed from the Mach number. Based on the
-  *   formulas in the US Air Force Aircraft Performance Flight Testing 
+  *   formulas in the US Air Force Aircraft Performance Flight Testing
   *   Manual (AFFTC-TIH-99-01).
   *   @param mach  The Mach number
   *   @param p     Pressure in psf
@@ -280,7 +286,7 @@ public:
   static double VcalibratedFromMach(double mach, double p);
 
   /** Calculate the Mach number from the calibrated airspeed.Based on the
-  *   formulas in the US Air Force Aircraft Performance Flight Testing 
+  *   formulas in the US Air Force Aircraft Performance Flight Testing
   *   Manual (AFFTC-TIH-99-01).
   *   @param vcas  The calibrated airspeed (CAS) in ft/s
   *   @param p     Pressure in psf
@@ -321,13 +327,13 @@ public:
   static bool EqualToRoundoff(double a, float b) {
     return EqualToRoundoff((float)a, b);
   }
-  
+
   /** Constrain a value between a minimum and a maximum value.
   */
   static constexpr double Constrain(double min, double value, double max) {
     return value<min?(min):(value>max?(max):(value));
   }
-  
+
   static constexpr double sign(double num) {return num>=0.0?1.0:-1.0;}
 
   static double GaussianRandomNumber(void);
diff --git a/src/FDM/JSBSim/initialization/FGInitialCondition.cpp b/src/FDM/JSBSim/initialization/FGInitialCondition.cpp
index 774b5596b..3f5935935 100644
--- a/src/FDM/JSBSim/initialization/FGInitialCondition.cpp
+++ b/src/FDM/JSBSim/initialization/FGInitialCondition.cpp
@@ -808,7 +808,7 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt)
         }
         geodAlt = z/sinGeodLat-N*(1-e2);
       }
-      
+
       double longitude = position.GetLongitude();
       position.SetPositionGeodetic(longitude, geodLatitude, geodAlt);
     }
@@ -1013,13 +1013,17 @@ bool FGInitialCondition::Load(const SGPath& rstfile, bool useStoredPath)
 
   // Make sure that the document is valid
   if (!document) {
-    cerr << "File: " << init_file_name << " could not be read." << endl;
-    exit(-1);
+    stringstream s;
+    s << "File: " << init_file_name << " could not be read.";
+    cerr << s.str() << endl;
+    throw BaseException(s.str());
   }
 
   if (document->GetName() != string("initialize")) {
-    cerr << "File: " << init_file_name << " is not a reset file." << endl;
-    exit(-1);
+    stringstream s;
+    s << "File: " << init_file_name << " is not a reset file.";
+    cerr << s.str() << endl;
+    throw BaseException(s.str());
   }
 
   double version = HUGE_VAL;
@@ -1031,8 +1035,9 @@ bool FGInitialCondition::Load(const SGPath& rstfile, bool useStoredPath)
   if (version == HUGE_VAL) {
     result = Load_v1(document); // Default to the old version
   } else if (version >= 3.0) {
-    cerr << "Only initialization file formats 1 and 2 are currently supported" << endl;
-    exit (-1);
+    const string s("Only initialization file formats 1 and 2 are currently supported");
+    cerr << document->ReadFrom() << endl << s << endl;
+    throw BaseException(s);
   } else if (version >= 2.0) {
     result = Load_v2(document);
   } else if (version >= 1.0) {
@@ -1182,15 +1187,7 @@ bool FGInitialCondition::Load_v1(Element* document)
   if (document->FindElement("trim"))
     SetTrimRequest(document->FindElementValue("trim"));
 
-  // Refer to Stevens and Lewis, 1.5-14a, pg. 49.
-  // This is the rotation rate of the "Local" frame, expressed in the local frame.
-  const FGMatrix33& Tl2b = orientation.GetT();
-  double radInv = 1.0 / position.GetRadius();
-  FGColumnVector3 vOmegaLocal = {radInv*vUVW_NED(eEast),
-                                 -radInv*vUVW_NED(eNorth),
-                                 -radInv*vUVW_NED(eEast)*tan(position.GetLatitude())};
-
-  vPQR_body = Tl2b * vOmegaLocal;
+  vPQR_body.InitMatrix();
 
   return result;
 }
@@ -1403,19 +1400,12 @@ bool FGInitialCondition::Load_v2(Element* document)
   // - Body
 
   Element* attrate_el = document->FindElement("attitude_rate");
-  const FGMatrix33& Tl2b = orientation.GetT();
-
-  // Refer to Stevens and Lewis, 1.5-14a, pg. 49.
-  // This is the rotation rate of the "Local" frame, expressed in the local frame.
-  double radInv = 1.0 / position.GetRadius();
-  FGColumnVector3 vOmegaLocal = { radInv*vUVW_NED(eEast),
-                                  -radInv*vUVW_NED(eNorth),
-                                  -radInv*vUVW_NED(eEast)*tan(position.GetLatitude())};
 
   if (attrate_el) {
 
     string frame = attrate_el->GetAttributeValue("frame");
     frame = to_lower(frame);
+    const FGMatrix33& Tl2b = orientation.GetT();
     FGColumnVector3 vAttRate = attrate_el->FindElementTripletConvertTo("RAD/SEC");
 
     if (frame == "eci") {
@@ -1424,6 +1414,12 @@ bool FGInitialCondition::Load_v2(Element* document)
     } else if (frame == "ecef") {
       vPQR_body = Tl2b * position.GetTec2l() * vAttRate;
     } else if (frame == "local") {
+      // Refer to Stevens and Lewis, 1.5-14a, pg. 49.
+      // This is the rotation rate of the "Local" frame, expressed in the local frame.
+      double radInv = 1.0 / position.GetRadius();
+      FGColumnVector3 vOmegaLocal = {radInv*vUVW_NED(eEast),
+                                    -radInv*vUVW_NED(eNorth),
+                                    -radInv*vUVW_NED(eEast)*tan(position.GetLatitude())};
       vPQR_body = Tl2b * (vAttRate + vOmegaLocal);
     } else if (frame == "body") {
       vPQR_body = vAttRate;
@@ -1434,11 +1430,11 @@ bool FGInitialCondition::Load_v2(Element* document)
       result = false;
 
     } else if (frame.empty()) {
-      vPQR_body = Tl2b * vOmegaLocal;
+      vPQR_body.InitMatrix();
     }
 
   } else { // Body frame attitude rate assumed 0 relative to local.
-      vPQR_body = Tl2b * vOmegaLocal;
+      vPQR_body.InitMatrix();
   }
 
   return result;
diff --git a/src/FDM/JSBSim/initialization/FGInitialCondition.h b/src/FDM/JSBSim/initialization/FGInitialCondition.h
index 9190c4651..0a84da1bc 100644
--- a/src/FDM/JSBSim/initialization/FGInitialCondition.h
+++ b/src/FDM/JSBSim/initialization/FGInitialCondition.h
@@ -519,7 +519,7 @@ public:
   {
     const FGMatrix33& Tb2l = orientation.GetTInv();
     FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
-    return _vt_NED(eW);
+    return -_vt_NED(eW);
   }
 
   /** Gets the initial body velocity
diff --git a/src/FDM/JSBSim/input_output/FGOutputFG.cpp b/src/FDM/JSBSim/input_output/FGOutputFG.cpp
index f95f980f9..846ea85e3 100644
--- a/src/FDM/JSBSim/input_output/FGOutputFG.cpp
+++ b/src/FDM/JSBSim/input_output/FGOutputFG.cpp
@@ -214,7 +214,7 @@ void FGOutputFG::SocketDataFill(FGNetFDM* net)
   net->stall_warning = 0.0;  // 0.0 - 1.0 indicating the amount of stall
   net->slip_deg    = (float)(Auxiliary->Getbeta(inDegrees));  // slip ball deflection, deg
 
-  net->num_engines = min((unsigned) FGNetFDM::FG_MAX_ENGINES, Propulsion->GetNumEngines()); // Number of valid engines
+  net->num_engines = min(FGNetFDM::FG_MAX_ENGINES,Propulsion->GetNumEngines()); // Number of valid engines
 
   for (i=0; i<net->num_engines; i++) {
     FGEngine* engine = Propulsion->GetEngine(i);
@@ -254,7 +254,7 @@ void FGOutputFG::SocketDataFill(FGNetFDM* net)
     }
   }
 
-  net->num_tanks = min((unsigned) FGNetFDM::FG_MAX_TANKS, Propulsion->GetNumTanks());   // Max number of fuel tanks
+  net->num_tanks = min(FGNetFDM::FG_MAX_TANKS, Propulsion->GetNumTanks());   // Max number of fuel tanks
 
   for (i=0; i<net->num_tanks; i++) {
     net->fuel_quantity[i] = (float)(((FGTank *)Propulsion->GetTank(i))->GetContents());
diff --git a/src/FDM/JSBSim/input_output/FGOutputFile.h b/src/FDM/JSBSim/input_output/FGOutputFile.h
index 99298bee3..ddfffb1ce 100644
--- a/src/FDM/JSBSim/input_output/FGOutputFile.h
+++ b/src/FDM/JSBSim/input_output/FGOutputFile.h
@@ -100,7 +100,7 @@ public:
       the next call to SetStartNewOutput().
       @param name new name */
   void SetOutputName(const std::string& fname) override {
-    Name = (FDMExec->GetRootDir()/fname).utf8Str();
+    Name = (FDMExec->GetOutputPath()/fname).utf8Str();
     runID_postfix = -1;
     Filename = SGPath();
   }
diff --git a/src/FDM/JSBSim/input_output/FGOutputSocket.cpp b/src/FDM/JSBSim/input_output/FGOutputSocket.cpp
index 6592efd9c..0ad87af0d 100644
--- a/src/FDM/JSBSim/input_output/FGOutputSocket.cpp
+++ b/src/FDM/JSBSim/input_output/FGOutputSocket.cpp
@@ -121,6 +121,12 @@ bool FGOutputSocket::Load(Element* el)
                 el->GetAttributeValue("protocol") + "/" +
                 el->GetAttributeValue("port"));
 
+  // Check if output precision for doubles has been specified, default to 7 if not
+  if(el->HasAttribute("precision"))
+    precision = (int)el->GetAttributeValueAsNumber("precision");
+  else
+    precision = 7;
+
   return true;
 }
 
@@ -130,7 +136,7 @@ bool FGOutputSocket::InitModel(void)
 {
   if (FGOutputType::InitModel()) {
     delete socket;
-    socket = new FGfdmSocket(SockName, SockPort, SockProtocol);
+    socket = new FGfdmSocket(SockName, SockPort, SockProtocol, precision);
 
     if (socket == 0) return false;
     if (!socket->GetConnectStatus()) return false;
diff --git a/src/FDM/JSBSim/input_output/FGOutputSocket.h b/src/FDM/JSBSim/input_output/FGOutputSocket.h
index d65ceec9b..d598ce222 100644
--- a/src/FDM/JSBSim/input_output/FGOutputSocket.h
+++ b/src/FDM/JSBSim/input_output/FGOutputSocket.h
@@ -108,6 +108,7 @@ protected:
   unsigned int SockPort;
   FGfdmSocket::ProtocolType SockProtocol;
   FGfdmSocket* socket;
+  int precision;
 };
 }
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/src/FDM/JSBSim/input_output/FGPropertyManager.cpp b/src/FDM/JSBSim/input_output/FGPropertyManager.cpp
index 9f8fbf806..9ec56b539 100644
--- a/src/FDM/JSBSim/input_output/FGPropertyManager.cpp
+++ b/src/FDM/JSBSim/input_output/FGPropertyManager.cpp
@@ -28,6 +28,7 @@
 INCLUDES
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
+#include <assert.h>
 #include "FGPropertyManager.h"
 
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -110,13 +111,6 @@ bool FGPropertyNode::HasNode (const string &path)
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-string FGPropertyNode::GetName( void ) const
-{
-  return getNameString();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
 string FGPropertyNode::GetPrintableName( void ) const
 {
   string temp_string(getNameString());
@@ -301,7 +295,7 @@ void FGPropertyNode::SetWritable (const string &name, bool state )
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-void FGPropertyManager::Untie (const string &name)
+void FGPropertyManager::Untie(const string &name)
 {
   SGPropertyNode* property = root->getNode(name.c_str());
   if (!property) {
@@ -309,8 +303,18 @@ void FGPropertyManager::Untie (const string &name)
     return;
   }
 
-  vector <SGPropertyNode_ptr>::iterator it;
-  for (it = tied_properties.begin(); it != tied_properties.end(); ++it) {
+  Untie(property);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropertyManager::Untie(SGPropertyNode *property)
+{
+  const string& name = property->getNameString();
+
+  assert(property->isTied());
+
+  for (auto it = tied_properties.begin(); it != tied_properties.end(); ++it) {
     if (*it == property) {
       property->untie();
       tied_properties.erase(it);
diff --git a/src/FDM/JSBSim/input_output/FGPropertyManager.h b/src/FDM/JSBSim/input_output/FGPropertyManager.h
index 4015f9118..dfdf2fa02 100644
--- a/src/FDM/JSBSim/input_output/FGPropertyManager.h
+++ b/src/FDM/JSBSim/input_output/FGPropertyManager.h
@@ -97,7 +97,7 @@ class FGPropertyNode : public SGPropertyNode
     /**
      * Get the name of a node
      */
-    std::string GetName( void ) const;
+    const std::string& GetName( void ) const { return getNameString(); }
 
     /**
      * Get the name of a node without underscores, etc.
@@ -413,9 +413,21 @@ class FGPropertyManager
      *
      * Classes should use this function to release control of any
      * properties they are managing.
+     *
+     * @param name The property name to untie (full path).
      */
     void Untie (const std::string &name);
 
+    /**
+     * Untie a property from an external data source.
+     *
+     * Classes should use this function to release control of any
+     * properties they are managing.
+     *
+     * @param property A pointer to the property to untie.
+     */
+    void Untie (SGPropertyNode* property);
+
     /**
      * Unbind all properties bound by this manager to an external data source.
      *
diff --git a/src/FDM/JSBSim/input_output/FGScript.cpp b/src/FDM/JSBSim/input_output/FGScript.cpp
index 4db9865fd..fd5d309a7 100644
--- a/src/FDM/JSBSim/input_output/FGScript.cpp
+++ b/src/FDM/JSBSim/input_output/FGScript.cpp
@@ -150,7 +150,7 @@ bool FGScript::LoadScript(const SGPath& script, double default_dT,
 
   // Make sure that the desired time is reached and executed.
   EndTime += 0.99*FDMExec->GetDeltaT();
-  
+
   // read aircraft and initialization files
 
   element = document->FindElement("use");
@@ -193,7 +193,7 @@ bool FGScript::LoadScript(const SGPath& script, double default_dT,
   while (element) {
     if (!FDMExec->GetInput()->Load(element))
       return false;
- 
+
     element = document->FindNextElement("input");
   }
 
@@ -206,7 +206,7 @@ bool FGScript::LoadScript(const SGPath& script, double default_dT,
   while (element) {
     if (!FDMExec->GetOutput()->Load(element, scriptDir))
       return false;
- 
+
     element = document->FindNextElement("output");
   }
 
@@ -295,7 +295,7 @@ bool FGScript::LoadScript(const SGPath& script, double default_dT,
         }
         else
           newEvent->NotifyProperties.push_back(new FGPropertyValue(notifyPropertyName, PropertyManager));
-        
+
         string caption_attribute = notify_property_element->GetAttributeValue("caption");
         if (caption_attribute.empty()) {
           newEvent->DisplayString.push_back(notifyPropertyName);
@@ -496,7 +496,7 @@ bool FGScript::RunScript(void)
         } else  {
           cout << endl << underon
                << highint << thisEvent.Name << normint << underoff
-               << " (Event " << event_ctr << ")" 
+               << " (Event " << event_ctr << ")"
                << " executed at time: " << highint << currentTime << normint
                << endl;
         }
@@ -573,7 +573,7 @@ void FGScript::Debug(int from)
              << " = " << node->getDoubleValue()
              << endl;
       }
-      
+
       if (LocalProperties.empty()) cout << endl;
 
       for (unsigned i=0; i<Events.size(); i++) {
@@ -597,38 +597,38 @@ void FGScript::Debug(int from)
         for (unsigned j=0; j<Events[i].SetValue.size(); j++) {
           if (Events[i].SetValue[j] == 0.0 && Events[i].Functions[j] != 0L) {
             if (Events[i].SetParam[j] == 0) {
-              if (Events[i].SetParamName[j].size() == 0) {
-              cerr << fgred << highint << endl
-                   << "  An attempt has been made to access a non-existent property" << endl
-                   << "  in this event. Please check the property names used, spelling, etc."
-                   << reset << endl;
-              exit(-1);
+              if (Events[i].SetParamName[j].empty()) {
+                stringstream s;
+                s << "  An attempt has been made to access a non-existent property" << endl
+                  << "  in this event. Please check the property names used, spelling, etc.";
+                cerr << fgred << highint << endl << s.str() << reset << endl;
+                throw BaseException(s.str());
               } else {
                 cout << endl << "      set " << Events[i].SetParamName[j]
                      << " to function value (Late Bound)";
-            }
+              }
             } else {
-            cout << endl << "      set "
-                 << Events[i].SetParam[j]->GetRelativeName("/fdm/jsbsim/")
-                 << " to function value";
+              cout << endl << "      set "
+                   << Events[i].SetParam[j]->GetRelativeName("/fdm/jsbsim/")
+                   << " to function value";
             }
           } else {
             if (Events[i].SetParam[j] == 0) {
-              if (Events[i].SetParamName[j].size() == 0) {
-              cerr << fgred << highint << endl
-                   << "  An attempt has been made to access a non-existent property" << endl
-                   << "  in this event. Please check the property names used, spelling, etc."
-                   << reset << endl;
-              exit(-1);
+              if (Events[i].SetParamName[j].empty()) {
+                stringstream s;
+                s << "  An attempt has been made to access a non-existent property" << endl
+                  << "  in this event. Please check the property names used, spelling, etc.";
+                cerr << fgred << highint << endl << s.str() << reset << endl;
+                throw BaseException(s.str());
               } else {
                 cout << endl << "      set " << Events[i].SetParamName[j]
                      << " to function value (Late Bound)";
-            }
+              }
             } else {
-            cout << endl << "      set "
-                 << Events[i].SetParam[j]->GetRelativeName("/fdm/jsbsim/")
-                 << " to " << Events[i].SetValue[j];
-          }
+              cout << endl << "      set "
+                   << Events[i].SetParam[j]->GetRelativeName("/fdm/jsbsim/")
+                   << " to " << Events[i].SetValue[j];
+            }
           }
 
           switch (Events[i].Type[j]) {
diff --git a/src/FDM/JSBSim/input_output/FGfdmSocket.cpp b/src/FDM/JSBSim/input_output/FGfdmSocket.cpp
index 5fddce2b3..e6ebc91e1 100644
--- a/src/FDM/JSBSim/input_output/FGfdmSocket.cpp
+++ b/src/FDM/JSBSim/input_output/FGfdmSocket.cpp
@@ -81,12 +81,13 @@ static bool LoadWinSockDLL(int debug_lvl)
 }
 #endif
 
-FGfdmSocket::FGfdmSocket(const string& address, int port, int protocol)
+FGfdmSocket::FGfdmSocket(const string& address, int port, int protocol, int precision)
 {
   sckt = sckt_in = 0;
   Protocol = (ProtocolType)protocol;
   connected = false;
   struct addrinfo *addr = nullptr;
+  this->precision = precision;
 
   #if defined(_MSC_VER) || defined(__MINGW32__)
   if (!LoadWinSockDLL(debug_lvl)) return;
@@ -150,12 +151,13 @@ FGfdmSocket::FGfdmSocket(const string& address, int port, int protocol)
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 // assumes TCP or UDP socket on localhost, for inbound datagrams
-FGfdmSocket::FGfdmSocket(int port, int protocol)
+FGfdmSocket::FGfdmSocket(int port, int protocol, int precision)
 {
   sckt = -1;
   connected = false;
   Protocol = (ProtocolType)protocol;
   string ProtocolName;
+  this->precision = precision;
 
 #if defined(_MSC_VER) || defined(__MINGW32__)
   if (!LoadWinSockDLL(debug_lvl)) return;
@@ -338,7 +340,7 @@ void FGfdmSocket::Append(const char* item)
 void FGfdmSocket::Append(double item)
 {
   if (buffer.tellp() > 0) buffer << ',';
-  buffer << std::setw(12) << std::setprecision(7) << item;
+  buffer << std::setw(12) << std::setprecision(precision) << item;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/src/FDM/JSBSim/input_output/FGfdmSocket.h b/src/FDM/JSBSim/input_output/FGfdmSocket.h
index 4075040c1..7327088df 100644
--- a/src/FDM/JSBSim/input_output/FGfdmSocket.h
+++ b/src/FDM/JSBSim/input_output/FGfdmSocket.h
@@ -70,10 +70,8 @@ CLASS DECLARATION
 class FGfdmSocket : public FGJSBBase
 {
 public:
-  FGfdmSocket(const std::string& address, int port)
-    : FGfdmSocket(address, port, ptTCP) {}
-  FGfdmSocket(const std::string&, int, int);
-  FGfdmSocket(int, int);
+  FGfdmSocket(const std::string& address, int port, int protocol, int precision = 7);
+  FGfdmSocket(int port, int protocol, int precision = 7);
   ~FGfdmSocket();
   void Send(void);
   void Send(const char *data, int length);
@@ -104,6 +102,7 @@ private:
   struct sockaddr_in scktName;
   struct hostent *host;
   std::ostringstream buffer;
+  int precision;
   bool connected;
   void Debug(int from);
 };
diff --git a/src/FDM/JSBSim/math/FGCondition.cpp b/src/FDM/JSBSim/math/FGCondition.cpp
index 14f94fb24..c77341a94 100644
--- a/src/FDM/JSBSim/math/FGCondition.cpp
+++ b/src/FDM/JSBSim/math/FGCondition.cpp
@@ -124,7 +124,7 @@ FGCondition::FGCondition(const string& test, FGPropertyManager* PropertyManager,
 
   Comparison = mComparison[conditional];
   if (Comparison == ecUndef) {
-      std::invalid_argument("JSBSim FGCondition: Comparison operator: \""+conditional
+    throw std::invalid_argument("JSBSim FGCondition: Comparison operator: \""+conditional
           +"\" does not exist.  Please check the conditional.");
   }
 }
diff --git a/src/FDM/JSBSim/math/FGFunction.cpp b/src/FDM/JSBSim/math/FGFunction.cpp
index 22959aa76..c4cc3efa5 100644
--- a/src/FDM/JSBSim/math/FGFunction.cpp
+++ b/src/FDM/JSBSim/math/FGFunction.cpp
@@ -890,10 +890,8 @@ void FGFunction::Load(Element* el, FGPropertyValue* var, FGFDMExec* fdmex,
 
 FGFunction::~FGFunction()
 {
-  if (pNode && pNode->isTied()) {
-    string pName = pNode->GetFullyQualifiedName();
-    PropertyManager->Untie(pName);
-  }
+  if (pNode && pNode->isTied())
+    PropertyManager->Untie(pNode);
 
   Debug(1);
 }
diff --git a/src/FDM/JSBSim/math/FGMatrix33.cpp b/src/FDM/JSBSim/math/FGMatrix33.cpp
index f187d89d1..bcf5105f1 100644
--- a/src/FDM/JSBSim/math/FGMatrix33.cpp
+++ b/src/FDM/JSBSim/math/FGMatrix33.cpp
@@ -425,19 +425,16 @@ FGMatrix33 FGMatrix33::operator/(const double scalar) const
 {
   FGMatrix33 Quot;
 
-  if ( scalar != 0 ) {
-    double tmp = 1.0/scalar;
-    Quot.data[0] = data[0] * tmp;
-    Quot.data[3] = data[3] * tmp;
-    Quot.data[6] = data[6] * tmp;
-    Quot.data[1] = data[1] * tmp;
-    Quot.data[4] = data[4] * tmp;
-    Quot.data[7] = data[7] * tmp;
-    Quot.data[2] = data[2] * tmp;
-    Quot.data[5] = data[5] * tmp;
-    Quot.data[8] = data[8] * tmp;
-  } else
-    throw MatrixException{"Attempt to divide by zero in method FGMatrix33::operator/(const double scalar)"};
+  double tmp = 1.0/scalar;
+  Quot.data[0] = data[0] * tmp;
+  Quot.data[3] = data[3] * tmp;
+  Quot.data[6] = data[6] * tmp;
+  Quot.data[1] = data[1] * tmp;
+  Quot.data[4] = data[4] * tmp;
+  Quot.data[7] = data[7] * tmp;
+  Quot.data[2] = data[2] * tmp;
+  Quot.data[5] = data[5] * tmp;
+  Quot.data[8] = data[8] * tmp;
 
   return Quot;
 }
@@ -446,19 +443,16 @@ FGMatrix33 FGMatrix33::operator/(const double scalar) const
 
 FGMatrix33& FGMatrix33::operator/=(const double scalar)
 {
-  if ( scalar != 0 ) {
-    double tmp = 1.0/scalar;
-    data[0] *= tmp;
-    data[3] *= tmp;
-    data[6] *= tmp;
-    data[1] *= tmp;
-    data[4] *= tmp;
-    data[7] *= tmp;
-    data[2] *= tmp;
-    data[5] *= tmp;
-    data[8] *= tmp;
-  } else
-    throw MatrixException{"Attempt to divide by zero in method FGMatrix33::operator/=(const double scalar)"};
+  double tmp = 1.0/scalar;
+  data[0] *= tmp;
+  data[3] *= tmp;
+  data[6] *= tmp;
+  data[1] *= tmp;
+  data[4] *= tmp;
+  data[7] *= tmp;
+  data[2] *= tmp;
+  data[5] *= tmp;
+  data[8] *= tmp;
 
   return *this;
 }
diff --git a/src/FDM/JSBSim/math/FGMatrix33.h b/src/FDM/JSBSim/math/FGMatrix33.h
index 0ca03e1bc..8e7791644 100644
--- a/src/FDM/JSBSim/math/FGMatrix33.h
+++ b/src/FDM/JSBSim/math/FGMatrix33.h
@@ -42,8 +42,8 @@ INCLUDES
 
 #include <string>
 #include <iosfwd>
-#include <stdexcept>
 
+#include "FGJSBBase.h"
 #include "FGColumnVector3.h"
 
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -54,23 +54,6 @@ namespace JSBSim {
 
 class FGQuaternion;
 
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Exception convenience class.
-  */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DECLARATION: MatrixException
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class MatrixException : public std::runtime_error
-{
-public:
-  MatrixException(const std::string& msg) : std::runtime_error{msg} { }
-};
-
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 CLASS DOCUMENTATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
diff --git a/src/FDM/JSBSim/math/FGTable.cpp b/src/FDM/JSBSim/math/FGTable.cpp
index 0f3ab6226..ff88b1281 100644
--- a/src/FDM/JSBSim/math/FGTable.cpp
+++ b/src/FDM/JSBSim/math/FGTable.cpp
@@ -158,7 +158,7 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
     std::cerr << el->ReadFrom()
               <<"  An unknown table type attribute is listed: " << call_type
               << endl;
-    throw TableException("Unknown table type.");
+    throw BaseException("Unknown table type.");
   }
 
   // Determine and store the lookup properties for this table unless this table
@@ -199,7 +199,7 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
       } else if (lookup_axis == string("table")) {
         lookupProperty[eTable] = node;
       } else if (!lookup_axis.empty()) {
-        throw TableException("Lookup table axis specification not understood: " + lookup_axis);
+        throw BaseException("Lookup table axis specification not understood: " + lookup_axis);
       } else { // assumed single dimension table; row lookup
         lookupProperty[eRow] = node;
       }
@@ -232,7 +232,7 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
       std::cerr << el->ReadFrom()
                 << "No independentVars found, and table is not marked as internal,"
                 << " nor is it a 3D table." << endl;
-      throw TableException("No independent variable found for table.");
+      throw BaseException("No independent variable found for table.");
     }
   }
   // end lookup property code
@@ -245,8 +245,16 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
   }
 
   for (i=0; i<tableData->GetNumDataLines(); i++) {
-    buf << tableData->GetDataLine(i) << string(" ");
+    string line = tableData->GetDataLine(i);
+    if (line.find_first_not_of("0123456789.-+eE \t\n") != string::npos) {
+      cerr << " In file " << tableData->GetFileName() << endl
+           << "   Illegal character found in line "
+           << tableData->GetLineNumber() + i + 1 << ": " << endl << line << endl;
+      throw BaseException("Illegal character");
+    }
+    buf << line << " ";
   }
+
   switch (dimension) {
   case 1:
     nRows = tableData->GetNumDataLines();
@@ -267,12 +275,12 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
       if (nCols < 2) {
         std::cerr << tableData->ReadFrom()
                   << "Not enough columns in table data" << endl;
-        throw TableException("Not enough columns in table data.");
+        throw BaseException("Not enough columns in table data.");
       }
     } else {
       std::cerr << tableData->ReadFrom()
                 << "Not enough rows in table data" << endl;
-      throw TableException("Not enough rows in the table data.");
+      throw BaseException("Not enough rows in the table data.");
     }
 
     Type = tt2D;
@@ -330,7 +338,7 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
         if (nameel != 0) std::cerr << " of table in " << nameel->GetAttributeValue("name");
         std::cerr << ":" << reset << endl
                   << "  " << Data[b][1] << "<=" << Data[b-1][1] << endl;
-        throw TableException("Breakpoint lookup is not monotonically increasing");
+        throw BaseException("Breakpoint lookup is not monotonically increasing");
       }
     }
   }
@@ -346,7 +354,7 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
         if (nameel != 0) std::cerr << " of table in " << nameel->GetAttributeValue("name");
         std::cerr << ":" << reset << endl
                   << "  " << Data[0][c] << "<=" << Data[0][c-1] << endl;
-        throw TableException("FGTable: column lookup is not monotonically increasing");
+        throw BaseException("FGTable: column lookup is not monotonically increasing");
       }
     }
   }
@@ -362,7 +370,7 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el,
         if (nameel != 0) std::cerr << " of table in " << nameel->GetAttributeValue("name");
         std::cerr << ":" << reset << endl
                   << "  " << Data[r][0] << "<=" << Data[r-1][0] << endl;
-        throw TableException("FGTable: row lookup is not monotonically increasing");
+        throw BaseException("FGTable: row lookup is not monotonically increasing");
       }
     }
   }
@@ -393,10 +401,10 @@ FGTable::~FGTable()
   // Untie the bound property so that it makes no further reference to this
   // instance of FGTable after the destruction is completed.
   if (!Name.empty() && !internal) {
-    string tmp = mkPropertyName(nullptr, "");
+    string tmp = PropertyManager->mkPropertyName(Name, false);
     FGPropertyNode* node = PropertyManager->GetNode(tmp);
-    if (node->isTied())
-      PropertyManager->Untie(tmp);
+    if (node && node->isTied())
+      PropertyManager->Untie(node);
   }
 
   if (nTables > 0) {
@@ -653,33 +661,26 @@ void FGTable::Print(void)
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-string FGTable::mkPropertyName(Element* el, const std::string& Prefix)
-{
-  if (!Prefix.empty()) {
-    if (is_number(Prefix)) {
-      if (Name.find("#") != string::npos) { // if "#" is found
-        Name = replace(Name, "#", Prefix);
-      } else {
-        cerr << el->ReadFrom()
-              << "Malformed table name with number: " << Prefix
-              << " and property name: " << Name
-              << " but no \"#\" sign for substitution." << endl;
-      }
-    } else {
-      Name = Prefix + "/" + Name;
-    }
-  }
-
-  return PropertyManager->mkPropertyName(Name, false);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
 void FGTable::bind(Element* el, const string& Prefix)
 {
   typedef double (FGTable::*PMF)(void) const;
+
   if ( !Name.empty() && !internal) {
-    string tmp = mkPropertyName(el, Prefix);
+    if (!Prefix.empty()) {
+      if (is_number(Prefix)) {
+        if (Name.find("#") != string::npos) { // if "#" is found
+          Name = replace(Name, "#", Prefix);
+        } else {
+          cerr << el->ReadFrom()
+                << "Malformed table name with number: " << Prefix
+                << " and property name: " << Name
+                << " but no \"#\" sign for substitution." << endl;
+        }
+      } else {
+        Name = Prefix + "/" + Name;
+      }
+    }
+    string tmp = PropertyManager->mkPropertyName(Name, false);
 
     if (PropertyManager->HasNode(tmp)) {
       FGPropertyNode* _property = PropertyManager->GetNode(tmp);
@@ -689,7 +690,8 @@ void FGTable::bind(Element* el, const string& Prefix)
         throw("Failed to bind the property to an existing already tied node.");
       }
     }
-    PropertyManager->Tie( tmp, this, (PMF)&FGTable::GetValue);
+
+    PropertyManager->Tie(tmp, this, (PMF)&FGTable::GetValue);
   }
 }
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/src/FDM/JSBSim/math/FGTable.h b/src/FDM/JSBSim/math/FGTable.h
index d9cea9198..dceaf629a 100644
--- a/src/FDM/JSBSim/math/FGTable.h
+++ b/src/FDM/JSBSim/math/FGTable.h
@@ -226,19 +226,6 @@ combustion_efficiency = Lookup_Combustion_Efficiency->GetValue(equivalence_ratio
 @author Jon S. Berndt
 */
 
-/** Exception convenience class.
-  */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DECLARATION: TableException
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class TableException : public std::runtime_error
-{
-public:
-  TableException(const std::string& msg) : std::runtime_error{msg} { }
-};
-
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 CLASS DECLARATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
@@ -317,8 +304,6 @@ private:
   FGPropertyManager* const PropertyManager;
   std::string Name;
   void bind(Element* el, const std::string& Prefix);
-
-  std::string mkPropertyName(Element* el, const std::string& Prefix);
   void Debug(int from);
 };
 }
diff --git a/src/FDM/JSBSim/models/FGAerodynamics.cpp b/src/FDM/JSBSim/models/FGAerodynamics.cpp
index 2cb7cda7b..2de19dd5f 100644
--- a/src/FDM/JSBSim/models/FGAerodynamics.cpp
+++ b/src/FDM/JSBSim/models/FGAerodynamics.cpp
@@ -229,9 +229,13 @@ bool FGAerodynamics::Run(bool Holding)
     vForcesAtCG = Ts2b*vFnativeAtCG;
     break;
   default:
-    cerr << endl << "  A proper axis type has NOT been selected. Check "
-         << "your aerodynamics definition." << endl;
-    exit(-1);
+    {
+      stringstream s;
+      s << "  A proper axis type has NOT been selected. Check "
+        << "your aerodynamics definition.";
+      cerr << endl << s.str() << endl;
+      throw BaseException(s.str());
+    }
   }
   // Calculate aerodynamic reference point shift, if any. The shift takes place
   // in the structual axis. That is, if the shift is positive, it is towards the
@@ -257,7 +261,7 @@ bool FGAerodynamics::Run(bool Holding)
       vMomentsMRC(axis_ctr+1) += (*f)->GetValue();
     }
   }
-  
+
   // Transform moments to bodyXYZ if the moments are specified in stability or
   // wind axes
   vMomentsMRCBodyXYZ.InitMatrix();
@@ -272,13 +276,17 @@ bool FGAerodynamics::Run(bool Holding)
     vMomentsMRCBodyXYZ = in.Tw2b*vMomentsMRC;
     break;
   default:
-    cerr << endl << "  A proper axis type has NOT been selected. Check "
-         << "your aerodynamics definition." << endl;
-    exit(-1);
+    {
+      stringstream s;
+      s << "  A proper axis type has NOT been selected. Check "
+        << "your aerodynamics definition.";
+      cerr << endl << s.str() << endl;
+      throw BaseException(s.str());
+    }
   }
 
   vMoments = vMomentsMRCBodyXYZ + vDXYZcg*vForces; // M = r X F
-  
+
   // Now add the "at CG" values to base forces - after the moments have been
   // transferred.
   vForces += vForcesAtCG;
@@ -310,7 +318,7 @@ bool FGAerodynamics::Run(bool Holding)
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 FGColumnVector3 FGAerodynamics::GetForcesInStabilityAxes(void) const
-{ 
+{
   FGColumnVector3 vFs = Tb2s*vForces;
   // Need sign flips since drag is positive and lift is positive in stability axes
   vFs(eDrag) *= -1; vFs(eLift) *= -1;
@@ -403,15 +411,15 @@ bool FGAerodynamics::Load(Element *document)
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 //
 // This private class function checks to verify consistency in the choice of
-// aerodynamic axes used in the config file. One set of LIFT|DRAG|SIDE, or 
+// aerodynamic axes used in the config file. One set of LIFT|DRAG|SIDE, or
 // X|Y|Z, or AXIAL|NORMAL|SIDE must be chosen; mixed system axes are not allowed.
-// Note that if the "SIDE" axis specifier is entered first in a config file, 
+// Note that if the "SIDE" axis specifier is entered first in a config file,
 // a warning message will be given IF the AXIAL|NORMAL specifiers are also given.
 // This is OK, and the warning is due to the SIDE specifier used for both
 // the Lift/Drag and Axial/Normal axis systems.
-// Alternatively the axis name 'X|Y|Z or ROLL|PITCH|YAW' can be specified in 
+// Alternatively the axis name 'X|Y|Z or ROLL|PITCH|YAW' can be specified in
 // conjunction with a frame 'BODY|STABILITY|WIND', for example:
-// <axis name="X" frame="STABILITY"/> 
+// <axis name="X" frame="STABILITY"/>
 
 void FGAerodynamics::DetermineAxisSystem(Element* document)
 {
@@ -447,10 +455,12 @@ void FGAerodynamics::DetermineAxisSystem(Element* document)
              << " aircraft config file. (NORMAL AXIAL)" << endl;
       }
     } else { // error
-      cerr << endl << axis_element->ReadFrom()
-           << endl << "  An unknown axis type, " << axis << " has been specified"
-           << " in the aircraft configuration file." << endl;
-      exit(-1);
+      stringstream s;
+      s << axis_element->ReadFrom()
+        << endl << "  An unknown axis type, " << axis << " has been specified"
+        << " in the aircraft configuration file.";
+      cerr << endl << s.str() << endl;
+      throw BaseException(s.str());
     }
     axis_element = document->FindNextElement("axis");
   }
@@ -495,8 +505,10 @@ void FGAerodynamics::ProcessAxesNameAndFrame(eAxisType& axisType, const string&
                    << " aircraft config file." << validNames << " - WIND" << endl;
   }
   else {
-    cerr << endl << " Unknown axis frame type of - " << frame << endl;
-    exit(-1);
+    stringstream s;
+    s << " Unknown axis frame type of - " << frame;
+    cerr << endl << s.str() << endl;
+    throw BaseException(s.str());
   }
 }
 
@@ -596,7 +608,7 @@ void FGAerodynamics::bind(void)
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 //
-// Build transformation matrices for transforming from stability axes to 
+// Build transformation matrices for transforming from stability axes to
 // body axes and to wind axes. Where "a" is alpha and "B" is beta:
 //
 // The transform from body to stability axes is:
diff --git a/src/FDM/JSBSim/models/FGGasCell.cpp b/src/FDM/JSBSim/models/FGGasCell.cpp
index 3aecd5c05..9e201415e 100644
--- a/src/FDM/JSBSim/models/FGGasCell.cpp
+++ b/src/FDM/JSBSim/models/FGGasCell.cpp
@@ -86,8 +86,9 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, unsigned int num,
   if (element) {
     vXYZ = element->FindElementTripletConvertTo("IN");
   } else {
-    cerr << "Fatal Error: No location found for this gas cell." << endl;
-    exit(-1);
+    const string s("Fatal Error: No location found for this gas cell.");
+    cerr << el->ReadFrom() << endl << s << endl;
+    throw BaseException(s);
   }
   if ((el->FindElement("x_radius") || el->FindElement("x_width")) &&
       (el->FindElement("y_radius") || el->FindElement("y_width")) &&
@@ -126,7 +127,7 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, unsigned int num,
       MaxVolume = M_PI * Yradius * Zradius * Xwidth;
     } else {
       cerr << "Warning: Unsupported gas cell shape." << endl;
-      MaxVolume = 
+      MaxVolume =
         (4.0  * M_PI * Xradius * Yradius * Zradius / 3.0 +
          M_PI * Yradius * Zradius * Xwidth +
          M_PI * Xradius * Zradius * Ywidth +
@@ -137,8 +138,9 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, unsigned int num,
          Xwidth * Ywidth * Zwidth);
     }
   } else {
-    cerr << "Fatal Error: Gas cell shape must be given." << endl;
-    exit(-1);
+    const string s("Fatal Error: Gas cell shape must be given.");
+    cerr << el->ReadFrom() << endl << s << endl;
+    throw BaseException(s);
   }
   if (el->FindElement("max_overpressure")) {
     MaxOverpressure = el->FindElementValueAsNumberConvertTo("max_overpressure",
@@ -146,12 +148,12 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, unsigned int num,
   }
   if (el->FindElement("fullness")) {
     const double Fullness = el->FindElementValueAsNumber("fullness");
-    if (0 <= Fullness) { 
-      Volume = Fullness * MaxVolume; 
+    if (0 <= Fullness) {
+      Volume = Fullness * MaxVolume;
     } else {
       cerr << "Warning: Invalid initial gas cell fullness value." << endl;
     }
-  }  
+  }
   if (el->FindElement("valve_coefficient")) {
     ValveCoefficient =
       el->FindElementValueAsNumberConvertTo("valve_coefficient",
@@ -171,7 +173,7 @@ FGGasCell::FGGasCell(FGFDMExec* exec, Element* el, unsigned int num,
   if (Volume != 0.0) {
     // Calculate initial gas content.
     Contents = Pressure * Volume / (R * Temperature);
-    
+
     // Clip to max allowed value.
     const double IdealPressure = Contents * R * Temperature / MaxVolume;
     if (IdealPressure > Pressure + MaxOverpressure) {
@@ -263,7 +265,7 @@ void FGGasCell::Calculate(double dt)
   const size_t no_ballonets = Ballonet.size();
 
   //-- Read ballonet state --
-  // NOTE: This model might need a more proper integration technique. 
+  // NOTE: This model might need a more proper integration technique.
   double BallonetsVolume = 0.0;
   double BallonetsHeatFlow = 0.0;
   for (i = 0; i < no_ballonets; i++) {
@@ -282,7 +284,7 @@ void FGGasCell::Calculate(double dt)
       dU += HeatTransferCoeff[i]->GetValue();
     }
     // Don't include dt when accounting for adiabatic expansion/contraction.
-    // The rate of adiabatic cooling looks about right: ~5.4 Rankine/1000ft. 
+    // The rate of adiabatic cooling looks about right: ~5.4 Rankine/1000ft.
     if (Contents > 0) {
       Temperature +=
         (dU * dt - Pressure * dVolumeIdeal - BallonetsHeatFlow) /
@@ -354,7 +356,7 @@ void FGGasCell::Calculate(double dt)
   //-- Current buoyancy --
   // The buoyancy is computed using the atmospheres local density.
   Buoyancy = Volume * AirDensity * g;
-  
+
   // Note: This is gross buoyancy. The weight of the gas itself and
   // any ballonets is not deducted here as the effects of the gas mass
   // is handled by FGMassBalance.
@@ -372,7 +374,7 @@ void FGGasCell::Calculate(double dt)
     // Ellipsoid volume.
     Ixx = (1.0 / 5.0) * mass * (Yradius*Yradius + Zradius*Zradius);
     Iyy = (1.0 / 5.0) * mass * (Xradius*Xradius + Zradius*Zradius);
-    Izz = (1.0 / 5.0) * mass * (Xradius*Xradius + Yradius*Yradius);     
+    Izz = (1.0 / 5.0) * mass * (Xradius*Xradius + Yradius*Yradius);
   } else if  ((Xradius == 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&
               (Xwidth  != 0.0) && (Ywidth  == 0.0) && (Zwidth  == 0.0)) {
     // Cylindrical volume (might not be valid with an elliptical cross-section).
@@ -407,7 +409,7 @@ void FGGasCell::Calculate(double dt)
     // Add the mass, moment and inertia of any ballonets.
     for (i = 0; i < no_ballonets; i++) {
       Mass += Ballonet[i]->GetMass();
-       
+
       // Add ballonet moments due to mass (in the structural frame).
       gasCellM(eX) +=
         Ballonet[i]->GetXYZ(eX) * Ballonet[i]->GetMass()*slugtolb;
@@ -415,7 +417,7 @@ void FGGasCell::Calculate(double dt)
         Ballonet[i]->GetXYZ(eY) * Ballonet[i]->GetMass()*slugtolb;
       gasCellM(eZ) +=
         Ballonet[i]->GetXYZ(eZ) * Ballonet[i]->GetMass()*slugtolb;
-      
+
       gasCellJ += Ballonet[i]->GetInertia();
     }
   }
@@ -451,9 +453,9 @@ void FGGasCell::Debug(int from)
       cout << "      Cell location (X, Y, Z) (in.): " << vXYZ(eX) << ", " <<
         vXYZ(eY) << ", " << vXYZ(eZ) << endl;
       cout << "      Maximum volume: " << MaxVolume << " ft3" << endl;
-      cout << "      Relief valve release pressure: " << MaxOverpressure << 
+      cout << "      Relief valve release pressure: " << MaxOverpressure <<
         " lbs/ft2" << endl;
-      cout << "      Manual valve coefficient: " << ValveCoefficient << 
+      cout << "      Manual valve coefficient: " << ValveCoefficient <<
         " ft4*sec/slug" << endl;
       cout << "      Initial temperature: " << Temperature << " Rankine" <<
         endl;
@@ -471,7 +473,7 @@ void FGGasCell::Debug(int from)
   }
   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
   }
-  if (debug_lvl & 8 ) { // Runtime state variables    
+  if (debug_lvl & 8 ) { // Runtime state variables
       cout << "      " << type << " cell holds " << Contents << " mol " << endl;
       cout << "      Temperature: " << Temperature << " Rankine" << endl;
       cout << "      Pressure: " << Pressure << " lbs/ft2" << endl;
@@ -517,8 +519,9 @@ FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, unsigned int num,
   if (element) {
     vXYZ = element->FindElementTripletConvertTo("IN");
   } else {
-    cerr << "Fatal Error: No location found for this ballonet." << endl;
-    exit(-1);
+    const string s("Fatal Error: No location found for this ballonet.");
+    cerr << el->ReadFrom() << endl << s << endl;
+    throw BaseException(s);
   }
   if ((el->FindElement("x_radius") || el->FindElement("x_width")) &&
       (el->FindElement("y_radius") || el->FindElement("y_width")) &&
@@ -557,7 +560,7 @@ FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, unsigned int num,
       MaxVolume = M_PI * Yradius * Zradius * Xwidth;
     } else {
       cerr << "Warning: Unsupported ballonet shape." << endl;
-      MaxVolume = 
+      MaxVolume =
         (4.0  * M_PI * Xradius * Yradius * Zradius / 3.0 +
          M_PI * Yradius * Zradius * Xwidth +
          M_PI * Xradius * Zradius * Ywidth +
@@ -568,8 +571,9 @@ FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, unsigned int num,
          Xwidth * Ywidth * Zwidth);
     }
   } else {
-    cerr << "Fatal Error: Ballonet shape must be given." << endl;
-    exit(-1);
+    const string s("Fatal Error: Ballonet shape must be given.");
+    cerr << el->ReadFrom() << endl << s << endl;
+    throw BaseException(s);
   }
   if (el->FindElement("max_overpressure")) {
     MaxOverpressure = el->FindElementValueAsNumberConvertTo("max_overpressure",
@@ -577,12 +581,12 @@ FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, unsigned int num,
   }
   if (el->FindElement("fullness")) {
     const double Fullness = el->FindElementValueAsNumber("fullness");
-    if (0 <= Fullness) { 
-      Volume = Fullness * MaxVolume; 
+    if (0 <= Fullness) {
+      Volume = Fullness * MaxVolume;
     } else {
       cerr << "Warning: Invalid initial ballonet fullness value." << endl;
     }
-  }  
+  }
   if (el->FindElement("valve_coefficient")) {
     ValveCoefficient =
       el->FindElementValueAsNumberConvertTo("valve_coefficient",
@@ -600,7 +604,7 @@ FGBallonet::FGBallonet(FGFDMExec* exec, Element* el, unsigned int num,
   if (Volume != 0.0) {
     // Calculate initial air content.
     Contents = Pressure * Volume / (R * Temperature);
-    
+
     // Clip to max allowed value.
     const double IdealPressure = Contents * R * Temperature / MaxVolume;
     if (IdealPressure > Pressure + MaxOverpressure) {
@@ -746,7 +750,7 @@ void FGBallonet::Calculate(double dt)
     // Ellipsoid volume.
     Ixx = (1.0 / 5.0) * mass * (Yradius*Yradius + Zradius*Zradius);
     Iyy = (1.0 / 5.0) * mass * (Xradius*Xradius + Zradius*Zradius);
-    Izz = (1.0 / 5.0) * mass * (Xradius*Xradius + Yradius*Yradius);     
+    Izz = (1.0 / 5.0) * mass * (Xradius*Xradius + Yradius*Yradius);
   } else if  ((Xradius == 0.0) && (Yradius != 0.0) && (Zradius != 0.0) &&
               (Xwidth  != 0.0) && (Ywidth  == 0.0) && (Zwidth  == 0.0)) {
     // Cylindrical volume (might not be valid with an elliptical cross-section).
@@ -798,9 +802,9 @@ void FGBallonet::Debug(int from)
       cout << "        Location (X, Y, Z) (in.): " << vXYZ(eX) << ", " <<
         vXYZ(eY) << ", " << vXYZ(eZ) << endl;
       cout << "        Maximum volume: " << MaxVolume << " ft3" << endl;
-      cout << "        Relief valve release pressure: " << MaxOverpressure << 
+      cout << "        Relief valve release pressure: " << MaxOverpressure <<
         " lbs/ft2" << endl;
-      cout << "        Relief valve coefficient: " << ValveCoefficient << 
+      cout << "        Relief valve coefficient: " << ValveCoefficient <<
         " ft4*sec/slug" << endl;
       cout << "        Initial temperature: " << Temperature << " Rankine" <<
         endl;
@@ -818,7 +822,7 @@ void FGBallonet::Debug(int from)
   }
   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
   }
-  if (debug_lvl & 8 ) { // Runtime state variables    
+  if (debug_lvl & 8 ) { // Runtime state variables
       cout << "        Ballonet holds " << Contents <<
         " mol air" << endl;
       cout << "        Temperature: " << Temperature << " Rankine" << endl;
diff --git a/src/FDM/JSBSim/models/FGInput.cpp b/src/FDM/JSBSim/models/FGInput.cpp
index da5b8cd9a..1fe66c76e 100644
--- a/src/FDM/JSBSim/models/FGInput.cpp
+++ b/src/FDM/JSBSim/models/FGInput.cpp
@@ -43,7 +43,7 @@ INCLUDES
 #include "input_output/FGUDPInputSocket.h"
 #include "input_output/FGXMLFileRead.h"
 #include "input_output/FGModelLoader.h"
- 
+
 using namespace std;
 
 namespace JSBSim {
@@ -84,7 +84,7 @@ bool FGInput::Load(Element* el)
   Element* element = ModelLoader.Open(el);
 
   if (!element) return false;
-  
+
   FGModel::PreLoad(element, FDMExec);
 
   size_t idx = InputTypes.size();
@@ -152,6 +152,11 @@ bool FGInput::SetDirectivesFile(const SGPath& fname)
 {
   FGXMLFileRead XMLFile;
   Element* document = XMLFile.LoadXMLDocument(fname);
+  if (!document) {
+    stringstream s;
+    s << "Could not read directive file: " << fname;
+    throw BaseException(s.str());
+  }
   bool result = Load(document);
 
   if (!result)
diff --git a/src/FDM/JSBSim/models/FGLGear.cpp b/src/FDM/JSBSim/models/FGLGear.cpp
index 4d8d0f0ed..049b246a6 100644
--- a/src/FDM/JSBSim/models/FGLGear.cpp
+++ b/src/FDM/JSBSim/models/FGLGear.cpp
@@ -180,7 +180,12 @@ FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number, const struct Inputs&
 
   Element* element = el->FindElement("location");
   if (element) vXYZn = element->FindElementTripletConvertTo("IN");
-  else {cerr << "No location given for contact " << name << endl; exit(-1);}
+  else {
+    stringstream s;
+    s << "No location given for contact " << name;
+    cerr << endl << s.str() << endl;
+    throw BaseException(s.str());
+  }
   SetTransformType(FGForce::tCustom);
 
   element = el->FindElement("orientation");
diff --git a/src/FDM/JSBSim/models/FGMassBalance.cpp b/src/FDM/JSBSim/models/FGMassBalance.cpp
index bf58c3d27..b65a8e85b 100644
--- a/src/FDM/JSBSim/models/FGMassBalance.cpp
+++ b/src/FDM/JSBSim/models/FGMassBalance.cpp
@@ -117,7 +117,7 @@ static FGMatrix33 ReadInertiaMatrix(Element* document)
 
   // Transform the inertia products from the structural frame to the body frame
   // and create the inertia matrix.
-  if (document->GetAttributeValue("negated_crossproduct_inertia") == string("false")) 
+  if (document->GetAttributeValue("negated_crossproduct_inertia") == string("false"))
     return FGMatrix33( bixx,  bixy, -bixz,
                        bixy,  biyy,  biyz,
                       -bixz,  biyz,  bizz );
@@ -268,9 +268,11 @@ void FGMassBalance::AddPointMass(Element* el)
   Element* loc_element = el->FindElement("location");
   string pointmass_name = el->GetAttributeValue("name");
   if (!loc_element) {
-    cerr << el->ReadFrom() << "Pointmass " << pointmass_name
-         << " has no location." << endl;
-    exit(-1);
+    stringstream s;
+    s << el->ReadFrom() << "Pointmass " << pointmass_name
+         << " has no location.";
+    cerr << endl << s.str() << endl;
+    throw BaseException(s.str());
   }
 
   double w = el->FindElementValueAsNumberConvertTo("weight", "LBS");
@@ -449,11 +451,11 @@ void FGMassBalance::PointMass::bind(FGPropertyManager* PropertyManager,
 
 void FGMassBalance::GetMassPropertiesReport(int i)
 {
-  cout << endl << fgblue << highint 
+  cout << endl << fgblue << highint
        << "  Mass Properties Report (English units: lbf, in, slug-ft^2)"
        << reset << endl;
   cout << "                                  " << underon << "    Weight    CG-X    CG-Y"
-       << "    CG-Z         Ixx         Iyy         Izz" 
+       << "    CG-Z         Ixx         Iyy         Izz"
        << "         Ixy         Ixz         Iyz" << underoff << endl;
   cout.precision(1);
   cout << highint << setw(34) << left << "    Base Vehicle " << normint
@@ -469,13 +471,13 @@ void FGMassBalance::GetMassPropertiesReport(int i)
          << right << setw(10) << pmweight << setw(8) << pm->GetLocation()(eX)
          << setw(8) << pm->GetLocation()(eY) << setw(8) << pm->GetLocation()(eZ)
          << setw(12) << pm->GetPointMassMoI(1,1) << setw(12) << pm->GetPointMassMoI(2,2) << setw(12) << pm->GetPointMassMoI(3,3)
-         << setw(12) << pm->GetPointMassMoI(1,2) << setw(12) << pm->GetPointMassMoI(1,3) << setw(12) << pm->GetPointMassMoI(2,3) << endl;         
+         << setw(12) << pm->GetPointMassMoI(1,2) << setw(12) << pm->GetPointMassMoI(1,3) << setw(12) << pm->GetPointMassMoI(2,3) << endl;
   }
 
   cout << FDMExec->GetPropulsionTankReport();
 
   cout << "    " << underon << setw(136) << " " << underoff << endl;
-  cout << highint << left << setw(30) << "    Total: " << right << setw(14) << Weight 
+  cout << highint << left << setw(30) << "    Total: " << right << setw(14) << Weight
        << setw(8) << vXYZcg(eX)
        << setw(8) << vXYZcg(eY)
        << setw(8) << vXYZcg(eZ)
diff --git a/src/FDM/JSBSim/models/FGOutput.cpp b/src/FDM/JSBSim/models/FGOutput.cpp
index 23147f31a..f98abb5a6 100644
--- a/src/FDM/JSBSim/models/FGOutput.cpp
+++ b/src/FDM/JSBSim/models/FGOutput.cpp
@@ -173,8 +173,13 @@ bool FGOutput::SetDirectivesFile(const SGPath& fname)
 {
   FGXMLFileRead XMLFile;
   Element* document = XMLFile.LoadXMLDocument(fname);
-  bool result = Load(document);
+  if (!document) {
+    stringstream s;
+    s << "Could not read directive file: " << fname;
+    throw BaseException(s.str());
+  }
 
+  bool result = Load(document);
   if (!result)
     cerr << endl << "Aircraft output element has problems in file " << fname << endl;
 
diff --git a/src/FDM/JSBSim/models/FGPropagate.cpp b/src/FDM/JSBSim/models/FGPropagate.cpp
index 3b55ea515..5dc0f127b 100644
--- a/src/FDM/JSBSim/models/FGPropagate.cpp
+++ b/src/FDM/JSBSim/models/FGPropagate.cpp
@@ -688,7 +688,7 @@ void FGPropagate::WriteStateFile(int num)
 
   if (num == 0) return;
 
-  SGPath path = FDMExec->GetFullAircraftPath();
+  SGPath path = FDMExec->GetOutputPath();
 
   if (path.isNull()) path = SGPath("initfile.");
   else               path.append("initfile.");
@@ -968,16 +968,22 @@ void FGPropagate::Debug(int from)
   if (debug_lvl & 16) { // Sanity checking
     if (from == 2) { // State sanity checking
       if (fabs(VState.vPQR.Magnitude()) > 1000.0) {
-        cerr << endl << "Vehicle rotation rate is excessive (>1000 rad/sec): " << VState.vPQR.Magnitude() << endl;
-        exit(-1);
+        stringstream s;
+        s << "Vehicle rotation rate is excessive (>1000 rad/sec): " << VState.vPQR.Magnitude();
+        cerr << endl << s.str() << endl;
+        throw BaseException(s.str());
       }
       if (fabs(VState.vUVW.Magnitude()) > 1.0e10) {
-        cerr << endl << "Vehicle velocity is excessive (>1e10 ft/sec): " << VState.vUVW.Magnitude() << endl;
-        exit(-1);
+        stringstream s;
+        s << "Vehicle velocity is excessive (>1e10 ft/sec): " << VState.vUVW.Magnitude();
+        cerr << endl << s.str() << endl;
+        throw BaseException(s.str());
       }
       if (fabs(GetDistanceAGL()) > 1e10) {
-        cerr << endl << "Vehicle altitude is excessive (>1e10 ft): " << GetDistanceAGL() << endl;
-        exit(-1);
+        stringstream s;
+        s << "Vehicle altitude is excessive (>1e10 ft): " << GetDistanceAGL();
+        cerr << endl << s.str() << endl;
+        throw BaseException(s.str());
       }
     }
   }
diff --git a/src/FDM/JSBSim/models/flight_control/FGKinemat.cpp b/src/FDM/JSBSim/models/flight_control/FGKinemat.cpp
index 67634d704..039860f65 100644
--- a/src/FDM/JSBSim/models/flight_control/FGKinemat.cpp
+++ b/src/FDM/JSBSim/models/flight_control/FGKinemat.cpp
@@ -52,34 +52,29 @@ CLASS IMPLEMENTATION
 FGKinemat::FGKinemat(FGFCS* fcs, Element* element)
   : FGFCSComponent(fcs, element)
 {
-  Element *traverse_element, *setting_element;
-  double tmpDetent;
-  double tmpTime;
-
   CheckInputNodes(1, 1, element);
 
-  Detents.clear();
-  TransitionTimes.clear();
-
   Output = 0;
   DoScale = true;
 
   if (element->FindElement("noscale")) DoScale = false;
 
-  traverse_element = element->FindElement("traverse");
-  setting_element = traverse_element->FindElement("setting");
+  Element* traverse_element = element->FindElement("traverse");
+  Element* setting_element = traverse_element->FindElement("setting");
   while (setting_element) {
-    tmpDetent = setting_element->FindElementValueAsNumber("position");
-    tmpTime = setting_element->FindElementValueAsNumber("time");
+    double tmpDetent = setting_element->FindElementValueAsNumber("position");
+    double tmpTime = setting_element->FindElementValueAsNumber("time");
     Detents.push_back(tmpDetent);
     TransitionTimes.push_back(tmpTime);
     setting_element = traverse_element->FindNextElement("setting");
   }
 
   if (Detents.size() <= 1) {
-    cerr << "Kinematic component " << Name
-         << " must have more than 1 setting element" << endl;
-    exit(-1);
+    stringstream s;
+    s << "Kinematic component " << Name
+      << " must have more than 1 setting element";
+    cerr << element->ReadFrom() << endl << s.str() << endl;
+    throw BaseException(s.str());
   }
 
   bind(element);
diff --git a/src/FDM/JSBSim/models/flight_control/FGWaypoint.cpp b/src/FDM/JSBSim/models/flight_control/FGWaypoint.cpp
index 9981918f2..c813c0a4e 100644
--- a/src/FDM/JSBSim/models/flight_control/FGWaypoint.cpp
+++ b/src/FDM/JSBSim/models/flight_control/FGWaypoint.cpp
@@ -182,7 +182,24 @@ bool FGWaypoint::Run(void )
   double target_longitude_rad = target_longitude->GetValue() * target_longitude_unit;
   source.SetPosition(source_longitude_rad, source_latitude_rad, radius);
 
+  if (fabs(target_latitude_rad) > M_PI/2.0) {
+    cerr << endl;
+    cerr << "Target latitude in waypoint \"" << Name << "\" must be less than or equal to 90 degrees." << endl;
+    cerr << "(is longitude being mistakenly supplied?)" << endl;
+    cerr << endl;
+    throw("Waypoint target latitude exceeded 90 degrees.");
+  }
+
+  if (fabs(source_latitude_rad) > M_PI/2.0) {
+    cerr << endl;
+    cerr << "Source latitude in waypoint \"" << Name << "\" must be less than or equal to 90 degrees." << endl;
+    cerr << "(is longitude being mistakenly supplied?)" << endl;
+    cerr << endl;
+    throw("Source latitude exceeded 90 degrees.");
+  }
+
   if (WaypointType == eHeading) {     // Calculate Heading
+
     double heading_to_waypoint_rad = source.GetHeadingTo(target_longitude_rad,
                                                          target_latitude_rad);
 
@@ -190,11 +207,12 @@ bool FGWaypoint::Run(void )
     else               Output = heading_to_waypoint_rad;
 
   } else {                            // Calculate Distance
+
     double wp_distance = source.GetDistanceTo(target_longitude_rad,
                                               target_latitude_rad);
-
     if (eUnit == eMeters) Output = FeetToMeters(wp_distance);
     else                  Output = wp_distance;
+
   }
 
   Clip();
diff --git a/src/FDM/JSBSim/models/propulsion/FGEngine.cpp b/src/FDM/JSBSim/models/propulsion/FGEngine.cpp
index 0432b85fc..0241c2837 100644
--- a/src/FDM/JSBSim/models/propulsion/FGEngine.cpp
+++ b/src/FDM/JSBSim/models/propulsion/FGEngine.cpp
@@ -56,8 +56,6 @@ FGEngine::FGEngine(int engine_number, struct Inputs& input)
   : in(input), EngineNumber(engine_number)
 {
   Type = etUnknown;
-  X = Y = Z = 0.0;
-  EnginePitch = EngineYaw = 0.0;
   SLFuelFlowMax = 0.0;
   FuelExpended = 0.0;
   MaxThrottle = 1.0;
@@ -113,18 +111,6 @@ unsigned int FGEngine::GetSourceTank(unsigned int i) const
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-void FGEngine::SetPlacement(const FGColumnVector3& location,
-                            const FGColumnVector3& orientation)
-{
-  X = location(eX);
-  Y = location(eY);
-  Z = location(eZ);
-  EnginePitch = orientation(ePitch);
-  EngineYaw = orientation (eYaw);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
 double FGEngine::GetThrust(void) const 
 {
   return Thruster->GetThrust();
@@ -200,19 +186,17 @@ bool FGEngine::Load(FGFDMExec *exec, Element *engine_element)
   // Call ModelFunctions loader
   FGModelFunctions::Load(engine_element, exec, to_string((int)EngineNumber));
 
-// Find and set engine location
-
+  // If engine location and/or orientation is supplied issue a warning since they
+  // are ignored. What counts is the location and orientation of the thruster.
   local_element = parent_element->FindElement("location");
-  if (local_element)  location = local_element->FindElementTripletConvertTo("IN");
-//  else      cerr << "No engine location found for this engine." << endl;
-// Jon: The engine location is not important - the nozzle location is.
+  if (local_element)
+    cerr << local_element->ReadFrom()
+         << "Engine location ignored, only thruster location is used." << endl;
 
   local_element = parent_element->FindElement("orient");
-  if (local_element)  orientation = local_element->FindElementTripletConvertTo("RAD");
-//  else          cerr << "No engine orientation found for this engine." << endl;
-// Jon: The engine orientation has a default and is not normally used.
-
-  SetPlacement(location, orientation);
+  if (local_element)
+    cerr << local_element->ReadFrom()
+         << "Engine orientation ignored, only thruster orientation is used." << endl;
 
   // Load thruster
   local_element = parent_element->FindElement("thruster");
diff --git a/src/FDM/JSBSim/models/propulsion/FGEngine.h b/src/FDM/JSBSim/models/propulsion/FGEngine.h
index 26a011eb5..5edc751ce 100644
--- a/src/FDM/JSBSim/models/propulsion/FGEngine.h
+++ b/src/FDM/JSBSim/models/propulsion/FGEngine.h
@@ -71,17 +71,6 @@ CLASS DOCUMENTATION
     <h3>Configuration File Format:</h3>
 @code
         <engine file="{string}">
-            <location unit="{IN | M}">
-                <x> {number} </x>
-                <y> {number} </y>
-                <z> {number} </z>
-            </location>
-            <!-- optional orientation definition -->
-            <orient unit="{RAD | DEG}">
-                <roll>  {number} </roll>
-                <pitch> {number} </pitch>
-                <yaw> {number} </yaw>
-            </orient>
             <feed> {integer} </feed>
             ... optional more feed tank index numbers ... 
             <thruster file="{string}">
@@ -183,9 +172,6 @@ public:
 
   virtual double GetThrust(void) const;
     
-  /// Sets engine placement information
-  virtual void SetPlacement(const FGColumnVector3& location, const FGColumnVector3& orientation);
-
   /** The fuel need is calculated based on power levels and flow rate for that
       power level. It is also turned from a rate into an actual amount (pounds)
       by multiplying it by the delta T and the rate.
@@ -216,9 +202,6 @@ protected:
   std::string Name;
   const int   EngineNumber;
   EngineType Type;
-  double X, Y, Z;
-  double EnginePitch;
-  double EngineYaw;
   double SLFuelFlowMax;
   double MaxThrottle;
   double MinThrottle;
diff --git a/src/FDM/JSBSim/models/propulsion/FGForce.cpp b/src/FDM/JSBSim/models/propulsion/FGForce.cpp
index 9dba77b32..30350350b 100644
--- a/src/FDM/JSBSim/models/propulsion/FGForce.cpp
+++ b/src/FDM/JSBSim/models/propulsion/FGForce.cpp
@@ -106,8 +106,11 @@ const FGMatrix33& FGForce::Transform(void) const
   case tNone:
     return mT;
   default:
-    cout << "Unrecognized tranform requested from FGForce::Transform()" << endl;
-    exit(1);
+    {
+      const string s("Unrecognized tranform requested from FGForce::Transform()");
+      cout << s << endl;
+      throw BaseException(s);
+    }
   }
 }
 
diff --git a/src/FDM/JSBSim/models/propulsion/FGNozzle.cpp b/src/FDM/JSBSim/models/propulsion/FGNozzle.cpp
index 11c546bd9..976533960 100644
--- a/src/FDM/JSBSim/models/propulsion/FGNozzle.cpp
+++ b/src/FDM/JSBSim/models/propulsion/FGNozzle.cpp
@@ -57,13 +57,14 @@ FGNozzle::FGNozzle(FGFDMExec* FDMExec, Element* nozzle_element, int num)
   if (nozzle_element->FindElement("area"))
     Area = nozzle_element->FindElementValueAsNumberConvertTo("area", "FT2");
   else {
-    cerr << "Fatal Error: Nozzle exit area must be given in nozzle config file." << endl;
-    exit(-1);
+    const string s("Fatal Error: Nozzle exit area must be given in nozzle config file.");
+    cerr << s << endl;
+    throw BaseException(s);
   }
 
   Thrust = 0;
   Type = ttNozzle;
-  
+
   Debug(0);
 }
 
diff --git a/src/FDM/JSBSim/models/propulsion/FGTank.cpp b/src/FDM/JSBSim/models/propulsion/FGTank.cpp
index 957e49226..30d09eaed 100644
--- a/src/FDM/JSBSim/models/propulsion/FGTank.cpp
+++ b/src/FDM/JSBSim/models/propulsion/FGTank.cpp
@@ -193,10 +193,9 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
     switch (grainType) {
       case gtCYLINDRICAL:
         if (Radius <= InnerRadius) {
-          cerr << element_Grain->ReadFrom()
-               << "The bore diameter should be smaller than the total grain diameter!"
-               << endl;
-          exit(-1);
+          const string s("The bore diameter should be smaller than the total grain diameter!");
+          cerr << element_Grain->ReadFrom() << endl << s << endl;
+          throw BaseException(s);
         }
         Volume = M_PI * Length * (Radius*Radius - InnerRadius*InnerRadius); // cubic inches
         break;
@@ -207,10 +206,11 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
         Volume = 1;  // Volume is irrelevant for the FUNCTION type, but it can't be zero!
         break;
       case gtUNKNOWN:
-        cerr << el->ReadFrom()
-             << "Unknown grain type found in this rocket engine definition."
-             << endl;
-        exit(-1);
+        {
+          const string s("Unknown grain type found in this rocket engine definition.");
+          cerr << el->ReadFrom() << endl << s << endl;
+          throw BaseException(s);
+        }
     }
     Density = (Capacity*lbtoslug)/Volume; // slugs/in^3
   }
@@ -221,7 +221,7 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
   Area = 40.0 * pow(Capacity/1975, 0.666666667);
 
   // A named fuel type will override a previous density value
-  if (!strFuelName.empty()) Density = ProcessFuelName(strFuelName); 
+  if (!strFuelName.empty()) Density = ProcessFuelName(strFuelName);
 
   bind(PropertyManager);
 
@@ -375,8 +375,9 @@ void FGTank::CalculateInertias(void)
     } else if (Contents <= 0.0) {
       Volume = 0;
     } else {
-      cerr << endl << "  Solid propellant grain density is zero!" << endl << endl;
-      exit(-1);
+      const string s("  Solid propellant grain density is zero!");
+      cerr << endl << s << endl;
+      throw BaseException(s);
     }
 
     switch (grainType) {
@@ -399,9 +400,11 @@ void FGTank::CalculateInertias(void)
       Izz = function_izz->GetValue()*izz_unit;
       break;
     default:
-      cerr << "Unknown grain type found." << endl;
-      exit(-1);
-      break;
+      {
+        const string s("Unknown grain type found.");
+        cerr << s << endl;
+        throw BaseException(s);
+      }
     }
 
   } else { // assume liquid propellant: shrinking snowball
@@ -415,7 +418,7 @@ void FGTank::CalculateInertias(void)
 
 double FGTank::ProcessFuelName(const std::string& name)
 {
-   if      (name == "AVGAS")    return 6.02; 
+   if      (name == "AVGAS")    return 6.02;
    else if (name == "JET-A")    return 6.74;
    else if (name == "JET-A1")   return 6.74;
    else if (name == "JET-B")    return 6.48;
@@ -442,7 +445,7 @@ double FGTank::ProcessFuelName(const std::string& name)
    else if (name == "AVCAT")    return 6.81;
    else {
      cerr << "Unknown fuel type specified: "<< name << endl;
-   } 
+   }
 
    return 6.6;
 }