/**
 * Updates each of the derived times from its parent time.
 *
 * \par Assumptions and Limitations
 *  - All but TimeDyn must have a parent; this should be defined by the
 *             user, or if not, already determined when the update_tree was built
 */


/**
 * Given a value of seconds, propagate to days.
 *
 * \par Assumptions and Limitations
 *  - 86400 seconds = 1 day
 * \param[in] new_seconds new value for seconds\n Units: s
 */


/**
 * Given a value of days, propagate to seconds.
 *
 * \par Assumptions and Limitations
 *  - 86400 seconds = 1 day
 * \param[in] new_days new value for days\n Units: day
 */


/**
 * Destroy a JeodBaseTime
 */


/**
 * Construct a TimeConverter_TAI_UT1
 */


/**
 * Initialize the converter.
 *
 * \par Assumptions and Limitations
 *  - None
 * \param[in] parent_ptr Time used to initialize the converter
 * \param[in] child_ptr Other Time used to initialize the converter
 * \param[in] int_dir Conversion direction: +1 a=parent; -1 b=parent; 0 error
 */


/**
 * The conversion from Atomic Time (TAI) to Universal Time (UT1)
 * involves the addition of value that is a continuous function of TAI.
 * That value is tabulated at regular points of TAI.  This function
 * initializes that table and sets the preliminary values.
 *
 * \par Assumptions and Limitations
 *  - The table does not go into the future.
 */


/**
 * Convert from TimeTAI to TimeUT1.
 *
 * \par Assumptions and Limitations
 *  - Time class MET is based on time class TAI, and counts the elapsed
 *                TAI time only
 */


/**
 * Convert from TimeUT1 to TimeTAI.
 *
 * \par Assumptions and Limitations
 *  - Time class MET is based on time class TAI, and counts the elapsed
 *                TAI time only
 */


/**
 * Used when time reverses direction.
 * Checks whether the table lookup function is using input values that
 * are outside the scope of the table, and sets the flags appropriately
 *
 * \par Assumptions and Limitations
 *  - None
 */


/**
 * Destroy a TimeConverter_TAI_UT1
 */


/**
 * Protection against inheriting nonsense function
 *
 * \par Assumptions and Limitations
 *  - GMST does not have a conventional calendar
 */


/******************************************************************************
 Function: TimeConverter_TAI_TDB
 Purpose: Construct a TimeConverter_TAI_TDB object
 ******************************************************************************/


/******************************************************************************
 Function: initialize
 Purpose:  Initialize the converter.
           \param[in] parent_ptr Time used to initialize the converter
           \param[in] child_ptr Other Time used to initialize the converter
           \param[in] int_dir Conversion direction: +1 a=parent; -1 b=parent; 0 error
 ******************************************************************************/


/******************************************************************************
 Function: set_a_to_b_offset
 Purpose: Calculate and set the a_to_b_offset
 ******************************************************************************/


/******************************************************************************
 Function: convert_a_to_b
 Purpose: Convert from TimeTAI to TimeTDB
 ******************************************************************************/


/******************************************************************************
 Function: convert_b_to_a
 Purpose: Convert from TimeTDB to TimeTAI
 ******************************************************************************/


/**
 * Construct a TimeConverter_UT1_GMST
 */


/**
 * Convert from TimeUT1 to TimeGMST.
 *
 * \par Assumptions and Limitations
 *  - None
 */


/**
 * Construct a TimeConverter_TAI_GPS
 */


/**
 * Construct a TimeConverter_Dyn_TDB
 */


/**
 * Initialize the converter.
 * \param[in] parent_ptr Time used to initialize the converter
 * \param[in] child_ptr Other Time used to initialize the converter
 * \param[in] int_dir Conversion direction: +1 a=parent; -1 b=parent; 0 error
 */


/**
 * Updates to current time
 */


/**
 * Construct a Time_TT
 */


/**
 * Recursively adds elements to the update tree.
 * If the "parent" to a time-type is defined, adds the "parent" then
 * returns to adding the "child" type.
 * If the "parent" is not defined it searches for a suitable "parent"
 * from the types already in the tree.  If that search is successful,
 * it adds the "child" to the tree, otherwise it returns without
 * change.
 *
 * \par Assumptions and Limitations
 *  - None
 * \param[in] seeking_status status-value for auto-seek.
 * \param[in] time_manager_init The TM initializer.
 */


/**
 * Construct a TimeConverter_TAI_TT
 */


/**
 * Construct a TimeConverter_Dyn_UDE
 */


/**
 * Convert from TimeDyn to TimeUDE.
 *
 * \par Assumptions and Limitations
 *  - Time class UDE is based on time class TAI, and counts the elapsed
 *             TAI time only
 */


/**
 * The master program behind the initialization of the time types and
 * the time converters
 *
 * \par Assumptions and Limitations
 *  - None
 * \param[in,out] time_mgr The time manager
 */


/**
 * A number of checks that the setup is self-consistent
 *
 * \par Assumptions and Limitations
 *  - None
 */


/**
 * The converter registry accounts for all of the converter functions
 * that provide conversions between time types.
 * This function populates that registry so that the existence of
 * functional converter functions can be tested efficiently.
 *
 * \par Assumptions and Limitations
 *  - None
 */


/**
 * To verify that there are no incompatibilities between specific
 * converters
 *
 * \par Assumptions and Limitations
 *  - The instance of TimeTAI, if it exists, has name "TAI"
 *  - The instance of TimeUTC, if it exists, has name "UTC"
 *  - The instance of TimeUT1, if it exists, has name "UT1"
 */


/**
 * Build and verify a "tree-like" structure to ensure that all time
 * representations can be initialized from the single "initializer"
 * representation.
 * Create_init_tree builds the tree, using add_type_initialize to
 * populate the tree recursively.
 *
 * \par Assumptions and Limitations
 *  - This is vastly improved if the user defines the parent type
 *                 "initialize_from" for each time representation, except the
 *                 top-level initializer type
 *  - Otherwise, the code will build the tree automatically, but it
 *                 takes longer and may be less than ideal
 */


/**
 * Initialize each time type so that it has a starting value
 * corresponding to dynamic_time = 0 and such that the starting values
 * are consistent.
 * Initialize_time_types repetitively calls initialize_from_parent for
 * each time type; initialize_from_parent recursively adds types moving
 * up the tree as necessary
 *
 * \par Assumptions and Limitations
 *  - An initializer time defined by the user
 */


/**
 * (To verify that the update procedures have a tree-like structure,
 * and that all time representations can be updated from the dynamic time.)
 *  (Contains 3 functions - create_update_tree builds the tree, populated
 *   recursively by add_type_update.  record_update records the update paths
 * to facilitate runtime updates)
 *
 * \par Assumptions and Limitations
 *  - None
 */


/**
 * Reorganizes the update list according to initialization status
 */


/**
 * Takes a calculated converter index - calculated by combining the two
 * time-type indices - and return the index in the time_manager's vector of
 * converters that corresponds to those two time-types.
 * @return Index corresponding to TimeConverter
 * \param[in] index_in Index of object
 */


/**
 * Takes a calculated converter index - calculated by combining the
 * indices of two time-types, a "from" and a "to" - and returns the direction
 * needed to use the appropriate converter to go from "from" to "to".
 *
 * \par Assumptions and Limitations
 *  - Returns 0 if no suitable converter available at initialization
 * @return Index corresponding to TimeConverter
 * \param[in] index Index of object
 */


/**
 * Takes a calculated converter index - calculated by combining the
 * indices of two time-types, a "from" and a "to" - and returns the direction
 * needed to use the appropriate converter to go from "from" to "to".
 *
 * \par Assumptions and Limitations
 *  - Returns 0 if no suitable converter available at update
 * @return Index corresponding to TimeConverter
 * \param[in] index Index of object
 */


/**
 * Returns the status of a time-type
 * @return Integer corresponding to Status
 * \param[in] index Index of object
 */


/**
 * Modifies the status of one time-type to be one higher than that of
 * another type for initialization purposes
 * \param[in] index_slave Index of object
 * \param[in] index_master Index of object
 */


/**
 * Destroy a TimeManagerInit
 */


/**
 * Construct a Time_TAI
 */


/**
 * Construct a TimeConverter_TAI_UTC
 */


/**
 * The conversion from Atomic Time (TAI) to Universal Time (UTC)
 * involves the addition of leap seconds. The number of leap seconds at any
 * given (historical) time is provided in a table. This function initializes
 * that table and sets the preliminary values.
 *
 * \par Assumptions and Limitations
 *  - The table does not go into the future.
 */


/**
 * Convert from TimeTAI to TimeUTC.
 *
 * \par Assumptions and Limitations
 *  - Time class MET is based on time class TAI, and counts the
 *                 elapsed TAI time only
 */


/**
 * Convert from TimeUTC to TimeTAI.
 */


/**
 * Used when time reverses direction.
 * Checks whether the table lookup function is using input values that
 *            are outside the scope of the table, and sets the flags appropriately
 */


/**
 * Destroy a TimeConverter_TAI_UTC
 */


/**
 * Construct a Time_UT1
 */


/**
 * Construct a Time_TDB
 */


/**
 * Return a pointer to the TimeConverter object with the provided index,
 * or NULL if no such TimeConverter object has been registered.
 * @return TimeConverter object corresponding to index in the vector of such types.
 * \param[in] index Index of object
 */


/**
 * Return a pointer to the Time object with the provided name,
 * or NULL if no such Time object has been registered.
 * @return Time object corresponding to name
 * \param[in] name Name of time object
 */


/**
 * Return a pointer to the Time object with the provided index,
 * or NULL if no such Time object has been registered.
 * @return Time object corresponding to name
 * \param[in] index Name of time object
 */


/**
 * Registers the time representation with the Time Manager.  Records the
 * frequency at which the representation should be updated.
 * \par Assumptions and Limitations
 *  - None
 * \param[in,out] time_ref reference to time-type being registered
 */


/**
 * Reassigns the name to the type; this is used when there are multiple instances of a time type such as a MET or UDE.
 * Registers the time representation with the Time Manager.  Records the frequency at which the representation should be
 * updated. \par Assumptions and Limitations
 *  - None
 * \param[in,out] time_ref reference to time-type being registered
 * \param[in] name name of the instance being registered.
 */


/**
 * Registers the time converters with the Time Manager.
 *
 * \par Assumptions and Limitations
 *  - the input values name_a and name_b will only be used if the
 *                converter-type names have not already been set.  So registering a
 *                Dyn_UDE converter will ignore name_a completely because it is
 *                already set.
 * \param[in,out] conv_ref ref. to converter being registered
 * \param[in] name_a name of type-a in the converter
 * \param[in] name_b name of type-b in the converter
 */


/**
 * Tests for the existence in the registry of time types that inherit
 * from TimeStandard.
 *
 * \par Assumptions and Limitations
 *  - None
 * @return true/false
 */


/**
 * Uses a string comparison to find where in the TimeManager record a
 * time type of a particular name is located.  Returns the integer
 * corresponding to the time type's index in the TimeManager.
 *
 * \par Assumptions and Limitations
 *  - Rarely used.  If the time type address is known, it is easier to
 *    access its index "time_type.index" which returns the same result.
 * @return index value of time-type
 * \param[in] name name of time-type
 */


/**
 * This function manages the time update process.
 * It first updates each of the representations of time, calling the
 * update functions for each time representation in dependency order.
 * After updating the representations of time, the function then
 * updates the dynamic time scale factor. Time change subscribers are
 * notified if the scale factor has changed.
 *
 * Note that by updating first and then checking for a change in the
 * rate/direction of time means that these changes in rate/direction
 * will first take affect on the next call to update_time or update.
 *
 * \par Assumptions and Limitations
 *  - Derived times must have a parent; this should be defined by the
 *         user, or if not, already determined when the update_tree was built
 * \param[in] current_simtime input time from simulation engine; it always runs forwards and allows for determination of
 * what has and has not already been done.\n Units: s
 */


/**
 * Update each of the representations of time, calling the update
 * functions for each such representation in dependency order.
 *
 * Note that this function only does the first part of the task
 * performed by TimeManager::update. It does not check for changes
 * in the rate/direction of time.
 *
 * \par Assumptions and Limitations
 *  - Derived times must have a parent; this should be defined by the
 *         user, or if not, already determined when the update_tree was built
 * \param[in] current_simtime input time from simulation engine; it always runs forwards and allows for determination of
 * what has and has not already been done.\n Units: s
 */


/**
 * This function is called when the simulation reverses direction (in
 * time.  It calls each time converter that uses a table lookup to check
 * whether the current time is off the end of the table.  This is
 * important because once the off-table-end flag is set, the only reason
 * to unset it is when time reverses direction)
 *
 * \par Assumptions and Limitations
 *  - None
 */


/**
 * Destroy a TimeManager
 */


/**
 * Construct a TimeConverter_Dyn_TAI
 */


/**
 * Convert from TimeDyn to TimeTAI.
 */


/**
 * Adds a UDE type to the initialization tree when it is appropriate to
 * do so.
 *
 * \par Assumptions and Limitations
 *  - The time type from which the UDE updates must be in the tree
 *           above the UDE.
 *  - If the time type in which the epoch is defined is another UDE, it
 *           also must be in the tree above this UDE
 *  - This function is only called when the UDE is NOT being used to
 *           initialize the simulation.
 * \param[in] seeking_status An indicator of relative level of progression in the tree.
 * \param[in] time_manager_init The TM initializer.
 */


/**
 * Converts the time, as specified in the epoch time-type to the
 * update_from time-type.  This sets the update_from time at the epoch
 * of "this", and allows for the initialization of the converter.
 *
 * \par Assumptions and Limitations
 *  - That there is a converter available to do this in one step
 *  - Future work may include an extension to this routine to cover
 *           other cases.
 * \param[in] epoch_ptr pointer to the epoch time-type
 * \param[in] update_from_ptr pointer to the time-type from which this time-type will be updated.
 * \param[in] time_manager_init The TM initializer.
 */


/**
 * Initializes this time-type
 *
 * \par Assumptions and Limitations
 *  - The subject object has a parent, a time-type with which it ticks.
 *            This has already been tested for.
 * \param[in] time_manager_init The TM initializer.
 */


/**
 * Each time type is initialized from its parent in the initialization
 * tree, except one.  In order to have an absolute reference time, one of
 * the time types must be defined ahead of time.  This is called the
 * initializer time. This function initializes the initializer time.
 * \param[in] time_manager_init The TM initializer.
 */


/**
 * To set the times in the epoch time type coincident with the
 * zero-point of this time-type
 *
 * \par Assumptions and Limitations
 *  - "This" is being defined by epoch.
 * \param[in] epoch_ptr pointer to the epoch time-type
 */


/**
 * Temporarily overwrites the simulation data in time type "epoch"
 * with the epoch value.
 *
 * \par Assumptions and Limitations
 *  - "Epoch" is DynTime
 * \param[in] epoch_ptr pointer to the epoch time-type
 */


/**
 * Overwrites the data in time type "epoch" with that in this class that
 * specifies the epoch.
 *
 * \par Assumptions and Limitations
 *  - "Epoch" is Absolute Derived Time
 * \param[in] epoch_ptr pointer to the epoch time-type
 */


/**
 * Overwrites the data in time type "epoch" with that in this class
 * that specifies the epoch.
 *
 * \par Assumptions and Limitations
 *  - "Epoch" is a User-Defined-Epoch Time.
 * \param[in] epoch_ptr pointer to the epoch time-type
 */


/**
 * Sets the initial value of this type from the myriad of initialization
 * options
 *
 * \par Assumptions and Limitations
 *  - At least one of the following is non-zero:
 *           initializing value, clock_day, clock_hour, clock_minute,
 *           clock_second, seconds, days
 */


/**
 * Given a seconds value, sets days and clock values
 * \param[in] new_days new value for days\n Units: day
 */


/**
 * Given a seconds value, sets days and clock values
 * \param[in] new_seconds new value for seconds\n Units: s
 */


/**
 * sets the decimal representation of time by the clock
 *
 * \par Assumptions and Limitations
 *  - 24 hrs = 1 day; 60 minutes - 1 hour ; 60 seconds = 1 minute
 */


/**
 * sets the initial epoch value
 *
 * \par Assumptions and Limitations
 *  - Assumes that the number that is passed in is correctly entered with
 *         the correct units interpretation.
 * \param[in] simtime Used to verify that this is at initialization
 * \param[in] epoch the value to be used.
 */


/**
 * converts the decimal seconds value to a clock interface
 *
 * \par Assumptions and Limitations
 *  - 24 hrs = 1 day; 60 minutes - 1 hour ; 60 seconds = 1 minute
 */


/**
 * Verifies that the epoch assignments are legitimate, and tests for the
 * presence and legitimacy of values for defining the epoch.
 */


/**
 * Verifies that any assignment to initialize_from is flagged as
 * inappropriate, and tests for the presence of initializing data.
 */


/**
 * Ensures that the time-type identified as "update_from" is legitimate
 */


/**
 * Register a Planet object with the Dynamics Manager.
 * \param[in,out] grav_source_in GravitySource object
 * \param[in,out] dyn_manager Dynamics manager
 */


/**
 * Initialize a Planet object.
 *
 * \par Assumptions and Limitations
 *  - Planet::register_model has already been invoked.
 */


/**
 * Set the fixed transformation from J2000 to alt_inertial
 *
 * \par Assumptions and Limitations
 *  - Method only works once
 * \param[in] trans trans J2000->alt_inertial
 */


/**
 * Use the celestial and ecliptic poles to set the conventional fixed
 * transformation from J2000 to alt_inertial
 *
 * \par Assumptions and Limitations
 *  - Method only works once
 *  - Celestial and ecliptic poles are not the same
 * \param[in] cp celestial pole unit vector
 * \param[in] ep Ecliptic pole unit vector
 */


/**
 * Set the fixed transformation from pfix to alt_pfix
 *
 * \par Assumptions and Limitations
 *  - Method only works once
 * \param[in] trans trans pfix->alt_pfix
 */


/**
 * Calculate the current transformation from J2000 to alt_pfix
 * using the fixed transformation between pfix and alt_pfix
 *
 * \par Assumptions and Limitations
 *      calculates J2000 to alt_pfix using a fixed
 *      transformation from pfix to alt_pfix
 */


/**
 * Register a BasePlanet object with the Ephemerides Manager.
 * \param[in,out] ephem_manager Ephemerides Manager
 */


/*****************************************************************************
initialize
Purpose:(initializes the WindVelocity model with these data.
         WindVelocity has only pointers to the data, so set those pointers to the
         data elements from this class.)
Limitations: (First method is deprecated)
*****************************************************************************/


/**
 * Copy Constructor
 * \param[in] rhs The METAtmosphereStateVars to copy
 */


/*****************************************************************************
update
Purpose:(Main executable for METAtmosphereThermal, returns the temperature
         at the current altitude.)
Notes: (The temperature at 125 km is a function of the exospheric
        temperature and is empirically derived)
*****************************************************************************/


/*****************************************************************************
compute_temperature

PURPOSE:
   (Calculates the temperature at a specified altitude
    using equation (10) for altitudes between 90 and 125 km and equation (13)
    for altitudes greater than 125 km, from Smithsonian Astrophysical
    Observatory Report 313, 1970.)

NOTES: (This method is used to generate the temperature at the current
        altitude AND at other reference altitudes in support of other aspects
        of the model.  Therefore, it is necessary to have the altitude as a
        passed argument.  The argument should not be assumed to be the vehicle
        altitude because it often is not.)

REFERENCE:
   (((Jacchia, L.G.) (New Static Models of the Thermosphere and
      Exosphere with Empirical Temperature Profiles) (Smithsonian
      Astrophysical Observatory Special Report No. 313) (--) (1970) (--))
    ((Jacchia, L.G.) (Revised Static Models of the Termosphere
      and Exosphere with Emperical Temperature Profiles)
      (Smithsonian Astrophysical Observatory Report No. 332) (--)
      (1971) (--)))

Assumptions:(( All temperature profiles:
               - start at height 90km with value 183K and gradient 0.
               - rise to an inflection point at 125 km
               - become asymptotic to the exospheric temperature above 125 km.)
             ( The temperature T_125 and gradient T_grad_125 at the
               inflection point are functions of the exospheric temperature.)
            )

*****************************************************************************/


/****************************************************************************
update_atmosphere:
Purpose:
   Front-end to the computation of the METAtmosphere at the current time
   Inserts the results into the AtmosphereState pointed to by
   state. This function is for a general AtmosphereState.
   \param[in] pfix_pos Geodetic altitude, latitude and longitude.
   \param[out] state Where the state results will be stored.
****************************************************************************/


/*****************************************************************************
modify_densities
Purpose:(
    Modifies the densities:
    - mass density below 170km
    - mass and Helium densities above base-fairing-height)
*****************************************************************************/


/*****************************************************************************
Function: compute_solar_angles, formerly atmos_MET_TME

PURPOSE:
   (Subroutine 'atmos_MET_TME' performs the calculations of the solar
    declination angle and solar hour angle.)

REFERENCE:
   (((Jacchia, L.G.) (New Static Models of the Thermosphere and
      Exosphere with Empirical Temperature Profiles) (Smithsonian
      Astrophysical Observatory Special Report No. 313) (--) (1970) (--))
    ((Jacchia, L.G.) (Revised Static Models of the Termosphere
      and Exosphere with Emperical Temperature Profiles)
      (Smithsonian Astrophysical Observatory Report No. 332) (--)
      (1971) (--)))

ASSUMPTIONS AND LIMITATIONS:
   ((Too many to enumerate here.))

******************************************************************************/


/*****************************************************************************
compute_exospheric_temperature, formerly atmos_MET_TINF

PURPOSE:
   (Calculates the exospheric temperature
    according to L. Jacchia, Smithsonian Astrophysical Observatory 313,
    1970.  Subroutine 'atmos_MET_TME' performs the calculations of the solar
    declination angle and solar hour angle.)

REFERENCE:
   (((Jacchia, L.G.) (New Static Models of the Thermosphere and
      Exosphere with Empirical Temperature Profiles) (Smithsonian
      Astrophysical Observatory Special Report No. 313) (--) (1970) (--))
    ((Jacchia, L.G.) (Revised Static Models of the Termosphere
      and Exosphere with Emperical Temperature Profiles)
      (Smithsonian Astrophysical Observatory Report No. 332) (--)
      (1971) (--)))

ASSUMPTIONS AND LIMITATIONS:
   ((Too many to enumerate here.))

******************************************************************************/


/*****************************************************************************
jacchia, formerly atmos_MET_JAC

PURPOSE:
   (Calculates the temperature, the total
    density DENS and its logarithm DL, the mean molecular weight EM, the
    individual species number densities for N, O2, O, A, HE and H [each
    preceded with an 'A'] at altitude Z given the exospheric temperature T.
    This subroutine uses the subroutine 'atmos_MET_GAUSS', 'atmos_MET_TEMP'
    and 'atmos_MET_MOL_WT'.)

REFERENCE:
   (((Jacchia, L.G.) (New Static Models of the Thermosphere and
      Exosphere with Empirical Temperature Profiles) (Smithsonian
      Astrophysical Observatory Special Report No. 313) (--) (1970) (--))
    ((Jacchia, L.G.) (Revised Static Models of the Termosphere
      and Exosphere with Emperical Temperature Profiles)
      (Smithsonian Astrophysical Observatory Report No. 332) (--)
      (1971) (--)))

ASSUMPTIONS AND LIMITATIONS:
   ((Too many to enumerate here.))

*****************************************************************************/


/*****************************************************************************

Function: compute_seasonal_latitude_variation

PURPOSE:
   (Computes the seasonal-latitudinal variation
    of density in the lower thermosphere in accordance with L. Jacchia,
    Smithsonian Astrophysical Observatory 332, 1971. This affects the
    densities between 90 and 170 km. This subroutine need not be called for
    densities above 170 km, because no effect is observed.  The variation
    should be computed after the calculation of density due to temperature
    variations and the density ( DEN ) must be in the form of a base 10 log.
    No adjustments are made to the temperature or constituent number
    densities in the region affected by this variation.)

REFERENCE:
   (((Jacchia, L.G.) (New Static Models of the Thermosphere and
      Exosphere with Empirical Temperature Profiles) (Smithsonian
      Astrophysical Observatory Special Report No. 313) (--) (1970) (--))
    ((Jacchia, L.G.) (Revised Static Models of the Termosphere
      and Exosphere with Emperical Temperature Profiles)
      (Smithsonian Astrophysical Observatory Report No. 332) (--)
      (1971) (--)))

ASSUMPTIONS AND LIMITATIONS:
   ((Too many to enumerate here.))

*****************************************************************************/


/*****************************************************************************

Function: compute_seasonal_lat_variation_He (was atmos_MET_SLVH)

PURPOSE:
   (Computes the seasonal-latitudinal variation
    of the helium number density according to L. Jacchia, Smithsonian
    Astrophysical Observatory 332, 1971. This correction is not important
    below about 500 km.)

REFERENCE:
   (((Jacchia, L.G.) (Revised Static Models of the Thermosphere
      and Exosphere with Emperical Temperature Profiles)
      (Smithsonian Astrophysical Observatory Report No. 332) (--)
      (1971) (--)))

ASSUMPTIONS AND LIMITATIONS:
   ((Too many to enumerate here.))

*****************************************************************************/


/*****************************************************************************

Function: atmos_MET_FAIR5

PURPOSE:
   (Subroutine 'atmos_MET_FAIR5' fairs between the region above 500 km -- which
    invokes the seasonal-latitudinal variation of the helium number density --
    and the region below, which does not invoke any
    seasonal-latitudinal variation at all.)

REFERENCE:
   (((Jacchia, L.G.) (New Static Models of the Thermosphere and
      Exosphere with Empirical Temperature Profiles) (Smithsonian
      Astrophysical Observatory Special Report No. 313) (--) (1970) (--))
    ((Jacchia, L.G.) (Revised Static Models of the Termosphere
      and Exosphere with Emperical Temperature Profiles)
      (Smithsonian Astrophysical Observatory Report No. 332) (--)
      (1971) (--)))

ASSUMPTIONS AND LIMITATIONS:
   ((Too many to enumerate here.))

*****************************************************************************/


/*****************************************************************************
compute_mol_wt, formerly atmos_MET_MOL_WT

PURPOSE:
   (Subroutine 'atmos_MET_MOL_WT' calculates the molecular weight for
    altitudes between 90 and 105 km according to equation (1) of Smithsonian
    Astrophysical Observatory Report 313, 1970.
    Otherwise, mean molar amss is set to the constant as defined in this class.)

REFERENCE:
   (((Jacchia, L.G.) (New Static Models of the Thermosphere and
      Exosphere with Empirical Temperature Profiles) (Smithsonian
      Astrophysical Observatory Special Report No. 313) (--) (1970) (--))
    ((Jacchia, L.G.) (Revised Static Models of the Termosphere
      and Exosphere with Emperical Temperature Profiles)
      (Smithsonian Astrophysical Observatory Report No. 332) (--)
      (1971) (--)))

ASSUMPTIONS AND LIMITATIONS:
   ((Too many to enumerate here.))

*****************************************************************************/


/*****************************************************************************
apply_gauss_quadrature

PURPOSE:
   (Subdivides total integration-altitude range
    into intervals suitable for applying Gaussian Quadrature, sets the number
    of points for integration for each sub-interval, and then perform
    Gaussian Quadrature.)

REFERENCE:
   (((Jacchia, L.G.) (New Static Models of the Thermosphere and
      Exosphere with Empirical Temperature Profiles) (Smithsonian
      Astrophysical Observatory Special Report No. 313) (--) (1970) (--))
    ((Jacchia, L.G.) (Revised Static Models of the Termosphere
      and Exosphere with Emperical Temperature Profiles)
      (Smithsonian Astrophysical Observatory Report No. 332) (--)
      (1971) (--)))

ASSUMPTIONS AND LIMITATIONS:
   ((Too many to enumerate here.))

*****************************************************************************/


/**
 * Updates the METAtmosphereState from the METAtmosphere pointed to
 * by atmos_model_. This is a specific function for the case of
 * an METAtmosphere state updating an METAtmosphere
 * \param[in] atmos_model_ METAtmosphere Model.
 * \param[in] pfix_pos_ Current vehicle position.
 */


/**
 * Updates the METAtmosphereState from the METAtmosphere pointed to
 * by class member atmos_model using class member pointer pfix_pos.
 * This is a specific function for the case of an METAtmosphere state
 * updating an METAtmosphere when constructed with the pointers set.
 */


/**
 * Copy Constructor
 * \param[in] rhs The AtmosphereState to copy from
 */


/**
 * Updates the invoking atmosphere state, using the atmosphere
 * model pointed to by atmos_model, and calculated at the planet
 * fixed position pointed to by pfix_pos. Note that any type
 * inheriting from Atmosphere can be sent in for atmos_model.
 * \param[in] atmos_model_ Atmosphere model.
 * \param[in] pfix_pos_ Planetary fixed position.
 */


/**
 * Updates the invoking atmosphere state, using the atmosphere
 * model pointed to by atmos, and calculated at the planet
 * fixed position pointed to by pfix_pos. Note that any type
 * inheriting from Atmosphere can used as the Atmosphere pointer
 * but only the values associated with AtmosphereState will be
 * copied back out.
 */


/**
 * Updates the wind portion of the invoking atmosphere state,
 * using the wind model pointed to by wind_vel, calculated at the
 * inertial position given by inrtl_pos and the altitude given
 * \param[in] wind_vel Wind velocity model.
 * \param[in] inrtl_pos Current inertial position.\n Units: M
 * \param[in] altitude Geodetic (elliptic) altitude.\n Units: M
 */


/**
 * Virtual function to define the interface for inheriting functions
 * \param[in] position The position of the vehicle, however the specific implementation defines it
 * \param[in] altitude The altitude of the vehicle, however the specific implementation defines it
 * \param[out] wind_inertial The wind applied to the craft, in the inertial frame
 */


/**
 * Updates the wind velocity from the parameters given.
 * \param[in] inertial_pos The inertial position of the vehicle\n Units: M
 * \param[in] altitude The altitude of the vehicle\n Units: M
 * \param[out] wind_inertial The wind, in the inertial frame, applied to the vehicle\n Units: M/s
 */


/**
 * @brief  Checking whether the component is thermalized during this step.
 * @note
 * @param  &p_cur: starting point of this step
 * @param  &p_inter: intermediate states of this step
 * @param  &should_follow_equilibrium: whether the component is already keep thermalized within this step
 * @retval The vector<bool> indicates whether this component is thermalized but not considered in follow_equilibrium
 */


// Count number of event in a given time bin


// Fast gamma (multiple)


// Compute mean Gamma Rate (Yang)


// NHPP_lik with median Gamma Rates


// Precompute some values


// Define a specie epoch span and estimated time in each epoch


// HPP_vec_lik using MEAN Yang discrete gamma rates


// HPP_vec_lik using MEDIAN Yang discrete gamma rates


// These routines are for reading blocks on and off disk without DIRECTIO


// not DISK
// These routines are for reading in and out of a big array in memory


// TODO: This handling of the memory allocation required for plans
// doesn't seem exceptionally safe.  Is it really true that "new Complx"
// always returns a suitably aligned variable?
// And we're trusting that every 2-d plane ends up aligned, although
// this has a better chance of being ok because we require an even PPD.


// Write a suitable header into the output file


// Returns GiB size of allocated buffer


// Remove files named ic_* and zeldovich.* from the current directory


// A recursive mkdir function.
// This is semantically similar to Python's os.makedirs()
// from https://gist.github.com/JonathonReinhart/8c0d90191c38af2dcadb102c4e202950


// Find the root in a filename, stripping off extension and directory, if present


// returns length of header, including the ^B^B at end, and leave the
//     file open, at the end of the header.


// look up an id in the symbol table, adding one if necessary;
//   return a pointer to the entry if there


// generate a warning for variables which have not recieved a value and for
//   which a warning was desired


// reset the parser -- remove all entries from the symbol table
//   so that we can start anew...


// install a variable in the symbol table and initialize it's entry


// Otherwise, we fall back to bit twiddling
// implementations


/*!
 * \brief Checks for command files written to the local directory.
 * If a file STOP was written and is readable, then a bailout with restart writing is initiated.
 * If a file KILL was written and is readable, then a bailout without a restart is initiated.
 * If a file SAVE was written and is readable, then restart writing without a bailout is initiated.
 * If a file DOLB was written and is readable, then a new load balancing is initiated.
 * To avoid bailing out upfront on a new run the files are renamed with the date to keep a trace.
 * The function should only be called by MASTER_RANK. This ensures that resetting P::bailout_write_restart works.
 */


/*!
  \brief Collective exit on error functions

  If any process(es) have a false success values then the program will
  abort and write out the message to the logfile
  \param success This process' value for successful execution
  \param message Error message to be shown upon failure
  \param comm MPI comm
  \return Returns true if the operation was successful
*/


/*!
 \brief Read cell ID's
 Read in cell ID's from file. Note: Uses the newer version of vlsv parallel reader
 \param file Some vlsv reader with a file open
 \param fileCells Vector in whic to store the cell ids
 \param masterRank The simulation's master rank id (Vlasiator uses 0, which should be the default)
 \param comm MPI comm (MPI_COMM_WORLD should be the default)
*/


/* Read the total number of velocity blocks per spatial cell in the spatial mesh.
 * The returned value for each cell is a sum of the velocity blocks associated in each particle species.
 * The value is used to calculate an initial load balance after restart.
 * @param file Some vlsv reader with a file open (can be old or new vlsv reader)
 * @param nBlocks Vector for holding information on cells and the number of blocks in them -- this function saves data here
 * @param masterRank The master rank of this process (Vlasiator uses masterRank = 0 and so it should be the default)
 * @param comm MPI comm
 * @return Returns true if the operation was successful
 @ @see exec_readGrid
*/


/** Read velocity block data of all existing particle species.
 * @param file VLSV reader.
 * @param meshName Name of the spatial mesh.
 * @param fileCells Vector containing spatial cell IDs.
 * @param localCellStartOffset Offset into fileCells, determines where the cells belonging
 * to this process start.
 * @param localCells Number of spatial cells assigned to this process.
 * @param mpiGrid Parallel grid library.
 * @return If true, velocity block data was read successfully.*/


/*! Reads cell parameters from the file and saves them in the right place in mpiGrid
 \param file Some parallel vlsv reader with a file open
 \param fileCells List of all cell ids
 \param localCellStartOffset Offset in the fileCells list for this process ( calculated so that the amount of blocks is distributed somewhat evenly between processes)
 \param localCells The amount of cells to read in this process after localCellStartOffset
 \param cellParamsIndex The parameter of the cell index e.g. CellParams::RHOM
 \param expectedVectorSize The amount of elements in the parameter (parameter can be a scalar or a vector of size N)
 \param mpiGrid Vlasiator's grid (the parameters are saved here)
 \return Returns true if the operation is successful
 */


/*! Read an ionosphere variable from the given vlsv file.
 * Note that only singular floating point values (no vectors) can be read at this time.
 * \param file VLSV parallel reader with a file open.
 * \param variableName Name of the variable in the file
 * \param grid the ionosphere grid that data will be deposited into
 * \param index index into the nodes' parameters array, where the data will end up.
 */


/*!
\brief Read in state from a vlsv file in order to restart simulations
\param mpiGrid Vlasiator's grid
\param name Name of the restart file e.g. "restart.00052.vlsv"
 \return Returns true if the operation was successful
 \sa readGrid
 */


//FIXME, readGrid has no support for checking or converting endianness
/*!
\brief Read in state from a vlsv file in order to restart simulations
\param mpiGrid Vlasiator's grid
\param name Name of the restart file e.g. "restart.00052.vlsv"
*/


/*!
\brief Refine the grid to be identical to the file's
\param mpiGrid Vlasiator's grid
\param name Name of the restart file e.g. "restart.00052.vlsv"
*/


/** Destructor for class Logger. Destructor only calls Logger::close.
 */


/** Close a logfile which has been previously opened with
 * Logger::open.
 * @return If true, the logfile was closed successfully.
 */


/** Write the Logger stream buffer into the output file. The stream buffer
 * is emptied if the write succeeded. The rank of the writing MPI process and
 * current time and date, as given by ctime, are written before the user-defined
 * message.
 * @return If true, the buffer was written successfully and buffer was emptied.
 */


/*!
   \brief Open a logfile

   This class can be used to write out logfiles. Only master rank
   writes out anythin, all other processes will not do anything when
   they attempt to use the logger, but it is still perfectly legal for
   them to call it.

   \param[in] comm  MPI communicator for processes that are able to call this logger
   \param[in] MASTERRANK The rank that does all communication.
   \param[in] fname The name of the logfile.
   \param[in] append Is the file appended (true), or overwritten (false)
   \return If true, the file was opened successfully and Logger is ready for use.
 */


// initialize velocity grid of spatial cells before creating cells in dccrg.initialize


/*
  Adjust sparse velocity space to make it consistent in all 6 dimensions.

  Further documentation in grid.h
*/


/*! Shrink to fit velocity space data to save memory.
 * \param mpiGrid Spatial grid
 */


/*! Estimates memory consumption and writes it into logfile. Collective operation on MPI_COMM_WORLD
 * \param mpiGrid Spatial grid
 */


/*! Deallocates all block data in remote cells in order to save
 *  memory
 * \param mpiGrid Spatial grid
 */


/*
Updates velocity block lists between remote neighbors and prepares local
copies of remote neighbors for receiving velocity block data.
*/


/*
  Set stencils. These are the stencils (in 2D, real ones in 3D of
  course). x are stencil neighbor to cell local cell o:

NEAREST SYSBOUNDARIES  (nearest neighbor)
-----------
  xxx
  xox
  xxx
-----------

EXTENDED_SYSBOUNDARIES (second nearest neighbor, also in diagonal)
-----------
  xxxxx
  xxxxx
  xxoxx
  xxxxx
  xxxxx
-----------

VLASOV
-----------
    x
    x
  xxoxx
    x
    x
-----------

VLASOV_{XYZ}
-----------
 xxoxxx
-----------

VLASOV_TARGET_{XYZ}
-----------
  xox

-----------

DIST_FUNC  (Includes all cells which should know about each others blocks and have space for them. VLASOV + SYSBOUNDARIES.
-----------
    x
   xxx
  xxoxx
   xxx
    x

-----------

FULL (Includes all possible communication, possible AMR extension)
-----------
    A
  xxxxx
  xxxxx
 AxxoxxA
  xxxxx
  xxxxx
    A
-----------

SHIFT_M_X    ox
SHIFT_P_X   xo
 Y, Z in the same way
*/


/*! Measures memory consumption and writes it into logfile.
 *  Collective operation on MPI_COMM_WORLD
 *  extra_bytes is used for additional buffer for the high water mark,
 *  for example when estimating refinement memory usage
 */


/** Get the total number of velocity blocks in this cell, summed over
     * all existing particle populations.
     * @return Total number of velocity blocks in the cell.*/


/*!
    Returns the indices of given velocity block
    */


/*!
    Returns the edge where given velocity block starts.
    */


/*!
    Returns the edge where given velocity block ends.
    */


/*!
    Returns the indices of given velocity cell
    */


/*!
    Returns the velocity cell at given indices or error_velocity_cell
    */


/*!
    Returns the velocity cell at given location or
    error_velocity_cell if outside of given velocity block.
    */


/*!
    Returns the edge where given velocity cell in the given velocity block starts.
    TODO: move these to velocity cell class?
    */


/*!
    Returns the edge where given velocity cell in the given velocity block ends.
    */


/*!
    Returns the edge where given velocity cell in the given velocity block starts.
    */


/*!
    Returns the number of given velocity blocks that exist.
    */


/*!
    Returns the number of existing velocity blocks.
    */


/*!
    Sets the given value to a velocity cell at given coordinates.
    *
    Creates the velocity block at given coordinates if it doesn't exist.
    */


/*! Sets the value of a particular cell in a block. The block is
    *  created if it does not exist. This version is faster than
    *  the velocity value based version.
    *
    * This function is not thread safe due to the creation of
    * blocks.
    *
    \param block Block index of velocity-cell
    \param cell  Cell index (0..WID3-1) of velocity-cell in block
    \param value Value that is set for velocity-cell
    */


/*!
    Increments the value of velocity cell at given coordinate-
    *
    Creates the velocity block at given coordinates if it doesn't exist.
    */


/*!
    Increments the value of velocity cell at given index
    *
    Creates the velocity block if it doesn't exist.
    */


/*!
    * Gets the value of a velocity cell at given coordinates.
    *
    * Returns 0 if it doesn't exist.
    */


/*!
    Removes all velocity blocks from this spatial cell and frees memory in the cell
    */


/*!
    Return the memory consumption in bytes as reported using the size()
    functions of the containers in spatial cell
    */


/*!
    Return the memory consumption in bytes as reported using
    the size() functions of the containers in spatial cell
    */


/*!
    Adds an empty velocity block into this spatial cell.
    Returns true if given block was added or already exists.
    Returns false if given block is invalid or would be outside
    of the velocity grid.
    */


/*!
    Removes given block from the velocity grid.
    Does nothing if given block doesn't exist.
    */


/*!
    Sets the type of data to transfer by mpi_datatype.
    */


/*!
    Returns true if given velocity block has enough of a distribution function.
    Returns false if the value of the distribution function is too low in every
    sense in given block.
    Also returns false if given block doesn't exist or is an error block.
    */


/** Get MPI datatype for sending the cell data.
    * @param cellID Spatial cell (dccrg) ID.
    * @param sender_rank Rank of the MPI process sending data from this cell.
    * @param receiver_rank Rank of the MPI process receiving data to this cell.
    * @param receiving If true, this process is receiving data.
    * @param neighborhood Neighborhood ID.
    * @return MPI datatype that transfers the requested data.*/


/** Prepares this spatial cell to receive the velocity grid over MPI.
    * At this stage we have received a new block list over MPI into
    * mpi_velocity_block_list, but the rest of the cell structures
    * have not been adapted to this new list. Here we re-initialize
    * the cell with empty blocks based on the new list.*/


/** Set the particle species SpatialCell should use in functions that
    * use the velocity mesh.
    * @param popID Population ID.
    * @return If true, the new species is in use.*/


/** Set maximum translation timestep for a particle species.
    * This function is called during Vlasov translation.
    * @param popID ID of the particle species.
    * @param value New maximum timestep.*/


/** Set maximum acceleration timestep for a particle species.
    * This function is called during Vlasov acceleration.
    * @param popID ID of the particle species.
    * @param value New maximum timestep.*/


/**  Purges extra capacity from block vectors. It sets size to
    * num_blocks * block_allocation_factor (if capacity greater than this),
    * and also forces capacity to this new smaller value.
    * @return True on success.*/


/** Update the two lists containing blocks with content, and blocks without content.
    * @see adjustVelocityBlocks */


/** Initialize the velocity mesh of the chosen particle population.
    * @param popID Population ID.
    * @param v_limits Velocity mesh min/max limits.
    * @param meshSize Number of blocks in each coordinate direction at base grid level.
    * @param blockSize Number of velocity cells in a block per coordinate direction.
    * @param f_min Sparse mesh threshold value.
    * @param maxRefLevel Maximum allowed mesh refinement level.*/


/** Updates minValue based on algorithm value from parameters (see parameters.cpp).
    * @param popID ID of the particle species.*/


/** Constructor for class ReadParameters.
 * The constructor defines some default parameters and parses the input files.
 * @param cmdargc Command line argc.
 * @param cmdargv Command line argv.
 */


/** Add a new composing input parameter.
 * Note that parse must be called in order for the input file(s) to be re-read.
 * Only needs to be called by root process.
 * It can be defined multiple times and are all returned as a vector.
 * @param name The name of the parameter, as given in the input file(s).
 * @param desc Description for the parameter.
 */


/** Write the descriptions of known input options to standard output if
 * an option called "help" has been read, and exit in that case.
 */


/** Write version information to standard output if
 * an option called "version" has been read.
 * @return If true, option called "version" was found and descriptions were
 * written to standard output.
 */


/** Request Parameters to reparse input file(s). This function needs to be
 * called after new options have been added via Parameters:add functions.
 * Otherwise the values of the new options are not read. This is a collective
 * function, all processes have to see it.
 * @param needsRunConfig Whether or not this program can run without a runconfig
 * file (esm: vlasiator can't, but particle pusher can).
 * @param allowUnknown true if unregistered options are parsed without error.
 * @return True if input file(s) were parsed successfully.
 */


// add names of input files


/*! \brief A function to stop the simulation if the boolean condition is true.
 * Raises a flag which gets MPI_Reduced and initiates bailout.
 * [bailout] parameters set details.
 * \param condition if true, bailout is initiated
 * \param message information message printed to cerr
 * \param file code file where bailout was called (use __FILE__ in the call)
 * \param line code line where bailout was called (use __LINE__ in the call)
 */


/*! \brief A function to stop the simulation if the boolean condition is true.
 * Raises a flag which gets MPI_Reduced and initiates bailout.
 * [bailout] parameters set details.
 * \param condition if true, bailout is initiated
 * \param file code file where bailout was called (use __FILE__ in the call)
 * \param line code line where bailout was called (use __LINE__ in the call)
 */


/*! \brief A function to stop the simulation if the boolean condition is true.
 * Raises a flag which gets MPI_Reduced and initiates bailout.
 * [bailout] parameters set details.
 * \param condition if true, bailout is initiated
 * \param message information message printed to cerr
 */


/*! Helper function for error handling. err_type default to 0.*/


/*! Updates local ids across MPI to let other processes know in which order this process saves the local cell ids
 \param mpiGrid Vlasiator's MPI grid
 \param local_cells local cells on in the current process (no ghost cells included)
 \param comm The MPi comm
 \return Returns true if operation was successful
 */


/*! Checks the success of write IO
 \param success Parameter for determining whether the IO has been successful
 \param errorMessage The message to be shown if global success is false
 \param comm The MPI comm
 \return Returns true if all of the processes running this function had success value of true, false otherwise
 */


/** Writes the velocity distribution into the file.
 @param vlsvWriter Some vlsv writer with a file open.
 @param mpiGrid Vlasiator's grid.
 @param cells Vector of local cells within this process (no ghost cells).
 @param comm The MPI communicator.
 @return Returns true if operation was successful.*/


/** Writes the velocity distribution of specified population into the file.
 @param vlsvWriter Some vlsv writer with a file open.
 @param mpiGrid Vlasiator's grid.
 @param cells Vector of local cells within this process (no ghost cells).
 @param comm The MPI communicator.
 @return Returns true if operation was successful.*/


/*! Writes info received from data reducer. This function writes out the variable arrays into the file
 \param mpiGrid The Vlasiator's grid
 \param cells List of local cells (no ghost cells included)
 \param writeAsFloat If true, the data reducer writes variable arrays as float instead of double
 \param dataReducer The data reducer which contains the necessary functions for calculating variables
 \param dataReducerIndex Index in the data reducer (determines which variable to read) Note: size of the data reducer can be retrieved with dataReducer.size()
 \param vlsvWriter Some vlsv writer with a file open
 \return Returns true if operation was successful
 */


/*! Writes common grid data such as parameters (time steps, x_min, ..) as well as local cell ids as variables
 \param vlsvWriter Some vlsv writer with a file open
 \param mpiGrid Vlasiator's grid
 \param local_cells The local cell ids in this process
 \param fileIndex File index, file will be called "name.index.vlsv"
 \param comm The MPI comm
 \return Returns true if operation was successful
 */


/*! Writes the zone global id numbers into the file. The vlsv file needs to know in which order the local cells + ghost cells are written. Local cells are first appended to a vector called global ids, after which the ghost cells are appended. The global ids vector will then be saved into a vlsv file
 \param mpiGrid Vlasiator's MPI grid
 \param vlsvWriter Some vlsv writer with a file open
 \param meshName Name of the mesh ("SpatialGrid" used in the writeGrid function and it should be the default)
 \param local_cells Vector containing the local cells of this process
 \param ghost_cells Vector containing the ghost cells of this process ( The cells on process boundary )
 \return Returns true if the operation was successful
 */


/*! Writes the node coordinates. This means basically every cell's node (Corner of each cell). Note: The grid is a structured one, so writing the nodes means starting from the corner of the grid and writing coordinates per every cell length until reaching the other corner of the grid
 \param vlsvWriter Some vlsv writer with a file open
 \param meshName Name of the mesh (SpatialGrid used in writeGrid and should be the default)
 \param masterRank The master rank (Vlasiator uses 0)
 \param comm The MPI comm
 \return Returns true if the operation was successful
 */


/*! Function for writing the bounding box. This writes only if the process running it is the master rank. This array contains info on the boundaries of the grid so for example the number of cells in x, y, z direction.
 * Note that this is *not* the physical coordinate bounding box, but the computational domain bounding box, measured in blocks and cells.
 \param vlsvWriter Some vlsv writer with a file open
 \param meshName Name of the mesh to write ("SpatialGrid" is used in writeGrid and it should be the default)
 \param masterRank The master process' id. Vlasiator uses 0 as the master process id, so by default should be 0
 \param comm MPI comm
 \return Returns true if operation was successful
 */


/*Function to append version information to current output file
 \param vlsvWriter Some vlsv writer with a file open
 \param comm MPI comm
 \return Returns true if operation was successful
 */


/*Function to append config information to current output file
 \param vlsvWriter Some vlsv writer with a file open
 \param comm MPI comm
 \return Returns true if operation was successful
 */


/** Writes the mesh metadata for Visit to read FSGrid variable data.
 * @param technicalGrid An fsgrid instance used to extract metadata info.
 * @param vlsvWriter file object to write into.
 */


/** Writes the mesh metadata for Visit to read the Ionosphere grid and its variables.
 */


/** This function writes the velocity space.
 * @param mpiGrid Vlasiator's grid.
 * @param vlsvWriter some vlsv writer with a file open.
 * @param index Index to call the correct member of the various parameter vectors.
 * @param cells Vector containing local cells of this process.
 * @return Returns true if the operation was successful.
 * @sa writeVelocityDistributionData. */


/*! This function makes sure that local cells and ghost cells do not have any identical members (used for error checking)
 \param local_cells List of local cells within this process
 \param ghost_cells List of ghost cells within this process (cells on the process boundary)
 */


/*!

\brief Write out system into a vlsv file

\param mpiGrid     The DCCRG grid with spatial cells
\param dataReducer Contains datareductionoperators that are used to compute data that is added into file
\param index       Index to call the correct member of the various parameter vectors
\param writeGhosts If true, writes out ghost cells (cells that exist on the process boundary so other process' cells)
*/


/*!

\brief Write out a restart of the simulation into a vlsv file. All block data in remote cells will be reset.

\param mpiGrid   The DCCRG grid with spatial cells
\param dataReducer Contains datareductionoperators that are used to compute data that is added into file
\param name       File name prefix, file will be called "name.index.vlsv"
\param fileIndex  File index, file will be called "name.index.vlsv"
*/


/*!

\brief Write out simulation diagnostics into diagnostic.txt

\param mpiGrid   The DCCRG grid with spatial cells
\param dataReducer Contains datareductionoperators that are used to compute diagnostic data
*/


/*! Function used to abort the program upon detecting a floating point exception. Which exceptions are caught is defined using the function feenableexcept.
 */


/*! Report spatial cell counts per refinement level as well as velocity cell counts per population into logfile
 */


/** Driver function for convertVelocityBlocks. Reads the names of
 * existing particle species and calls convertVelocityBlocks2 for
 * each of them.
 * @param vlsvReader VLSV file reader that has input file open.
 * @param fname Name of the input file.
 * @param meshName Name of the spatial mesh.
 * @param cellStruct Struct containing mesh metadata.
 * @param cellID ID of the spatial cell whose distribution function(s) are to be extracted.
 * @param rotate If true, distribution function(s) are rotated so that the magnetic field points
 * along +vz axis.
 * @param plasmaFrame If true, distribution function(s) are translated to local plasma rest frame.
 * @return If true, all distributions were extracted successfully.*/


//Searches for the closest cell id to the given coordinates from a list of cell ids and returns it
//Input:
//[0] CellStructure cellStruct -- a struct that holds info on cell structure
//[1] uint64_t * cellIdList -- Some list of cell ids (Note: Could use a vector here)
//[2] Real * coordinates, -- Some coordinates x, y, z  (Note: Could use std::array here)
//[3] uint64_t sizeOfCellIdList -- Size of cellIdList (Note: This would not be needed if a vector was used)a
//Output:
//[0] Returns the closest cell id to the given coordinates


//Searches for the closest cell id to the given coordinates from a list of cell ids and returns it
//Input:
//[0] CellStructure cellStruct -- a struct that holds info on cell structure
//[1] cellIdList -- Some list of cell ids
//[2] coordinates, -- Some coordinates x, y, z
//Output:
//[0] Returns the closest cell id to the given coordinates


//Prints out the usage message


//Used in main() to retrieve options (returns false if something goes wrong)
//Input:
//[0] int argn -- number of arguments in args
//[1] char *args -- arguments
//Output:
//[0] UserOptions & mainOptions -- Saves all the options in this class


/** Read given array data from input file, and byte-copy it to the output file.
 * @param input Input file reader.
 * @param output Output file reader.
 * @param tagName Name of the copied array.
 * @param inputAttributes XML attributes for the copied array.
 * @param optional If true, this parameter is OK to be missing.
 * @return If true, the array was copied successfully.*/


/* Small function that overrides how fsgrid diff files are written*/


/** Copy the spatial mesh from input to output.
 * @param inputFileName Name of the input file where the mesh is copied from.
 * @param output VLSV reader for the file where the cloned mesh is written.
 * @param meshName Name of the mesh.
 * @return If true, the mesh was successfully cloned.*/


/*! Extracts the dataset from the VLSV file opened by convertSILO.
 * \param vlsvReader vlsvinterface::Reader class object used to access the VLSV file
 * \param meshName Address of the string containing the name of the mesh to be extracted
 * \param varToExtract Pointer to the char array containing the name of the variable to extract
 * \param compToExtract Unsigned int designating the component to extract (0 for scalars)
 * \param orderedData Pointer to the return argument map which will get the extracted dataset
 */


/*! Shift the second file to the average of the first
 * \param orderedData1 Pointer to the reference file's data
 * \param orderedData2 Pointer to the data to be shifted
 * \param shiftedData2 Pointer to where the shifted data of the second file will be put
 */


/*! Compute the absolute and relative \f$ p \f$-distance between two datasets X(x) provided in the maps orderedData1 and orderedData2. Note that the dataset passed in orderedData1 will be taken as the reference dataset both when shifting averages and when computing relative distances.
 *
 * For \f$ p \neq 0 \f$:
 *
 * absolute \f$ p \f$-distance defined as:
 *
 * \f$ \|X_1 - X_2\|_p = \left[\sum_i |X_1(i) - X_2(i)|^p\right]^{1/p}\f$,
 *
 * relative \f$ p \f$-distance defined as:
 *
 * \f$ \|X_1 - X_2\|_p = \left[\sum_i |X_1(i) - X_2(i)|^p\right]^{1/p} / \|X_1\|_p \f$.
 *
 * For \f$ p = 0 \f$ it is the \f$ \infty \f$-distance:
 *
 * absolute \f$ \infty \f$-distance defined as:
 *
 * \f$ \|X_1 - X_2\|_\infty = \max_i\left(|X_1(i) - X_2(i)|\right)\f$
 *
 * relative \f$ \infty \f$-distance defined as:
 *
 * \f$ \|X_1 - X_2\|_\infty = \max_i\left(|X_1(i) - X_2(i)|\right) / \|X_1\|_\infty \f$
 *
 * \param orderedData1 Pointer to the first file's data map
 * \param orderedData2 Pointer to the second file's data map
 * \param p Parameter of the distance formula
 * \param absolute Return argument pointer, absolute value
 * \param relative Return argument pointer, relative value
 * \param doShiftAverage Boolean argument to determine whether to shift the second file's data
 * \sa shiftAverage
 */


/*! In verbose mode print the distance, in non-verbose store them for later output when lastCall is true
 * \param p Parameter of the distance
 * \param absolute Absolute value pointer
 * \param relative Relative value pointer
 * \param shiftedAverage Boolean parameter telling whether the dataset is average-shifted
 * \param verboseOutput Boolean parameter telling whether the output is verbose or compact
 * \param lastCall Boolean parameter telling whether this is the last call to the function
 * \sa shiftAverage pDistance
 */


/*! In verbose mode print delta t, in non-verbose store them for later output when lastCall is true
 * \param dt delta t
 * \param verboseOutput Boolean parameter telling whether the output is verbose or compact
 * \param lastCall Boolean parameter telling whether this is the last call to the function
 */


/*! Compute statistics on a single file
 * \param size Return argument pointer, dataset size
 * \param mini Return argument pointer, dataset minimum
 * \param maxi Return argument pointer, dataset maximum
 * \param avg Return argument pointer, dataset average
 * \param stdev Return argument pointer, dataset standard deviation
 */


/*! In verbose mode print the statistics, in non-verbose store them for later output when lastCall is true
 * \param size Pointer to dataset size
 * \param mini Pointer to dataset minimum
 * \param maxi Pointer to dataset maximum
 * \param avg Pointer to dataset average
 * \param stdev Pointer to dataset standard deviation
 * \param verboseOutput Boolean parameter telling whether the output is verbose or compact
 * \param lastCall Boolean parameter telling whether this is the last call to the function
 * \sa singleStatistics
 */


/*! In folder-processing, non-verbose mode the data are stored during the processing and output at the end to have the data sorted properly
 * \sa outputStats outputDistance
 */


/*! Read in the contents of the variable component in both files passed in strings fileName1 and fileName2, and compute statistics and distances as wished
 * \param fileName1 String argument giving the location of the first file to process
 * \param fileName2 String argument giving the location of the second file to process
 * \param varToExtract Pointer to the char array containing the name of the variable to extract
 * \param compToExtract Unsigned int designating the component to extract (0 for scalars)
 * \param verboseOutput Boolean parameter telling whether the output will be verbose or compact
 * \sa convertSILO singleStatistics outputStats pDistance outputDistance printNonVerboseData
 */


/*! Creates the list of grid*.vlsv files present in the folder passed
 * \param dir DIR type pointer to the directory entry to process
 * \param fileList Pointer to a set of strings, return argument for the produced file list
 */


// Pointer to file opened by SILO


// Calculate fluxfunction by integrating along -y/z boundary first,
// and then going along y/z-direction.


// Calculate fluxfunction by integrating along +y/z boundary first,
// and then going along negative y/z-direction.


// Calculate fluxfunction by integrating along -x from the right boundary


// Calculate fluxfunction by integrating along -y/z boundary
// Then along the -x boundary
// And finally right in the +x direction


// Calculate fluxfunction by integrating along +y/z boundary
// Then along the -x boundary
// And finally right in the +x direction


// Get median of vector


// Get mean of vector


/** Initialize the Project. Velocity mesh and particle population
    * parameters are read from the configuration file, and corresponding internal
    * variables are created here.
    * NOTE: Each project must call this function!
    * @return If true, particle species and velocity meshes were created successfully.*/


/*! Print a warning message to stderr and abort, one should not use the base class functions. */


/** Write simulated particle populations to logfile.*/


/** Calculate the volume averages of distribution function for the
    * given particle population in the given spatial cell. The velocity block
    * is defined by its local ID. The function returns the maximum value of the
    * distribution function within the velocity block. If it is below the sparse
    * min value for the population, this block should be removed or marked
    * as a no-content block.
    * @param cell Spatial cell.
    * @param blockLID Velocity block local ID within the spatial cell.
    * @param popID Population ID.
    * @return Maximum value of the calculated distribution function.*/


/** Rescale the distribution function of the given particle species so that
    * the number density corresponds to the value returned by getCorrectNumberDensity.
    * @param cell Spatial cell.
    * @param popID ID of the particle species.*/


/*!
     Get random number between 0 and 1.0. One should always first initialize the rng.
   */


/*!
     Set random seed (thread-safe) that is always the same for
     this particular cellID. Can be used to make reproducible
     simulations that do not depend on number of processes or threads.

     \param  cellParams The cell parameters list in each spatial cell
   */


/*
     Refine cells of mpiGrid. Each project that wants refinement should implement this function.
     Base class function uses AMR box half width parameters
    */


/*!
    * WARNING This assumes that the velocity space is isotropic (same resolution in vx, vy, vz).
    */


/** Returns the center coordinates of the maxwellian distribution
   @ param x The x coordinate of the given spatial cell
   @ param y The x coordinate of the given spatial cell
   @ param z The x coordinate of the given spatial cell
   */


/* set 0-centered dipole */


/*!
  Computes the intersection point of a plane and a line

  \param l_point Point on the line
  \param l_direction Vector in the direction of the line
  \param p_point Point on plane
  \param p_normal Normal vector to plane
  \param intersection The function will set this to the intersection point
*/


/**
 * Computes the first intersection data; this is z~ in section 2.4 in Zerroukat et al (2012). We assume all velocity cells have the same dimensions.
 * Intersection z coordinate for (i,j,k) is: intersection + i * intersection_di + j * intersection_dj + k * intersection_dk
 * @param spatial_cell spatial cell that is accelerated
 * @param fwd_transform Transform that describes acceleration forward in time
 * @param bwd_transform Transform that describes acceleration backward in time, used to compute the lagrangian departure grid
 * @param dimension Along which dimension is this intersection/mapping computation done. It is assumed the three mappings are in order 012, 120 or 201
 * @param refLevel Refinement level at which intersections are calculated.
 * @param intersection Intersection z coordinate at i,j,k=0
 * @param intersection_di Change in z-coordinate for a change in i index of 1
 * @param intersection_dj Change in z-coordinate for a change in j index of 1
 * @param intersection_dk Change in z-coordinate for a change in k index of 1
*/


/*!
  Computes the second intersection data; this is x~ in section 2.4 in Zerroukat et al (2012). We assume all velocity cells have the same dimensions.
  Intersection x coordinate for (i,j,k) is: intersection + i * intersection_di + j * intersection_dj + k * intersection_dk
  \param spatial_cell spatial cell that is accelerated
  \param fwd_transform Transform that describes acceleration forward in time
  \param bwd_transform Transform that describes acceleration backward in time, used to compute the lagrangian departure grid
  \param dimension Along which dimension is this intersection/mapping computation done. It is assumed the three mappings are in order 012, 120 or 201
  \param intersection Intersection x-coordinate at i,j,k=0
  \param intersection_di Change in x-coordinate for a change in i index of 1
  \param intersection_dj Change in x-coordinate for a change in j index of 1
  \param intersection_dk Change in x-coordinate for a change in k index of 1
*/


/*!
  Computes the third intersection data; this is y intersesctions in Zerroukat et al (2012). We assume all velocity cells have the same dimensions.
  Intersection y-coordinate for (i,j,k) is: intersection + i * intersection_di + j * intersection_dj + k * intersection_dk
  \param spatial_cell spatial cell that is accelerated
  \param fwd_transform Transform that describes acceleration forward in time
  \param bwd_transform Transform that describes acceleration backward in time, used to compute the lagrangian departure grid
  \param dimension Along which dimension is this intersection/mapping computation done. It is assumed the three mappings are in order 012, 120 or 201
  \param intersection Intersection y-coordinate at i,j,k=0
  \param intersection_di Change in y-coordinate for a change in i index of 1
  \param intersection_dj Change in y-coordinate for a change in j index of 1
  \param intersection_dk Change in y-coordinate for a change in k index of 1

  euclidian y goes from vy_min to vy_max, this is mapped to wherever y plane is in lagrangian

*/


/*
   This function copies the block list from spatial cell to blocks and sorts it

   Note: blocks must be allocated
*/


/*compute spatial target neighbors, stencil has a size of 3. No boundary cells are included*/


/*
 Here we map from the current time step grid, to a target grid which
 is the lagrangian departure grid (so the grid at timestep +dt,
 tracked backwards by -dt). This is done in ordinary space in the translation step

 This function can, and should be, safely called in a parallel
 OpenMP region (as long as it does only one dimension per parallel
 refion). It is safe as each thread only computes certain blocks (blockID%tnum_threads = thread_num */


/*
   Here we map from the current time step grid, to a target grid which
   is the lagrangian departure grid (so th grid at timestep +dt,
   tracked backwards by -dt)

   TODO: parallelize with openMP over block-columns. If one also
   pre-creates new blocks in a separate loop first (serial operation),
   then the openmp parallization would scale well (better than over
   spatial cells), and would not need synchronization.

*/


/** Generate target mesh at given refinement level.
 * @param spatial_cell Pointer to the spatial cell.
 * @param blocks List of source blocks, identified by their local IDs.
 * @param params Accelerator parameters.
 * @param targetRefLevel
 * @param vmesh Source mesh.
 */


/**
 * @param spatial_cell Propagated spatial cell, contains a valid (unsorted) target mesh.
 * @param params Parameters needed in the propagation.
 * @param vmesh The source mesh.
 * @param blockContainer Source mesh data.*/


/*Compute transform during on timestep, and update the bulk velocity of the cell*/


/*
  --------------------------------------------------
  Acceleration (velocity space propagation)
  --------------------------------------------------
*/


/*--------------------------------------------------
  Functions for computing moments
  --------------------------------------------------*/


/**
    * NOTE that this is called once for each particle species!
    * @param mpiGrid
    * @param cellID
    */


/*!\brief Function used to determine on which face(s) if any the cell at given coordinates is.
    *
    * This function is used by some of the classes inheriting from this base class.
    *
    * Depth is hard-coded to be 2 as other parts of the code (field solver especially) rely on that.
    *
    * \param isThisCellOnAFace Pointer to an array of 6 bool returning of each face whether the cell is on that face. Order: 0 x+; 1 x-; 2 y+; 3 y-; 4 z+; 5 z-
    * \param x Cell x coordinate
    * \param y Cell y coordinate
    * \param z Cell z coordinate
    * \param dx Cell dx size
    * \param dy Cell dy size
    * \param dz Cell dz size
    * \param excludeSlicesAndPeriodicDimensions If true, do not consider a cell to be part of the face if that face has a depth of 1 only (single-cell thick slices/columns) or if that direciton is periodic..
    */


/*!\brief Function used to determine on which face(s) if any the cell with the given MPI id is on
    *
    * This function is used by some of the classes inheriting from this base class.
    *
    * Depth is hard-coded to be 2 as other parts of the code (field solver especially) rely on that.
    * So if a cell has less than two unique neighbors in some direction, it is considered to be on that face.
    *
    * \param isThisCellOnAFace Referemce to an std::array of 6 bool returning of each face whether the cell is on that face. Order: 0 x+; 1 x-; 2 y+; 3 y-; 4 z+; 5 z-
    * \param mpiGrid Reference to grid
    * \param id ID of cell to check
    * \param excludeSlicesAndPeriodicDimensions If true, do not consider a cell to be part of the face if that face has a depth of 1 only (single-cell thick slices/columns) or if that direciton is periodic..
    */


/*! Function used to set the system boundary condition cell's derivatives to 0.
    * \param mpiGrid Grid
    * \param cellID The cell's ID.
    * \param component 0: x-derivatives, 1: y-derivatives, 2: z-derivatives, 3: xy-derivatives, 4: xz-derivatives, 5: yz-derivatives.
    */


/*! Function used to set the system boundary condition cell's BVOL derivatives to 0.
    * \param mpiGrid Grid
    * \param cellID The cell's ID.
    * \param component 0: x-derivatives, 1: y-derivatives, 2: z-derivatives.
    */


/*! Function used to copy the distribution and moments from (one of) the closest sysboundarytype::NOT_SYSBOUNDARY cell.
    * \param mpiGrid Grid
    * \param cellID The cell's ID.
    * \param copyMomentsOnly If true, do not touch velocity space.
    */


/*! Function used to average and copy the distribution and moments from all the closest sysboundarytype::NOT_SYSBOUNDARY cells.
    * \param mpiGrid Grid
    * \param cellID The cell's ID.
    */


/*! Function used to average and copy the distribution and moments from all the close sysboundarytype::NOT_SYSBOUNDARY cells.
    * \param mpiGrid Grid
    * \param cellID The cell's ID.
    */


/*! Function used to copy the distribution from (one of) the closest sysboundarytype::NOT_SYSBOUNDARY cell but limiting to values no higher than where it can flow into. Moments are recomputed.
    * \param mpiGrid Grid
    * \param cellID The cell's ID.
    */


/*! Function used to copy the distribution and moments from one cell to another.
    * \param from Pointer to parent cell to copy from.
    * \param to Pointer to destination cell.
    */


/*! Take a list of cells and set the destination cell distribution function to the average of the list's cells'.
    * \param mpiGrid Grid
    * \param cellList Vector of cells to copy from.
    * \param to Pointer to cell in which to set the averaged distribution.
    * \param popID ID of population to average the distribution of
    * \param fluffiness Factor to replace data with from 0.0 (default, do nothing) to 1.0 (replace all destination data with source data)
    */


/*! Take neighboring distribution and reflect all parts going in the direction opposite to the normal vector given in.
    * \param mpiGrid Grid
    * \param cellID Cell in which to set the distribution where incoming velocity cells have been reflected/bounced.
    * \param nx Unit vector x component normal to the bounce/reflection plane.
    * \param ny Unit vector y component normal to the bounce/reflection plane.
    * \param nz Unit vector z component normal to the bounce/reflection plane.
    */


/*! Take neighboring distribution and absorb all parts going in the direction opposite to the normal vector given in.
    * \param mpiGrid Grid
    * \param cellID Cell in which to set the distribution where incoming velocity cells have been kept or swallowed.
    * \param nx Unit vector x component normal to the absorption plane.
    * \param ny Unit vector y component normal to the absorption plane.
    * \param nz Unit vector z component normal to the absorption plane.
    * \param quenchingFactor Multiplicative factor by which to scale the distribution function values. 0: absorb. ]0;1[: quench.
    */


/*! Updates the system boundary conditions after load balancing. This is called from e.g. the class SysBoundary.
    * \param mpiGrid Grid
    * \param local_cells_on_boundary Cells within this process
    * \retval success Returns true if the operation is successful
    */


/*! Get the cellID of the first closest cell of type NOT_SYSBOUNDARY found.
    * \param i,j,k Coordinates of the cell to start looking from
    * \return The cell index of that cell
    * \sa getAllClosestNonsysboundaryCells
    */


/*! Get the cellIDs of all the closest cells of type NOT_SYSBOUNDARY.
    * \param i,j,k Coordinates of the cell to start looking from
    * \return The vector of cell indices of those cells
    * \sa getTheClosestNonsysboundaryCell
    */


/*! Function used in some cases to know which faces the system boundary condition is being applied to.
    * \param faces Pointer to array of 6 bool in which the values are returned whether the corresponding face is of that type. Order: 0 x+; 1 x-; 2 y+; 3 y-; 4 z+; 5 z-
    */


/*! Load inflow boundary data from given file.
 * The number of entries per line is given by nParams which is defined as a parameter
 * from the configuration file/command line.
 * \param fn Name of the data file.
 * \retval dataset Vector of Real vectors.
 */


/*! Loops through the array of template cells and generates the ones needed.
 * The function generateTemplateCell is defined in the child class to have the specific condition needed.
 * \param t Simulation time
 * \sa generateTemplateCell
 */


/*!Interpolate the input data to the given time.
 * The first entry of each line is assumed to be the time.
 * \param inputDataIndex Index used to get the correct face's input data.
 * \param t Current simulation time.
 * \param outputData Pointer to the location where to write the result.
 * Make sure from the calling side that nParams Real values can be written there!
 */


/*  Here the while loop iterates  from the centre of the maxwellian in blocksize (4*dvx) increments,
   *  and looks at the centre of the first velocity cell in the block (+0.5dvx), checking if the
   *  phase-space density there is large enough to be included due to sparsity threshold.
   *  That results in a "blocks radius"  vRadiusSquared from the centre of the maxwellianDistribution.
   *  Then we iterate through the actual blocks and calculate their radius R2 based on their velocity coordinates
   *  and the plasma bulk velocity. Blocks that fullfil R2<vRadiusSquared are included to blocksToInitialize.
   */


/*!\brief Generate the template cell for the face corresponding to the index passed.
    * This function generates a spatial cell which is to be used as a template for the
    * system boundary condition.
    * \param templateCell Address of the template cell to be generated.
    * \param B Address of the magnetic field to be used as template.
    * \param inputDataIndex Index used for the location of the input data.
    * \param t Current simulation time.
    */


// Offset field aligned currents so their sum is 0


// Scale all nodes' coordinates so that they are situated on a spherical
// shell with radius R


// Regenerate linking information between nodes and elements
// Note: if this runs *before* stitchRefinementInterfaces(), there will be no
// more information about t-junctions, so further stitiching won't work


// Initialize base grid as a tetrahedron


// Initialize base grid as a icosahedron


// Spherical fibonacci base grid with arbitrary number of nodes n>8,
// after Keinert et al 2015


// Find the neighbouring element of the one with index e, that is sharing the
// two corner nodes n1 and n2
//
//            2 . . . . . . . .*
//           /  \             .
//          /    \   neigh   .
//         /      \   bour  .
//        /   e    \       .
//       /          \     .
//      /            \   .
//     /              \ .
//    0----------------1
//


// Find the mesh node closest to the given coordinates.


// And three new nodes get created at the interfaces,
// unless they already exist.
// The new center element (3) replaces the old parent element in place.


// Fractional energy dissipation rate for a isotropic beam, based on Rees (1963), figure 1


// Energy dissipasion function based on Sergienko & Ivanov (1993), eq. A2


/* Read atmospheric model file in MSIS format.
    * Based on the table data, precalculate and fill the ionisation production lookup table
    */


/*!< Store the value of the magnetic field at the node.*/


/* Look up the free electron production rate in the ionosphere, given the atmospheric height index,
    * particle energy after the ionospheric potential drop and inflowing distribution temperature */


/* Estimate the magnetospheric electron precipitation energy flux (in W/m^2) from
    * mass density, electron temperature and potential difference.
    *
    * TODO: This is the coarse MHD estimate, lacking a better approximation. Should this
    * instead use the precipitation data reducer?
    */


/* Calculate the conductivity tensor for every grid node, based on the
    * given F10.7 photospheric flux as a solar activity proxy.
    *
    * This assumes the FACs have already been coupled into the grid.
    *
    * If refillTensorAtRestart is true, we don't recompute precipitation and integration, we just refill the tensor from the sigmas as read from restart.
    * That is necessary so ig_inplanecurrent has non-zero data if an output file is written after restart and before the next ionosphere solution step.
    */


// (Re-)create the subcommunicator for ionosphere-internal communication
// This needs to be rerun after Vlasov grid load balancing to ensure that
// ionosphere info is still communicated to the right ranks.


// Calculate upmapped potential at the given coordinates,
// by tracing down to the ionosphere and interpolating the appropriate element


// Transport field-aligned currents down from the simulation cells to the ionosphere


// Calculate grad(T) for a element basis function that is zero at corners a and b,
// and unity at corner c


// Calculate the average sigma tensor of an element by averaging over the three nodes it touches


// calculate integral( grd(Ti) Sigma grad(Tj) ) over the area of the given element
// The i and j parameters enumerate the piecewise linear element basis function


// Add matrix value for the solver, linking two nodes.


// Add solver matrix dependencies for the neighbouring nodes


// Make sure refinement interfaces are properly "stitched", and that there are no
// nodes remaining on t-junctions. This is done by splitting the bigger neighbour:
//
//      A---------------C         A---------------C
//     / \             /         / \  resized .-'/
//    /   \           /         /   \      .-'  /
//   /     \         /         /     \  .-'    /
//  o-------n       /    ==>  o-------n' new  /.  <- potential other node to update next?
//   \     / \     /           \     / \     /  .
//    \   /   \   /             \   /   \   /    .
//     \ /     \ /               \ /     \ /      .
//      o-------B                 o-------B . . .  .


// Initialize the CG sover by assigning matrix dependency weights


// Evaluate a nodes' neighbour parameter, averaged through the coupling
// matrix
//
// -> "A times parameter"


// Evaluate a nodes' own parameter value
// (If preconditioning is used, this is already adjusted for self-coupling)


// Solve the ionosphere potential using a conjugate gradient solver


/*! We want here to
    *
    * -- Average perturbed face B from the nearest neighbours
    *
    * -- Retain only the normal components of perturbed face B
    */


/**
    * NOTE: This function must initialize all particle species!
    * @param project
    */


/*!\brief Destructor for class SysBoundary.
 *
 * Reduces the value of SysBoundary::nSysBoundaries by one,
 * and if after the destruction SysBoundary::nSysBoundaries equals zero all stored SysBoundaries are deleted.
 */


/*!\brief Add its own and all existing SysBoundaryConditions' parameters.
 *
 * Adds the parameters specific to the SysBondary class handling the list of
 * SysBoundaryConditions and then calls the static addParameters functions of all
 * SysBoundaryConditions implemented in the code in order to have them appear also in the
 * help.
 */


/*!\brief Get this class' parameters.
 *
 * Get the parameters pertaining to this class.
 *
 * getParameters for each actually used system boundary condition is called by each
 * SysBoundaryCondition's initialization function.
 */


/*! Add a new SBC::SysBoundaryCondition which has been created with new sysBoundary.
 * SysBoundary will take care of deleting it.
 *
 * \param bc SysBoundaryCondition object
 * \param project Project object
 * \param t Current time
 * \retval success If true, the given SBC::SysBoundaryCondition was added successfully.
 */


/*!\brief Initialise all system boundary conditions actually used.
 *
 * This function loops through the list of system boundary conditions listed as to be used
 * in the configuration file/command line arguments. For each of these it adds the
 * corresponding instance and updates the member isDynamic to determine whether any
 * SysBoundaryCondition is dynamic in time.
 *
 * \param project Project object
 * \param t Current time
 * \retval success If true, the initialisation of all system boundaries succeeded.
 * \sa addSysBoundary
 */


/*!\brief Boolean check if queried sysboundarycondition exists
 * Note: this queries against the parsed list of names, not against the actual existing boundaries.
 * This is so that the project configuration (which is handled before grid and boundary initialization)
 * can use this call.
 *
 * \param string name
 * \retval success if queried boundary exists
 * \sa addSysBoundary
 */


/*!\brief Classify all simulation cells with respect to the system boundary conditions.
 *
 * Loops through all cells and and for each assigns the correct sysBoundaryFlag depending on
 * the return value of each SysBoundaryCondition's assignSysBoundary.
 *
 * \param mpiGrid Grid
 */


/*!\brief Apply the initial state to all system boundary cells.
 * Loops through all SysBoundaryConditions and calls the corresponding applyInitialState
 * function. This function must apply the initial state for all existing particle species.
 *
 * \param mpiGrid Grid
 * \retval success If true, the application of all system boundary states succeeded.
 */


/*!\brief Apply the Vlasov system boundary conditions to all system boundary cells at time t.
 *
 * Loops through all SysBoundaryConditions and calls the corresponding vlasovBoundaryCondition() function.
 * The boundary condition functions are called for all particle species, one at a time.
 *
 * WARNING (see end of the function) Blocks are changed but lists not updated now,
 * if you need to use/communicate them before the next update is done, add an
 * update at the end of this function.
 *
 * \param mpiGrid Grid
 * \param t Current time
 * \param calculate_V_moments if true, compute into _V, false into _R moments so that the interpolated ones can be done
 */


/*! Get a pointer to the SysBoundaryCondition of given index.
 * \param sysBoundaryType Type of the system boundary condition to return
 * \return Pointer to the instance of the SysBoundaryCondition. NULL if sysBoundaryType is invalid.
 */


/*! Updates all NonsysboundaryCells into an internal map. This should be called in loadBalance.
 * \param mpiGrid The DCCRG grid
 * \retval Returns true if the operation is successful
 */


/*
  1D,2D,3D Romberg non-singular integration a'la Numerical Recipes.
  Integration bounds must be constants.
  Header file is quadr.H.
  Test program is tstquadr.C
  Same in Mathematica is tstquadr.ma
*/


//tilt_angle is agains the z axis in the x-z plane. In radians*/


// tilt_angle_phi is from the z-axis in radians
// tilt_angle_theta is from the Sun-Earth-line in radians


/** Destructor for class DataReducer. All stored DataReductionOperators
 * are deleted.
 */


/** Request a DataReductionOperator to calculate its output data and to write it to the given buffer.
 * @param cell Pointer to spatial cell whose data is to be reduced.
 * @param operatorID ID number of the applied DataReductionOperator.
 * @param buffer Buffer in which DataReductionOperator should write its data.
 * @return If true, DataReductionOperator calculated and wrote data successfully.
 */


/** Request a DataReductionOperator to calculate its output data and to write it to the given variable.
 * @param cell Pointer to spatial cell whose data is to be reduced.
 * @param operatorID ID number of the applied DataReductionOperator.
 * @param result Real variable in which DataReductionOperator should write its result.
 * @return If true, DataReductionOperator calculated and wrote data successfully.
 */


/** Write parameters related to given DataReductionOperator to the output file.
 * @param operatorID ID number of the selected DataReductionOperator.
 * @param vlsvWriter VLSV file writer that has output file open.
 * @return If true, DataReductionOperator wrote its parameters successfully.*/


/** Write all data thet the given DataReductionOperator wants to obtain from fsgrid into the output file.
 */


/** Reduce the data and write the data vector to the given vlsv output buffer.
    * @param cell the SpatialCell to reduce data out of
    * @param buffer Buffer in which the reduced data is written.
    * @return If true, DataReductionOperator reduced data successfully.
    */


/** Reduce the data and write the data vector to the given variable.
    * If the vector length is larger than one, memory gets corrupted.
    * Note that this function is only used for writing into diagnostic files.
    * @param cell the SpatialCell to reduce data out of
    * @param buffer Buffer in which the reduced data is written.
    * @return If true, DataReductionOperator reduced data successfully.
    */


//Calculates rho thermal or rho non-thermal


/*! \brief Precipitation directional differential number flux (within loss cone)
    * Evaluation of the precipitating differential flux (per population).
    * In a selected number (default: 16) of logarithmically spaced energy bins, the average of
    *      V*V/mass
    * is calculated within the loss cone of fixed angular opening (default: 10 deg).
    * The differential flux is converted in part. / cm^2 / s / sr / eV (unit used by observers).
    * Parameters that can be set in cfg file under [{species}_precipitation]: nChannels, emin [eV], emax [eV], lossConeAngle [deg]
    * The energy channels are saved in bulk files as PrecipitationCentreEnergy{channel_number}.
    */


/*! \brief Precipitation directional differential number flux (along line)
    * Evaluation of the precipitating differential flux (per population) targeted at low energies.
    * In a selected number (default: 16) of logarithmically spaced energy bins, the average of
    *      V*V/mass
    * is calculated along (or antiparallel to) the magnetic field direction.
    * The differential flux is converted in part. / cm^2 / s / sr / eV (unit used by observers).
    * Parameters that can be set in cfg file under [{species}_precipitation]: nChannels, emin [eV], emax [eV]
    * The energy channels are saved in bulk files as PrecipitationCentreEnergyLine{channel_number}.
    */


/*! \brief Energy density
    * Calculates the energy density of particles in three bins: total energy density, above E1limit*solar wind energy, and above E2limit*solar wind energy
    * Energy densities are given in eV/cm^3.
    * Parameters that can be set in cfg file under [{species}_energydensity]:
    *    - solarwindspeed [m/s],
    *    - solarwindenergy [eV],
    *    - limit1 [scalar, default: 5.],
    *    - limit2 [scalar, default: 10.].
    * The energy thresholds are saved in bulk files as parameters:
    *    - EnergyDensityESW (in eV),
    *    - EnergyDensityELimit1 (as scalar multiplier of EnergyDensityESW),
    *    - EnergyDensityELimit2 (as scalar multiplier of EnergyDensityESW).
    */


/*print all values in the vector valued values array. In this array
  there are blocks_per_dim blocks with a width of WID*/


// Very simplified version of CalculateDerivatives from fieldsolver/derivatives.cpp


/*Compute all face values. For cell k (globla index), its left face
 * value is in fv_l[k] and right value in fv_r[k]. Based on explicit
 * h6 estimate*/


/*Filter according to Eq. 19 in White et al.*/


/*!
 Compute PLM coefficients
 f(v) = a[0] + a[1]/2.0*t
 t=(v-v_{i-0.5})/dv where v_{i-0.5} is the left face of a cell
 The factor 2.0 is in the polynom to ease integration, then integral is a[0]*t + a[1]*t**2
*/


/*
  Compute parabolic reconstruction with an explicit scheme

  Note that value array starts with an empty block, thus values[k + WID]
  corresponds to the current (centered) cell.
*/


/*!
  MC slope limiter
*/


/*!
  MC limiter. Give absolute value of slope and its sign separately
*/


/* Call the heavier operations for DROs to be called only if needed, before an IO.
    */


/*! Calculate mapping between ionospheric nodes and fsGrid cells.
   * To do so, the magnetic field lines are traced from all mesh nodes
   * outwards until a non-boundary cell is encountered. Their proportional
   * coupling values are recorded in the grid nodes.
   */


/*! Calculate mapping between ionospheric nodes and Vlasov grid cells.
   * Input is the cell coordinate of the vlasov grid cell.
   * To do so, magnetic field lines are traced inwords from the Vlasov grid
   * IONOSPHERE boundary cells to the ionosphere shell.
   *
   * The return value is a pair of nodeID and coupling factor for the three
   * corners of the containing element.
   */


/*! Trace magnetic field lines out from ionospheric nodes to record whether they are on an open or closed field line.
   */