/** \file
 *
 *  Contains the SimulatorUtils class implementation.
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#include "SimulatorUtils.h"

#include "data/ConfigReader.h"
#include "data/Point3D.h"
#include "data/Point6D.h"
#include "data/Slate.h"
#include "data/StrValue.h"
#include "units/Units.h"

#include "SimulatorIF.h"
#include "VehicleIF.h"
#include "controlModule/VerticalControlIF.h"


/// Configure the SimHeadStruct.
void SimulatorUtils::InitHead( SimHeadStruct& head, SimHeadStruct::StructType structType,
                               unsigned int addr, unsigned int uid )
{
    memset( ( void* )&head, 0, sizeof( head ) );
    head.uuid_ = ( ( ( long long )addr ) << 32 ) + uid;
    head.structType_ = structType;
    switch( structType )
    {
    default:
    case SimHeadStruct::SIM_NO_STRUCT:
        head.structSize_ = 0;
        break;
    case SimHeadStruct::SIM_INIT_STRUCT:
        head.structSize_ = sizeof( SimInitStruct );
        break;
    case SimHeadStruct::SIM_RUN_STRUCT:
        head.structSize_ = sizeof( SimRunStruct );
        break;
    case SimHeadStruct::SIM_COMMS_STRUCT:
        head.structSize_ = sizeof( SimCommsStructToSim );
        break;
    }
}

/// Load properties from config files into the SimInitStruct.
bool SimulatorUtils::LoadInit( SimInitStruct& init, Component* owner, Logger& logger )
{
    // Check if all the parameters are read correctly
    bool ok = true;

    // Initial location
    ok &= Slate::ReadOnce( SimulatorIF::INIT_LAT_CFG, Units::ANGULAR_DEGREE, init.initLat_, logger );
    ok &= Slate::ReadOnce( SimulatorIF::INIT_LON_CFG, Units::ANGULAR_DEGREE, init.initLon_, logger );

    Slate::ReadOnce( SimulatorIF::INIT_Z_CFG, Units::METER, init.initZ_, logger, Syslog::NONE );
    Slate::ReadOnce( SimulatorIF::INIT_PITCH_CFG, Units::RADIAN, init.initPitch_, logger, Syslog::NONE );
    Slate::ReadOnce( SimulatorIF::INIT_ROLL_CFG, Units::RADIAN, init.initRoll_, logger, Syslog::NONE );
    Slate::ReadOnce( SimulatorIF::INIT_YAW_CFG, Units::RADIAN, init.initHeading_, logger, Syslog::NONE );

    Slate::ReadOnce( SimulatorIF::INIT_U_CFG, Units::METER_PER_SECOND, init.initU_, logger, Syslog::NONE );
    Slate::ReadOnce( SimulatorIF::INIT_V_CFG, Units::METER_PER_SECOND, init.initV_, logger, Syslog::NONE );
    Slate::ReadOnce( SimulatorIF::INIT_W_CFG, Units::METER_PER_SECOND, init.initW_, logger, Syslog::NONE );
    Slate::ReadOnce( SimulatorIF::INIT_P_CFG, Units::RADIAN_PER_SECOND, init.initP_, logger, Syslog::NONE );
    Slate::ReadOnce( SimulatorIF::INIT_Q_CFG, Units::RADIAN_PER_SECOND, init.initQ_, logger, Syslog::NONE );
    Slate::ReadOnce( SimulatorIF::INIT_R_CFG, Units::RADIAN_PER_SECOND, init.initR_, logger, Syslog::NONE );

    // Vehicle model properties
    Slate::ReadOnce( SimulatorIF::MASS_INIT_POS_CFG, Units::METER, init.initMassPosition_, logger, Syslog::NONE );
    Slate::ReadOnce( SimulatorIF::BUOY_INIT_POS_CFG, Units::CUBIC_METER, init.initBuoyancyPosition_, logger, Syslog::NONE );

    Slate::ReadOnce( SimulatorIF::INIT_NORTH_CURRENT_CFG, Units::METER_PER_SECOND, init.northCurrent_, logger, Syslog::NONE );
    if( init.northCurrent_ == init.northCurrent_ )
    {
        ok &= Slate::ReadOnce( SimulatorIF::INIT_EAST_CURRENT_CFG, Units::METER_PER_SECOND, init.eastCurrent_, logger );
    }
    Slate::ReadOnce( SimulatorIF::INIT_VERT_CURRENT_CFG, Units::METER_PER_SECOND, init.vertCurrent_, logger, Syslog::NONE );

    Slate::ReadOnce( SimulatorIF::MAGNETIC_VARIATION_CFG, Units::DEGREE, init.magneticVariation_, logger, Syslog::NONE );
    Slate::ReadOnce( SimulatorIF::SOUND_SPEED_CFG, Units::METER_PER_SECOND, init.soundSpeed_, logger, Syslog::NONE );

    Slate::ReadOnce( SimulatorIF::SST_CFG, Units::CELSIUS, init.sst_, logger, Syslog::NONE );
    if( init.sst_ == init.sst_ )
    {
        ok &= Slate::ReadOnce( SimulatorIF::T_MIXED_CFG, Units::CELSIUS, init.tMixed_, logger );
        ok &= Slate::ReadOnce( SimulatorIF::T_300_CFG, Units::CELSIUS, init.t300_, logger );
    }

    Slate::ReadOnce( SimulatorIF::SSS_CFG, Units::PART_PER_THOUSAND, init.sss_, logger, Syslog::NONE );
    if( init.sss_ == init.sss_ )
    {
        ok &= Slate::ReadOnce( SimulatorIF::S_MIXED_CFG, Units::PART_PER_THOUSAND, init.sMixed_, logger );
        ok &= Slate::ReadOnce( SimulatorIF::S_300_CFG, Units::PART_PER_THOUSAND, init.s300_, logger );
    }

    if( init.sss_ == init.sss_ || init.sst_ == init.sst_ )
    {
        ok &= Slate::ReadOnce( SimulatorIF::MIXED_LAYER_DEPTH_CFG, Units::METER, init.mixedLayerDepth_, logger );
    }

    StrValue oceanModelDataStr;
    Slate::ReadOnce( SimulatorIF::OCEAN_MODEL_DATA_CFG, oceanModelDataStr, logger, Syslog::NONE );
    Str oceanModelStr = oceanModelDataStr.asString();

    ok &= Slate::ReadOnce( SimulatorIF::DEFAULT_OCEAN_DENSITY_CFG, Units::KILOGRAM_PER_CUBIC_METER, init.defaultDensity_, logger );

    // Variable buoyancy setting
    ConfigReader* buoyancyNeutralCfgReader = owner->newConfigReader( VerticalControlIF::BUOYANCY_NEUTRAL_CFG );
    ok &= buoyancyNeutralCfgReader->read( Units::CUBIC_METER, init.buoyancyNeutral_ ); // cc    // volume in buoyancy "bag" at neutral trim

    // Mass Properties -- from vehicle.cfg
    ok &= Slate::ReadOnce( SimulatorIF::VEHICLE_MASS_CFG, Units::KILOGRAM, init.mass_, logger ); // mass kg; Vehicle mass
    ok &= Slate::ReadOnce( SimulatorIF::VEHICLE_VOLUME_CFG, Units::CUBIC_METER, init.volume_, logger ); // volume m3

    // Stability Derivatives -- from vehicle.cfg
    //effDragCoef        = .21;        // effDragCoef, unitless; veh drag in x; related to Xuu
    ok &= Slate::ReadOnce( SimulatorIF::XUABU_CFG, Units::KILOGRAM_PER_METER, init.xuabu_, logger ); // Xuabu, Force Derivative, kg/meter

    // Initialize the center of mass -- from vehicle.cfg
    ok &= Slate::ReadOnce( SimulatorIF::CENTER_OF_MASS_X_CFG, Units::METER, init.centerOfMassX_, logger );
    ok &= Slate::ReadOnce( SimulatorIF::CENTER_OF_MASS_Y_CFG, Units::METER, init.centerOfMassY_, logger );
    ok &= Slate::ReadOnce( SimulatorIF::CENTER_OF_MASS_Z_CFG, Units::METER, init.centerOfMassZ_, logger );

    // Initialize the center of buoyancy -- from vehicle.cfg
    ok &= Slate::ReadOnce( SimulatorIF::CENTER_OF_BUOY_X_CFG, Units::METER, init.centerOfBuoyX_, logger ); // centerOfBuoyX
    ok &= Slate::ReadOnce( SimulatorIF::CENTER_OF_BUOY_Y_CFG, Units::METER, init.centerOfBuoyY_, logger ); // centerOfBuoyY
    ok &= Slate::ReadOnce( SimulatorIF::CENTER_OF_BUOY_Z_CFG, Units::METER, init.centerOfBuoyZ_, logger ); // centerOfBuoyZ

    // Initialize the center of movable mass -- from vehicle.cfg
    ok &= Slate::ReadOnce( SimulatorIF::MOVABLE_MASS_CFG, Units::KILOGRAM, init.movableMass_, logger ); // mass kg; Vehicle movable mass
    ok &= Slate::ReadOnce( SimulatorIF::CENTER_OF_MOVABLE_MASS_X_CFG, Units::METER, init.centerOfMovableMassX_, logger ); // centerOfMass
    ok &= Slate::ReadOnce( SimulatorIF::CENTER_OF_MOVABLE_MASS_Y_CFG, Units::METER, init.centerOfMovableMassY_, logger ); // centerOfMassY
    ok &= Slate::ReadOnce( SimulatorIF::CENTER_OF_MOVABLE_MASS_Z_CFG, Units::METER, init.centerOfMovableMassZ_, logger ); // centerOfMassZ

    /// Initialize the fins locations -- from vehicle.cfg
    ok &= Slate::ReadOnce( SimulatorIF::LOWER_RUDDER_X_POS_CFG, Units::METER, init.lowerRudX_, logger ); // lowerRudX
    ok &= Slate::ReadOnce( SimulatorIF::LOWER_RUDDER_Y_POS_CFG, Units::METER, init.lowerRudY_, logger ); // lowerRudY
    ok &= Slate::ReadOnce( SimulatorIF::LOWER_RUDDER_Z_POS_CFG, Units::METER, init.lowerRudZ_, logger ); // lowerRudZ

    ok &= Slate::ReadOnce( SimulatorIF::UPPER_RUDDER_X_POS_CFG, Units::METER, init.upperRudX_, logger ); // upperRudX
    ok &= Slate::ReadOnce( SimulatorIF::UPPER_RUDDER_Y_POS_CFG, Units::METER, init.upperRudY_, logger ); // upperRudY
    ok &= Slate::ReadOnce( SimulatorIF::UPPER_RUDDER_Z_POS_CFG, Units::METER, init.upperRudZ_, logger ); // upperRudZ

    ok &= Slate::ReadOnce( SimulatorIF::PORT_ELEVATOR_X_POS_CFG, Units::METER, init.portElevX_, logger ); // portElevX
    ok &= Slate::ReadOnce( SimulatorIF::PORT_ELEVATOR_Y_POS_CFG, Units::METER, init.portElevY_, logger ); // portElevY
    ok &= Slate::ReadOnce( SimulatorIF::PORT_ELEVATOR_Z_POS_CFG, Units::METER, init.portElevZ_, logger ); // portElevZ

    ok &= Slate::ReadOnce( SimulatorIF::STBD_ELEVATOR_X_POS_CFG, Units::METER, init.stbdElevX_, logger ); // stbdElevX
    ok &= Slate::ReadOnce( SimulatorIF::STBD_ELEVATOR_Y_POS_CFG, Units::METER, init.stbdElevY_, logger ); // stbdElevY
    ok &= Slate::ReadOnce( SimulatorIF::STBD_ELEVATOR_Z_POS_CFG, Units::METER, init.stbdElevZ_, logger ); // stbdElevZ

    ok &= Slate::ReadOnce( SimulatorIF::DESIGN_SPEED_CFG, Units::METER_PER_SECOND, init.designSpeed_, logger ); // designSpeed
    ok &= Slate::ReadOnce( SimulatorIF::DESIGN_PROP_EFFICIENCY_CFG, Units::RATIO, init.designPropEff_, logger ); // designPropEff
    ok &= Slate::ReadOnce( SimulatorIF::DESIGN_PROP_OMEGA_CFG, Units::RADIAN_PER_SECOND, init.designOmega_, logger ); // designOmega
    ok &= Slate::ReadOnce( SimulatorIF::DESIGN_PROP_THRUST_CFG, Units::NEWTON, init.designThrust_, logger ); // designThrust
    ok &= Slate::ReadOnce( SimulatorIF::DESIGN_PROP_TORQUE_CFG, Units::NEWTON_METER, init.designTorque_, logger ); // designTorque

    ok &= Slate::ReadOnce( SimulatorIF::DROP_WEIGHT_MASS_CFG, Units::KILOGRAM, init.dropWt1Mass_, logger ); //dropWt1Mass
    ok &= Slate::ReadOnce( SimulatorIF::DROP_WEIGHT_VOLUME_CFG, Units::CUBIC_METER, init.dropWt1Volume_, logger ); // dropWt1Volume
    ok &= Slate::ReadOnce( SimulatorIF::DROP_WEIGHT_X_POS_CFG, Units::METER, init.dropWt1X_, logger ); // dropWt1X
    ok &= Slate::ReadOnce( SimulatorIF::DROP_WEIGHT_Y_POS_CFG, Units::METER, init.dropWt1Y_, logger ); // dropWt1Y
    ok &= Slate::ReadOnce( SimulatorIF::DROP_WEIGHT_Z_POS_CFG, Units::METER, init.dropWt1Z_, logger ); // dropWt1Z

    ok &= Slate::ReadOnce( SimulatorIF::VEHICLE_BODY_CYLINDER_LENGTH_CFG, Units::METER, init.cylinderLength_, logger );
    ok &= Slate::ReadOnce( SimulatorIF::VEHICLE_BODY_CYLINDER_RADIUS_CFG, Units::METER, init.cylinderRadius_, logger );

    // Moment of Intertia terms -- from simulator.cfg
    ok &= Slate::ReadOnce( SimulatorIF::IXX_CFG, Units::KILOGRAM_METER_SQUARED, init.momentXX_, logger ); // Ixx, kg-m^2.
    ok &= Slate::ReadOnce( SimulatorIF::IYY_CFG, Units::KILOGRAM_METER_SQUARED, init.momentYY_, logger ); // Iyy, kg-m^2.
    ok &= Slate::ReadOnce( SimulatorIF::IZZ_CFG, Units::KILOGRAM_METER_SQUARED, init.momentZZ_, logger ); // Izz, kg-m^2.

    // Added mass terms -- from simulator.cfg
    ok &= Slate::ReadOnce( SimulatorIF::KPDOT_CFG, Units::KILOGRAM_METER_SQUARED, init.kpDot_, logger ); // Kpdot, kg-m^2.
    ok &= Slate::ReadOnce( SimulatorIF::MQDOT_CFG, Units::KILOGRAM_METER_SQUARED, init.mqDot_, logger ); // Mqdot, kg-m^2.
    ok &= Slate::ReadOnce( SimulatorIF::NRDOT_CFG, Units::KILOGRAM_METER_SQUARED, init.nrDot_, logger ); // Nrdot, kg-m^2.
    ok &= Slate::ReadOnce( SimulatorIF::XUDOT_CFG, Units::KILOGRAM, init.xuDot_, logger ); // Xudot, kg.
    ok &= Slate::ReadOnce( SimulatorIF::YVDOT_CFG, Units::KILOGRAM, init.yvDot_, logger ); // Yvdot, kg.
    ok &= Slate::ReadOnce( SimulatorIF::ZWDOT_CFG, Units::KILOGRAM, init.zwDot_, logger ); // Zwdot, kg.
    //
    // added mass cross terms -- from simulator.cfg
    ok &= Slate::ReadOnce( SimulatorIF::KVDOT_CFG, Units::KILOGRAM_METER, init.kvDot_, logger ); // Kvdot, kg-m.
    ok &= Slate::ReadOnce( SimulatorIF::MWDOT_CFG, Units::KILOGRAM_METER, init.mwDot_, logger ); // Mwdot, kg-m.
    ok &= Slate::ReadOnce( SimulatorIF::NVDOT_CFG, Units::KILOGRAM_METER, init.nvDot_, logger ); // Nvdot, kg-m.
    ok &= Slate::ReadOnce( SimulatorIF::YRDOT_CFG, Units::KILOGRAM_METER, init.yrDot_, logger ); // Yrdot, kg-m.
    ok &= Slate::ReadOnce( SimulatorIF::YPDOT_CFG, Units::KILOGRAM_METER, init.ypDot_, logger ); // Ypdot, kg-m.
    ok &= Slate::ReadOnce( SimulatorIF::ZQDOT_CFG, Units::KILOGRAM_METER, init.zqDot_, logger ); // Zqdot, kg-m.

    // quadratic drag -- from simulator.cfg
    ok &= Slate::ReadOnce( SimulatorIF::KPABP_CFG, Units::KILOGRAM_METER_SQUARED, init.kpabp_, logger ); // Kpabp, Kp|p| , kg-m^2
    ok &= Slate::ReadOnce( SimulatorIF::MQABQ_CFG, Units::KILOGRAM_METER_SQUARED, init.mqabq_, logger ); // Mqabq, Mq|q| , kg-m^2
    ok &= Slate::ReadOnce( SimulatorIF::NRABR_CFG, Units::KILOGRAM_METER_SQUARED, init.nrabr_, logger ); // Nrabr, Nr|r| , kg-m^2
    ok &= Slate::ReadOnce( SimulatorIF::YVABV_CFG, Units::KILOGRAM_METER, init.yvabv_, logger ); // Yvabv, Yv|v| , kg/m
    ok &= Slate::ReadOnce( SimulatorIF::ZWABW_CFG, Units::KILOGRAM_METER, init.zwabw_, logger ); // Zwabw, Zw|w| , kg/m

    // quadratic drag cross terms -- from simulator.cfg
    ok &= Slate::ReadOnce( SimulatorIF::MWABW_CFG, Units::KILOGRAM, init.mwabw_, logger ); // Mwabw, Mw|w| , kg
    ok &= Slate::ReadOnce( SimulatorIF::NVABV_CFG, Units::KILOGRAM, init.nvabv_, logger ); // Nvabv, Nv|v| , kg
    ok &= Slate::ReadOnce( SimulatorIF::YRABR_CFG, Units::NONE, init.yrabr_, logger ); // Yrabr, Yr|r| , ?
    ok &= Slate::ReadOnce( SimulatorIF::ZQABQ_CFG, Units::NONE, init.zqabq_, logger ); // Zqabq, Zq|q| , ?

    // in-line lift and drag -- from simulator.cfg
    ok &= Slate::ReadOnce( SimulatorIF::MUQ_CFG, Units::KILOGRAM_METER, init.muq_, logger ); // Muq, kg-m
    ok &= Slate::ReadOnce( SimulatorIF::MUW_CFG, Units::KILOGRAM, init.muw_, logger ); // Muw, kg
    ok &= Slate::ReadOnce( SimulatorIF::MPR_CFG, Units::KILOGRAM_METER_SQUARED, init.mpr_, logger ); // Mpr, kg-m^2
    //
    ok &= Slate::ReadOnce( SimulatorIF::NUR_CFG, Units::KILOGRAM_METER, init.nur_, logger ); // Nur, kg-m
    ok &= Slate::ReadOnce( SimulatorIF::NUV_CFG, Units::KILOGRAM, init.nuv_, logger ); // Nuv, kg
    ok &= Slate::ReadOnce( SimulatorIF::NPQ_CFG, Units::KILOGRAM_METER_SQUARED, init.npq_, logger ); // Npq, kg-m^2
    //
    ok &= Slate::ReadOnce( SimulatorIF::XVV_CFG, Units::KILOGRAM_PER_METER, init.xvv_, logger ); // Xvv, kg/m
    ok &= Slate::ReadOnce( SimulatorIF::XWW_CFG, Units::KILOGRAM_PER_METER, init.xww_, logger ); // Xww, kg/m
    ok &= Slate::ReadOnce( SimulatorIF::XVR_CFG, Units::KILOGRAM, init.xvr_, logger ); // Xvr, kg
    ok &= Slate::ReadOnce( SimulatorIF::XWQ_CFG, Units::KILOGRAM, init.xwq_, logger ); // Xwq, kg
    ok &= Slate::ReadOnce( SimulatorIF::XRR_CFG, Units::KILOGRAM_METER, init.xrr_, logger ); // Xrr, kg-m
    ok &= Slate::ReadOnce( SimulatorIF::XQQ_CFG, Units::KILOGRAM_METER, init.xqq_, logger ); // Xqq, kg-m

    ok &= Slate::ReadOnce( SimulatorIF::YUR_CFG, Units::KILOGRAM, init.yur_, logger ); // Yur, kg
    ok &= Slate::ReadOnce( SimulatorIF::YUV_CFG, Units::KILOGRAM_PER_METER, init.yuv_, logger ); // Yuv, kg/m
    ok &= Slate::ReadOnce( SimulatorIF::YWP_CFG, Units::KILOGRAM_METER, init.ywp_, logger ); // Ywp, kg-m

    ok &= Slate::ReadOnce( SimulatorIF::ZUQ_CFG, Units::KILOGRAM, init.zuq_, logger ); // Zuq, kg
    ok &= Slate::ReadOnce( SimulatorIF::ZUW_CFG, Units::KILOGRAM_PER_METER, init.zuw_, logger ); // Zuw, kg/m
    ok &= Slate::ReadOnce( SimulatorIF::ZVP_CFG, Units::KILOGRAM, init.zvp_, logger ); // Zvp, kg

    ok &= Slate::ReadOnce( SimulatorIF::KVT2_CFG, Units::NONE, init.kvt2_, logger ); // Kvt2, ?

    ok &= Slate::ReadOnce( SimulatorIF::FIN_ASPECT_RATIO_CFG, Units::RATIO, init.aspectRatio_, logger ); // aspectRatio
    ok &= Slate::ReadOnce( SimulatorIF::FIN_STALL_ANGLE_CFG, Units::RADIAN, init.stallAngle_, logger ); // stallAngle

    ok &= Slate::ReadOnce( SimulatorIF::RUDDER_HYST_WIDTH_CFG, Units::RADIAN, init.rudderHystWidth_, logger );  // wideHystRud
    ok &= Slate::ReadOnce( SimulatorIF::RUDDER_HYST_CENTER_CFG, Units::RADIAN, init.rudderHystCenter_, logger );  // centerHystRud
    ok &= Slate::ReadOnce( SimulatorIF::RUDDER_SPEED_CFG, Units::RADIAN_PER_SECOND, init.rudderSpeed_, logger );  // centerHystRud

    ok &= Slate::ReadOnce( SimulatorIF::ELEVATOR_HYST_WIDTH_CFG, Units::RADIAN, init.elevatorHystWidth_, logger );  // wideHystElev
    ok &= Slate::ReadOnce( SimulatorIF::ELEVATOR_HYST_CENTER_CFG, Units::RADIAN, init.elevatorHystCenter_, logger );  // centerHystElev
    ok &= Slate::ReadOnce( SimulatorIF::ELEVATOR_SPEED_CFG, Units::RADIAN_PER_SECOND, init.elevatorSpeed_, logger );  // centerHystElev

    ok &= Slate::ReadOnce( SimulatorIF::MASS_HYST_WIDTH_CFG, Units::METER, init.movableMassHystWidth_, logger );  // wideHystMovableMass
    ok &= Slate::ReadOnce( SimulatorIF::MASS_HYST_CENTER_CFG, Units::METER, init.movableMassHystCenter_, logger );  // centerHystMovableMass
    ok &= Slate::ReadOnce( SimulatorIF::MASS_SPEED_CFG, Units::METER_PER_SECOND, init.movableMassSpeed_, logger );  // centerHystMovableMass

    ok &= Slate::ReadOnce( SimulatorIF::BUOY_HYST_WIDTH_CFG, Units::CUBIC_METER, init.buoyancyHystWidth_, logger );  // wideHystBuoyancy
    ok &= Slate::ReadOnce( SimulatorIF::BUOY_HYST_CENTER_CFG, Units::CUBIC_METER, init.buoyancyHystCenter_, logger );  // centerHystBuoyancy
    ok &= Slate::ReadOnce( SimulatorIF::BUOY_SPEED_CFG, Units::CUBIC_METER_PER_SECOND, init.buoyancySpeed_, logger );  // centerHystBuoyancy

    ok &= Slate::ReadOnce( SimulatorIF::FIN_AREA_CFG, Units::SQUARE_METER, init.finArea_, logger ); // finArea, m^2
    ok &= Slate::ReadOnce( SimulatorIF::FIN_DRAG_COEFF_CFG, Units::RATIO, init.coeffDrag_, logger ); // CDc, Coef. of Drag, Unitless
    ok &= Slate::ReadOnce( SimulatorIF::FIN_LIFT_COEFF_CFG, Units::RATIO, init.coeffLift_, logger ); // dCL, Coef. of Lift, Unitless

    int oceanModelVarCount = 0;
    if( Slate::ReadOnce( "Config/Simulator", "oceanModelVarCount", Units::COUNT, oceanModelVarCount, logger, Syslog::NONE ) &&
            oceanModelVarCount > 0 )
    {
        if( oceanModelVarCount > SimResultStruct::MAX_SCIENCE_VALUES )
        {
            logger.syslog( Str( "Too many oceanModelVars, truncating to " ) + SimResultStruct::MAX_SCIENCE_VALUES, Syslog::FAULT );
            oceanModelVarCount = SimResultStruct::MAX_SCIENCE_VALUES;
        }
        for( int i = 1; i <= oceanModelVarCount; ++i )
        {
            StrValue oceanModelVarNameStr;
            StrValue oceanModelVarUnitStr;
            if( Slate::ReadOnce( "Config/Simulator", Str( "oceanModelVarName" ) + i, oceanModelVarNameStr, logger, Syslog::NONE ) )
            {
                if( Slate::ReadOnce( "Config/Simulator", Str( "oceanModelVarUnit" ) + i, oceanModelVarUnitStr, logger, Syslog::NONE ) )
                {
                    oceanModelStr += ":" + oceanModelVarNameStr.asString() + ":" + oceanModelVarUnitStr.asString();
                }
                else
                {
                    logger.syslog( Str( "Could not read config variable for oceanModelVarUnit" ) + i, Syslog::FAULT );
                }
            }
            else
            {
                logger.syslog( Str( "Could not read config variable for oceanModelVarName" ) + i, Syslog::FAULT );
            }
        }
    }
    logger.syslog( "oceanModelVarCount=", oceanModelVarCount );

    if( oceanModelStr.length() > sizeof( init.oceanModelData_ ) - 1 )
    {
        logger.syslog( "Model description is too long: " + oceanModelStr, Syslog::CRITICAL );
    }
    strncpy( ( char* )init.oceanModelData_, oceanModelStr.cStr(), sizeof( init.oceanModelData_ ) );

    init.time_ = Timestamp::Now().asDouble();

    return ok;
}

