// This may look like C code, but it is really -*- C++ -*-
// RTSS --- Railway Total System Simulator
// (c) TAKAGI Ryo (at Kogakuin University)
// OBESS_Voltage_Controlled.cc
//   --- implementation of class OBESS_Voltage_Controlled


#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <string>
#include <stdexcept>
#include <algorithm>
#include <typeinfo>
#include "OBESS_Voltage_Controlled.hh"
#include "globvar.hh"
#include "train.hh"

using std :: cerr ;
using std :: endl ;
using std :: fixed ;
using std :: setprecision ;
using std :: setw ;


//#define DEBUG_TRN_ESS


// -----
// Constructor of class OBESS_Voltage_Controlled using a DOM node.
// ESS_Initialiser is typedef'ed to TiXmlNode * .
// OBESS_Voltage_Controlled クラスを DOM ノードで初期化する. ESS_Initialiser は
// TiXmlNode * に typedef されている。
// -----
OBESS_Voltage_Controlled :: OBESS_Voltage_Controlled
( ESS_Initialiser const & d_in )
  : ESS_OnBoard () ,
    OBESS_Expander ()
{
  // -----
  // Checking if d_in is of tag "voltage_controlled".
  // d_in が "voltage_controlled" タグであることを確認する。
  // -----
  string d_val = string ( d_in -> Value () ) ;
  if ( d_val != "voltage_controlled" )
  {
    cerr << "Error: \"" << d_val << "\" tag not allowed for construction of "
         << "OBESS_Voltage_Controlled." << endl ;
    exit ( 1 ) ;
  }

  // -----
  // Accessing subdata.
  // 子データにアクセスする。
  // -----
  bool sw_volt = false ;
  bool sw_dc_dc = false ;
  bool sw_esd = false ;
  bool sw_volt_lowest = false ;
  bool sw_volt_low_limiter = false ;
  bool sw_volt_discharge_th_low = false ;
  bool sw_volt_discharge_th_high = false ;
  bool sw_volt_charge_th_low = false ;
  bool sw_volt_charge_th_high = false ;
  bool sw_volt_high_limiter = false ;
  bool sw_volt_maximum = false ;
  bool sw_curr_discharge = false ;
  bool sw_curr_floating = false ;
  bool sw_curr_charge = false ;
  bool sw_other_params = false ;
  for ( const TiXmlNode * _cc = d_in -> FirstChild () ;
        _cc ; _cc = _cc -> NextSibling () )
  {
    // -----
    // Ignore non-Element node.
    // エレメント以外は無視。
    // -----
    if ( _cc -> Type () != TiXmlNode :: TINYXML_ELEMENT )
      continue ;

    // -----
    // Check tag name and "execute".
    // タグ名チェックと「実行」.
    // -----
    string _cc_val = _cc -> ValueStr () ;
    if ( _cc_val == "dc_dc_converter_losses" )
    {
      // -----
      // Accessing sub-subdata.
      // 孫データにアクセスする。
      // -----
      for ( const TiXmlNode * _gc = _cc -> FirstChild () ;
            _gc ; _gc = _gc -> NextSibling () )
      {
        // -----
        // Ignore non-Element node.
        // エレメント以外は無視。
        // -----
        if ( _gc -> Type () != TiXmlNode :: TINYXML_ELEMENT )
          continue ;
        if ( sw_dc_dc )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  two or more elements within tag \"" << _cc_val
               << "\" tag are not allowed." << endl ;
          exit ( 1 ) ;
        }
        sw_dc_dc = true ;

        // -----
        // Create an object.
        // オブジェクトをつくる。
        // -----
        DC_DC_Converter_Losses * p_ddcl
          = DC_DC_Expander :: create ( _gc -> Value () , _gc ) ;
        _ddcl = p_ddcl ;
      }
      continue ;
    }
    else if ( _cc_val == "energystoragedevice" )
    {
      // -----
      // Accessing sub-subdata.
      // 孫データにアクセスする。
      // -----
      for ( const TiXmlNode * _gc = _cc -> FirstChild () ;
            _gc ; _gc = _gc -> NextSibling () )
      {
        // -----
        // Ignore non-Element node.
        // エレメント以外は無視。
        // -----
        if ( _gc -> Type () != TiXmlNode :: TINYXML_ELEMENT )
          continue ;

        if ( sw_esd )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  two or more elements within tag \"" << _cc_val
               << "\" are not allowed." << endl ;
          exit ( 1 ) ;
        }
        sw_esd = true ;

        // -----
        // Create an object.
        // オブジェクトをつくる。
        // -----
        EnergyStorageDevice * p_esd
          = ESD_Expander :: create ( _gc -> Value () , _gc ) ;
        _esd = p_esd ;
      }
      continue ;
    }
    else if ( _cc_val == "g_ess_current" || _cc_val == "g_ess_voltage" )
    {
      if ( _cc_val == "g_ess_voltage" )
      {
        // Tag "g_ess_voltage"
        sw_volt = true ;
      }
      else if ( _cc_val == "g_ess_current" )
      {
        // Tag "g_ess_current"
        sw_volt = false ;
      }

      // -----
      // Scan attributes.
      // 属性をスキャンする。
      // -----
      bool _sw_type = true ;
      string type_attr ;
      for ( TiXmlAttribute const * attr
              = _cc -> ToElement () -> FirstAttribute () ;
            attr ; attr = attr -> Next () )
      {
        if ( string ( attr -> Name () ) != "type" )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  \"" << attr -> Name ()
               << "\" attribute not allowed in tag <" << _cc_val << ">"
               << endl ;
          exit ( 1 ) ;
        }
        if ( ! _sw_type )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  \"" << attr -> Name () << "\" in tag <"
               << _cc_val << ">; appeared twice???" << endl ;
          exit ( 1 ) ;
        }
        _sw_type = false ;
        type_attr = string ( attr -> Value () ) ;
      }
      if ( _sw_type )
      {
        cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
             << endl << "  tag <" << _cc_val
             << ">: no attribute \"type\" found" << endl ;
        exit ( 1 ) ;
      }

      // -----
      // Constructing an SOCDependent object.
      // SOCDependent オブジェクトを作成する。
      // -----
      SOCDependent * sd_x = new SOCDependent ( _cc ) ;
      if ( sw_volt )
      {
        if ( type_attr == "lowest" )
        {
          if ( sw_volt_lowest )
          {
            cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
                 << endl << "  type \"lowest\" of tag <" << _cc_val
                 << "> already defined" << endl ;
            exit ( 1 ) ;
          }
          _g_ess_voltage_lowest = sd_x ;
          sw_volt_lowest = true ;
        }
        else if ( type_attr == "low_limiter" )
        {
          if ( sw_volt_low_limiter )
          {
            cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
                 << endl << "  type \"low_limiter\" of tag <" << _cc_val
                 << "> already defined" << endl ;
            exit ( 1 ) ;
          }
          _g_ess_voltage_low_limiter = sd_x ;
          sw_volt_low_limiter = true ;
        }
        else if ( type_attr == "discharge_th_low" )
        {
          if ( sw_volt_discharge_th_low )
          {
            cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
                 << endl << "  type \"discharge_th_low\" of tag <" << _cc_val
                 << "> already defined" << endl ;
            exit ( 1 ) ;
          }
          _g_ess_voltage_discharge_th_low = sd_x ;
          sw_volt_discharge_th_low = true ;
        }
        else if ( type_attr == "discharge_th_high" )
        {
          if ( sw_volt_discharge_th_high )
          {
            cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
                 << endl << "  type \"discharge_th_high\" of tag <" << _cc_val
                 << "> already defined" << endl ;
            exit ( 1 ) ;
          }
          _g_ess_voltage_discharge_th_high = sd_x ;
          sw_volt_discharge_th_high = true ;
        }
        else if ( type_attr == "charge_th_low" )
        {
          if ( sw_volt_charge_th_low )
          {
            cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
                 << endl << "  type \"charge_th_low\" of tag <" << _cc_val
                 << "> already defined" << endl ;
            exit ( 1 ) ;
          }
          _g_ess_voltage_charge_th_low = sd_x ;
          sw_volt_charge_th_low = true ;
        }
        else if ( type_attr == "charge_th_high" )
        {
          if ( sw_volt_charge_th_high )
          {
            cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
                 << endl << "  type \"charge_th_low\" of tag <" << _cc_val
                 << "> already defined" << endl ;
            exit ( 1 ) ;
          }
          _g_ess_voltage_charge_th_high = sd_x ;
          sw_volt_charge_th_high = true ;
        }
        else if ( type_attr == "high_limiter" )
        {
          if ( sw_volt_high_limiter )
          {
            cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
                 << endl << "  type \"high_limiter\" of tag <" << _cc_val
                 << "> already defined" << endl ;
            exit ( 1 ) ;
          }
          _g_ess_voltage_high_limiter = sd_x ;
          sw_volt_high_limiter = true ;
        }
        else if ( type_attr == "maximum" )
        {
          if ( sw_volt_maximum )
          {
            cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
                 << endl << "  type \"maximum\" of tag <" << _cc_val
                 << "> already defined" << endl ;
            exit ( 1 ) ;
          }
          _g_ess_voltage_maximum = sd_x ;
          sw_volt_maximum = true ;
        }
        else
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  tag <" << _cc_val << "> with incorrect type \""
               << type_attr << "\"" << endl ;
          exit ( 1 ) ;
        }
      }
      else
      {
        if ( type_attr == "discharge" )
        {
          if ( sw_curr_discharge )
          {
            cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
                 << endl << "  type \"discharge\" of tag <" << _cc_val
                 << "> already defined" << endl ;
            exit ( 1 ) ;
          }
          _g_ess_current_discharge = sd_x ;
          sw_curr_discharge = true ;
        }
        else if ( type_attr == "floating" )
        {
          if ( sw_curr_floating )
          {
            cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
                 << endl << "  type \"floating\" of tag <" << _cc_val
                 << "> already defined" << endl ;
            exit ( 1 ) ;
          }
          _g_ess_current_floating = sd_x ;
          sw_curr_floating = true ;
        }
        else if ( type_attr == "charge" )
        {
          if ( sw_curr_charge )
          {
            cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
                 << endl << "  type \"charge\" of tag <" << _cc_val
                 << "> already defined" << endl ;
            exit ( 1 ) ;
          }
          _g_ess_current_charge = sd_x ;
          sw_curr_charge = true ;
        }
        else
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  tag <" << _cc_val << "> with incorrect type \""
               << type_attr << "\"" << endl ;
          exit ( 1 ) ;
        }
      }
      continue ;
    }
    else if ( _cc_val != "other_parameters" )
    {
      cerr << "Error: \"" << _cc_val << "\" tag not allowed for construction"
           << " of a OBESS_Voltage_Controlled class object." << endl ;
      exit ( 1 ) ;
    }

    // -----
    // Tag _cc must now be <other_parameters>. Scan attributes.
    // ここではタグ _cc は必ず <other_patameters>。属性をスキャンする。
    // -----
    if ( sw_other_params )
    {
      cerr << "ERROR: duplicate tag <" << _cc_val << "> found" << endl ;
      exit ( 1 ) ;
    }
    sw_other_params = true ;
    bool _sw_max_accelerating_current_low_speed = false ;
    bool _sw_max_regenerating_current_low_speed = false ;
    bool _sw_lowest_velocity_threshold = false ;
    bool _sw_low_velocity_threshold = false ;
    bool _sw_max_accelerating_current = false ;
    bool _sw_max_regenerating_current = false ;
    bool _sw_max_charge_current = false ;
    bool _sw_max_charge_soc_low_threshold = false ;
    bool _sw_max_charge_soc_high_threshold = false ;
    bool _sw_max_discharge_current = false ;
    bool _sw_max_discharge_soc_low_threshold = false ;
    bool _sw_max_discharge_soc_high_threshold = false ;
    for ( TiXmlAttribute const *
            attr = _cc -> ToElement () -> FirstAttribute () ;
          attr ; attr = attr -> Next () )
    {
      string _atn = string ( attr -> Name () ) ;
      string _atv = string ( attr -> Value () ) ;
      if ( _atn == "max_accelerating_current_low_speed" )
      {
        // Attribute "max_accelerating_current_low_speed"
        //  -- for variable _max_accelerating_current_low_speed
        if ( _sw_max_accelerating_current_low_speed )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  Duplicate attribute \""
               << "max_accelerating_current_low_speed\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _max_accelerating_current_low_speed ) ;
        l_ofs << "Voltage OBESS: _max_accelerating_current_low_speed = " ;
        ostringstream _o_macls ;
        _o_macls << fixed << setprecision ( 2 )
                 << _max_accelerating_current_low_speed ;
        l_ofs << _o_macls . str () << endl ;
        _sw_max_accelerating_current_low_speed = true ;
      }
      else if ( _atn == "max_regenerating_current_low_speed" )
      {
        // Attribute "max_regenerating_current_low_speed"
        //  -- for variable _max_regenerating_current_low_speed
        if ( _sw_max_regenerating_current_low_speed )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  Duplicate attribute \""
               << "max_regenerating_current_low_speed\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _max_regenerating_current_low_speed ) ;
        l_ofs << "Voltage OBESS: _max_regenerating_current_low_speed = " ;
        ostringstream _o_mrcls ;
        _o_mrcls << fixed << setprecision ( 2 )
                 << _max_regenerating_current_low_speed ;
        l_ofs << _o_mrcls . str () << endl ;
        _sw_max_regenerating_current_low_speed = true ;
      }
      else if ( _atn == "lowest_velocity_threshold" )
      {
        // Attribute "lowest_velocity_threshold"
        //  -- for variable _lowest_velocity_threshold
        if ( _sw_lowest_velocity_threshold )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  Duplicate attribute \""
               << "lowest_velocity_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf", & _lowest_velocity_threshold ) ;
        l_ofs << "Voltage OBESS: _lowest_velocity_threshold = " ;
        ostringstream _o_llvt ;
        _o_llvt << fixed << setprecision ( 2 )
                << _lowest_velocity_threshold ;
        l_ofs << _o_llvt . str () << endl ;
        _sw_lowest_velocity_threshold = true ;
      }
      else if ( _atn == "low_velocity_threshold" )
      {
        // Attribute "low_velocity_threshold"
        //  -- for variable _low_velocity_threshold
        if ( _sw_low_velocity_threshold )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  Duplicate attribute \""
               << "low_velocity_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf", & _low_velocity_threshold ) ;
        l_ofs << "Voltage OBESS: _low_velocity_threshold = " ;
        ostringstream _o_lvt ;
        _o_lvt << fixed << setprecision ( 2 )
               << _low_velocity_threshold ;
        l_ofs << _o_lvt . str () << endl ;
        _sw_low_velocity_threshold = true ;
      }
      else if ( _atn == "max_accelerating_current" )
      {
        // Attribute "max_accelerating_current"
        //  -- for variable _max_accelerating_current
        if ( _sw_max_accelerating_current )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  Duplicate attribute \""
               << "max_accelerating_current\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _max_accelerating_current ) ;
        l_ofs << "Voltage OBESS: _max_accelerating_current = " ;
        ostringstream _o_mac ;
        _o_mac << fixed << setprecision ( 2 )
               << _max_accelerating_current ;
        l_ofs << _o_mac . str () << endl ;
        _sw_max_accelerating_current = true ;
      }
      else if ( _atn == "max_regenerating_current" )
      {
        // Attribute "max_regenerating_current"
        //  -- for variable _max_regenerating_current
        if ( _sw_max_regenerating_current )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  Duplicate attribute \""
               << "max_regenerating_current\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _max_regenerating_current ) ;
        l_ofs << "Voltage OBESS: _max_regenerating_current = " ;
        ostringstream _o_mrc ;
        _o_mrc << fixed << setprecision ( 2 )
               << _max_regenerating_current ;
        l_ofs << _o_mrc . str () << endl ;
        _sw_max_regenerating_current = true ;
      }
      else if ( _atn == "max_charge_current" )
      {
        // Attribute "max_charge_current"
        //  -- for variable _max_charge_current
        if ( _sw_max_charge_current )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  Duplicate attribute \""
               << "max_charge_current\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _max_charge_current ) ;
        l_ofs << "Voltage OBESS: _max_charge_current = " ;
        ostringstream _o_max_charge_current ;
        _o_max_charge_current << fixed << setprecision ( 2 )
                              << _max_charge_current ;
        l_ofs << _o_max_charge_current . str () << endl ;
        _sw_max_charge_current = true ;
      }
      else if ( _atn == "max_charge_soc_low_threshold" )
      {
        // Attribute "max_charge_soc_low_threshold"
        //  -- for variable _max_charge_soc_low_threshold
        if ( _sw_max_charge_soc_low_threshold )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  Duplicate attribute \""
               << "max_charge_soc_low_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _max_charge_soc_low_threshold ) ;
        l_ofs << "Voltage OBESS: _max_charge_soc_low_threshold = " ;
        ostringstream _o_max_charge_soc_low_threshold ;
        _o_max_charge_soc_low_threshold << fixed << setprecision ( 2 )
                                        << _max_charge_soc_low_threshold ;
        l_ofs << _o_max_charge_soc_low_threshold . str () << endl ;
        _sw_max_charge_soc_low_threshold = true ;
      }
      else if ( _atn == "max_charge_soc_high_threshold" )
      {
        // Attribute "max_charge_soc_high_threshold"
        //  -- for variable _max_charge_soc_high_threshold
        if ( _sw_max_charge_soc_high_threshold )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  Duplicate attribute \""
               << "max_charge_soc_high_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _max_charge_soc_high_threshold ) ;
        l_ofs << "Voltage OBESS: _max_charge_soc_high_threshold = " ;
        ostringstream _o_max_charge_soc_high_threshold ;
        _o_max_charge_soc_high_threshold << fixed << setprecision ( 2 )
                                         << _max_charge_soc_high_threshold ;
        l_ofs << _o_max_charge_soc_high_threshold . str () << endl ;
        _sw_max_charge_soc_high_threshold = true ;
      }
      else if ( _atn == "max_discharge_current" )
      {
        // Attribute "max_discharge_current"
        //  -- for variable _max_discharge_current
        if ( _sw_max_discharge_current )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  Duplicate attribute \""
               << "max_discharge_current\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _max_discharge_current ) ;
        l_ofs << "Voltage OBESS: _max_discharge_current = " ;
        ostringstream _o_max_discharge_current ;
        _o_max_discharge_current << fixed << setprecision ( 2 )
                                 << _max_discharge_current ;
        l_ofs << _o_max_discharge_current . str () << endl ;
        _sw_max_discharge_current = true ;
      }
      else if ( _atn == "max_discharge_soc_low_threshold" )
      {
        // Attribute "max_discharge_soc_low_threshold"
        //  -- for variable _max_discharge_soc_low_threshold
        if ( _sw_max_discharge_soc_low_threshold )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  Duplicate attribute \""
               << "max_discharge_soc_low_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _max_discharge_soc_low_threshold ) ;
        l_ofs << "Voltage OBESS: _max_discharge_soc_low_threshold = " ;
        ostringstream _o_mdslt ;
        _o_mdslt << fixed << setprecision ( 2 )
                 << _max_discharge_soc_low_threshold ;
        l_ofs << _o_mdslt . str () << endl ;
        _sw_max_discharge_soc_low_threshold = true ;
      }
      else if ( _atn == "max_discharge_soc_high_threshold" )
      {
        // Attribute "max_discharge_soc_high_threshold"
        //  -- for variable _max_discharge_soc_high_threshold
        if ( _sw_max_discharge_soc_high_threshold )
        {
          cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
               << endl << "  Duplicate attribute \""
               << "max_discharge_soc_high_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _max_discharge_soc_high_threshold ) ;
        l_ofs << "Voltage OBESS: _max_discharge_soc_high_threshold = " ;
        ostringstream _o_mdsht ;
        _o_mdsht << fixed << setprecision ( 2 )
                 << _max_discharge_soc_high_threshold ;
        l_ofs << _o_mdsht . str () << endl ;
        _sw_max_discharge_soc_high_threshold = true ;
      }
      else
      {
        cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
             << endl
             << "  Attribute \"" << _atn << "\" not allowed" << endl ;
        exit ( 1 ) ;
      }
    }
    if ( ! ( _sw_max_accelerating_current_low_speed
             && _sw_max_regenerating_current_low_speed
             && _sw_lowest_velocity_threshold && _sw_low_velocity_threshold
             && _sw_max_accelerating_current && _sw_max_regenerating_current
             && _sw_max_charge_current && _sw_max_charge_soc_low_threshold
             && _sw_max_charge_soc_high_threshold
             && _sw_max_discharge_current
             && _sw_max_discharge_soc_low_threshold
             && _sw_max_discharge_soc_high_threshold ) )
    {
      cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
           << endl << "  Some of the required attribute(s) missing in tag "
           << "<other_parameters>" << endl ;
      exit ( 1 ) ;
    }

    // ----
    // Data check.
    // ----
    if ( _max_accelerating_current < 0 )
    {
      cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
           << endl << "  _max_accelerating_current must be positive"
           << endl ;
      exit ( 1 ) ;
    }
    if ( _max_regenerating_current < 0 )
    {
      cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
           << endl << "  _max_regenrating_current must be positive"
           << endl ;
      exit ( 1 ) ;
    }
    if ( _max_accelerating_current_low_speed < 0 )
    {
      cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
           << endl << "  _max_accelerating_current_low_speed must be positive"
           << endl ;
      exit ( 1 ) ;
    }
    if ( _max_regenerating_current_low_speed < 0 )
    {
      cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
           << endl << "  _max_regenrating_current_low_speed must be positive"
           << endl ;
      exit ( 1 ) ;
    }
    if ( _max_accelerating_current_low_speed >= _max_accelerating_current )
    {
      cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
           << endl << "  _max_accelerating_current_low_speed must be smaller"
           << endl << "  than _max_accelerating_current"
           << endl ;
      exit ( 1 ) ;
    }
    if ( _max_regenerating_current_low_speed >= _max_regenerating_current )
    {
      cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
           << endl << "  _max_regenerating_current_low_speed must be smaller"
           << endl << "  than _max_regenerating_current"
           << endl ;
      exit ( 1 ) ;
    }
    if ( _lowest_velocity_threshold < INVLIM
         || _lowest_velocity_threshold > _low_velocity_threshold )
    {
      cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
           << endl << "  _low(*)_velocity_threshold "
           << "inconsistently configured" << endl ;
      exit ( 1 ) ;
    }
    if ( _max_discharge_current < 0 )
    {
      cerr << "Error initialising OBESS_Voltage_Controlled in P file:" << endl
           << "  _max_discharge_current must be positive" << endl ;
      exit ( 1 ) ;
    }
    if ( _max_discharge_soc_low_threshold < - INVLIM
         || _max_discharge_soc_low_threshold
         > _max_discharge_soc_high_threshold
         || _max_discharge_soc_high_threshold > 100 + INVLIM )
    {
      cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
           << endl << "  _max_discharge_soc_(*)_threshold "
           << "inconsistently configured" << endl ;
      exit ( 1 ) ;
    }
    if ( _max_charge_current < 0 )
    {
      cerr << "Error initialising OBESS_Voltage_Controlled in P file:" << endl
           << "  _max_charge_current must be positive" << endl ;
      exit ( 1 ) ;
    }
    if ( _max_charge_soc_low_threshold < - INVLIM
         || _max_charge_soc_low_threshold > _max_charge_soc_high_threshold
         || _max_charge_soc_high_threshold > 100 + INVLIM )
    {
      cerr << "Error initialising OBESS_Voltage_Controlled in P file:"
           << endl << "  _max_charge_soc_(*)_threshold "
           << "inconsistently configured" << endl ;
      exit ( 1 ) ;
    }
  }
  if ( ! ( sw_dc_dc && sw_esd && sw_volt_lowest && sw_volt_low_limiter
           && sw_volt_discharge_th_low && sw_volt_discharge_th_high
           && sw_volt_charge_th_low && sw_volt_charge_th_high
           && sw_volt_high_limiter && sw_volt_maximum && sw_curr_discharge
           && sw_curr_floating && sw_curr_charge && sw_other_params ) )
  {
    cerr << "ERROR: data missing in tag <voltage_controlled>" << endl ;
    exit ( 1 ) ;
  }
}




// -----
// Copy constructor.
// コピーコンストラクタ.
// -----
OBESS_Voltage_Controlled :: OBESS_Voltage_Controlled
( OBESS_Voltage_Controlled const & e_in )
  : ESS_OnBoard	( e_in ) ,
    OBESS_Expander () ,
    _max_accelerating_current_low_speed
    ( e_in . _max_accelerating_current_low_speed ) ,
    _max_regenerating_current_low_speed
    ( e_in . _max_regenerating_current_low_speed ) ,
    _lowest_velocity_threshold ( e_in . _lowest_velocity_threshold ) ,
    _low_velocity_threshold ( e_in . _low_velocity_threshold ) ,
    _max_accelerating_current ( e_in . _max_accelerating_current ) ,
    _max_regenerating_current ( e_in . _max_regenerating_current ) ,
    _max_charge_current ( e_in . _max_charge_current ) ,
    _max_charge_soc_low_threshold ( e_in . _max_charge_soc_low_threshold ) ,
    _max_charge_soc_high_threshold ( e_in . _max_charge_soc_high_threshold ) ,
    _max_discharge_current ( e_in . _max_discharge_current ) ,
    _max_discharge_soc_low_threshold
    ( e_in . _max_discharge_soc_low_threshold ) ,
    _max_discharge_soc_high_threshold
    ( e_in . _max_discharge_soc_high_threshold ) ,
    _voltage_lowest ( e_in . _voltage_lowest ) ,
    _voltage_low_limiter ( e_in . _voltage_low_limiter ) ,
    _voltage_discharge_th_low ( e_in . _voltage_discharge_th_low ) ,
    _voltage_discharge_th_high ( e_in . _voltage_discharge_th_high ) ,
    _voltage_charge_th_low ( e_in . _voltage_charge_th_low ) ,
    _voltage_charge_th_high ( e_in . _voltage_charge_th_high ) ,
    _voltage_high_limiter ( e_in . _voltage_high_limiter ) ,
    _voltage_maximum ( e_in . _voltage_maximum ) ,
    _current_discharge ( e_in . _current_discharge ) ,
    _current_floating ( e_in . _current_floating ) ,
    _current_charge ( e_in . _current_charge ) ,
    _v ( e_in . _v ) ,
    _i ( e_in . _i ) ,
    _dv_dth ( e_in . _dv_dth ) ,
    _di_dth ( e_in . _di_dth )
{
  _esd = e_in . _esd -> getMyClone () ;
  _ddcl = e_in . _ddcl -> getMyClone () ;
  _g_ess_voltage_lowest
    = e_in . _g_ess_voltage_lowest -> getMyClone () ;
  _g_ess_voltage_low_limiter
    = e_in . _g_ess_voltage_low_limiter -> getMyClone () ;
  _g_ess_voltage_discharge_th_low
    = e_in . _g_ess_voltage_discharge_th_low -> getMyClone () ;
  _g_ess_voltage_discharge_th_high
    = e_in . _g_ess_voltage_discharge_th_high -> getMyClone () ;
  _g_ess_voltage_charge_th_low
    = e_in . _g_ess_voltage_charge_th_low -> getMyClone () ;
  _g_ess_voltage_charge_th_high
    = e_in . _g_ess_voltage_charge_th_high -> getMyClone () ;
  _g_ess_voltage_high_limiter
    = e_in . _g_ess_voltage_high_limiter -> getMyClone () ;
  _g_ess_voltage_maximum
    = e_in . _g_ess_voltage_maximum -> getMyClone () ;
  _g_ess_current_discharge
    = e_in . _g_ess_current_discharge -> getMyClone () ;
  _g_ess_current_floating
    = e_in . _g_ess_current_floating -> getMyClone () ;
  _g_ess_current_charge
    = e_in . _g_ess_current_charge -> getMyClone () ;
}




// -----
// Destructor.
// デストラクタ.
// -----
OBESS_Voltage_Controlled :: ~OBESS_Voltage_Controlled
()
{
  delete _esd ;
  delete _ddcl ;
  delete _g_ess_voltage_lowest ;
  delete _g_ess_voltage_low_limiter ;
  delete _g_ess_voltage_discharge_th_low ;
  delete _g_ess_voltage_discharge_th_high ;
  delete _g_ess_voltage_charge_th_low ;
  delete _g_ess_voltage_charge_th_high ;
  delete _g_ess_voltage_high_limiter ;
  delete _g_ess_voltage_maximum ;
  delete _g_ess_current_discharge ;
  delete _g_ess_current_floating ;
  delete _g_ess_current_charge ;
}




// -----
// Substitution operator.
// 代入演算子.
// -----
OBESS_Voltage_Controlled &
OBESS_Voltage_Controlled :: operator=
( ESS_OnBoard const & y )
{
  try
  {
    OBESS_Voltage_Controlled const & x
      = dynamic_cast < OBESS_Voltage_Controlled const & > ( y ) ;
    if ( & x == this )
    {
      return * this ;
    }

    // -----
    // Voltage, current, dv/dth and di/dth are the only variables that must
    // be copied.
    // 電圧，電流，dv/dθ および di/dθ のみがコピーすべきものである。
    // -----
    _v = x . _v ;
    _i = x . _i ;
    _dv_dth = x . _dv_dth ;
    _di_dth = x . _di_dth ;

    return * this ;
  }
  catch ( std :: bad_cast & bc )
  {
    cerr << "Error: bad cast at OBESS_Voltage_Controlled::operator=(...):"
         << endl << "  message: " << bc . what () << endl ;
    exit ( 1 ) ;
  }
}




// -----
// Calculate the state (voltage and current) of the system.
// システムの状態（電圧・電流）の計算
// 計算すべき変数：
//  ★ _pf -> __a_wo_capper: current capping しない場合の電流（主回路）
//  以下はすべて current capping 後
//  ★ _i: OBESSの電流 (正値: 放電)
//  ★ _pf -> __noshibo: 回生絞込前の電流（主回路）
//  ★ _pf -> __a: パンタ点電流（主回路＋OBESS），呼出前は = __noshibo
//  ★ _pf -> __a_main_circuit: 主回路電流，= __a - _i
//  ★ _pf -> __rnotch_for_capper: = __noshibo / __a_wo_capper
//  ★ _pf -> __di: 電流 (__a) の媒介変数微分値
// -----
void
OBESS_Voltage_Controlled :: calculateVoltagesAndCurrents
( train_ParamFunc * _pf )
{
#ifdef DEBUG_TRN_ESS
  l_ofs << "car " << _pf -> getCarNumber ()
        << ": OBESS Voltage, VI cal" << endl ;
  l_ofs << " _i, __a_mc, __noshibo, __a = " << _i << ", "
        << _pf -> getMainCircuitCurrent () << ", "
        << _pf -> getCurrentWithoutLimiter () << ", "
        << _pf -> getCurrent () << endl ;
#endif

  // -----
  // Setting parameters.
  // パラメータのセット.
  // -----

  // これらは車両全体で同一 !!!
  _v = _pf -> getVoltage () ;		// OBESS の電圧 v
  _dv_dth = _pf -> get_dV_dTheta () ;	// OBESS の dv / dθ

#ifdef DEBUG_TRN_ESS
  l_ofs << " _v, _dv_dth = " << _v << ", " << _dv_dth << endl ;
#endif

  double _soc = getSOC () ;		// SOC

  double _vel = _pf -> getVelocity () ;	// 列車速度

#ifdef DEBUG_TRN_ESS
  double _pos = _pf -> getPosition () ;	// 列車位置
  l_ofs << " _pos, _vel, _soc = " << _pos << ", " << _vel
        << ", " << _soc << endl ;
#endif

  _voltage_lowest = _g_ess_voltage_lowest -> getData ( _soc ) ;
  _voltage_low_limiter = _g_ess_voltage_low_limiter -> getData ( _soc ) ;
  if ( _voltage_low_limiter <= _voltage_lowest - INVLIM )
  {
    cerr << "ERROR: OBESS_Voltage_Controlled: violation of voltage parameters: "
         << "low limiter voltage and lowest voltage: " << _voltage_low_limiter
         << " <= " << _voltage_lowest << ", at SOC = " << _soc << endl ;
    exit ( 1 ) ;
  }
  _voltage_discharge_th_low
    = _g_ess_voltage_discharge_th_low -> getData ( _soc ) ;
  if ( _voltage_discharge_th_low <=_voltage_low_limiter - INVLIM )
  {
    cerr << "ERROR: OBESS_Voltage_Controlled: violation of voltage parameters: "
         << "lower threshold of discharge voltage and low limiter voltage: "
         << _voltage_discharge_th_low << " <= " << _voltage_low_limiter
         << ", at SOC = " << _soc << endl ;
    exit ( 1 ) ;
  }
  _voltage_discharge_th_high
    = _g_ess_voltage_discharge_th_high -> getData ( _soc ) ;
  if ( _voltage_discharge_th_high <= _voltage_discharge_th_low - INVLIM )
  {
    cerr << "ERROR: OBESS_Voltage_Controlled: violation of voltage parameters: "
         << "higher and lower thresholds of discharge voltages: "
         << _voltage_discharge_th_high << " <= " << _voltage_discharge_th_low
         << ", at SOC = " << _soc << endl ;
    exit ( 1 ) ;
  }
  _voltage_charge_th_low = _g_ess_voltage_charge_th_low -> getData ( _soc ) ;
  if ( _voltage_charge_th_low <= _voltage_discharge_th_high - INVLIM )
  {
    cerr << "ERROR: OBESS_Voltage_Controlled: violation of voltage parameters: "
         << "lower threshold of charge voltage and higher threshold of "
         << "discharge voltage: " << _voltage_discharge_th_high << " <= "
         << _voltage_discharge_th_low << ", at SOC = " << _soc << endl ;
    exit ( 1 ) ;
  }
  _voltage_charge_th_high
    = _g_ess_voltage_charge_th_high -> getData ( _soc ) ;
  if ( _voltage_charge_th_high <= _voltage_charge_th_low - INVLIM )
  {
    cerr << "ERROR: OBESS_Voltage_Controlled: violation of voltage parameters: "
         << "higher and lower thresholds of charge voltages: "
         << _voltage_charge_th_high << " <= " << _voltage_charge_th_low
         << ", at SOC = " << _soc << endl ;
    exit ( 1 ) ;
  }
  _voltage_high_limiter = _g_ess_voltage_high_limiter -> getData ( _soc ) ;
  if ( _voltage_high_limiter <= _voltage_charge_th_high - INVLIM )
  {
    cerr << "ERROR: OBESS_Voltage_Controlled: violation of voltage parameters: "
         << "high limiter voltage and higher threshold of charge voltage: "
         << _voltage_high_limiter << " <= " << _voltage_charge_th_high
         << ", at SOC = " << _soc << endl ;
    exit ( 1 ) ;
  }
  _voltage_maximum = _g_ess_voltage_maximum -> getData ( _soc ) ;
  if ( _voltage_maximum <= _voltage_high_limiter - INVLIM )
  {
    cerr << "ERROR: OBESS_Voltage_Controlled: violation of voltage parameters: "
         << "maximum voltage and high limiter voltage: "
         << _voltage_maximum << " <= " << _voltage_high_limiter
         << ", at SOC = " << _soc << endl ;
    exit ( 1 ) ;
  }
  _current_discharge = _g_ess_current_discharge -> getData ( _soc ) ;
  _current_floating = _g_ess_current_floating -> getData ( _soc ) ;
  _current_charge = _g_ess_current_charge -> getData ( _soc ) ;

  // -----
  // Calculating _i and _di_dth. Copied from class Generic_ESS_Substation.
  // _i と _di_dth の計算。Generic_ESS_Substation クラスからのコピー。
  // -----
  double _di_dv ;
  if ( _v < _voltage_lowest )
  {
    _i = 0 ;
    _di_dv = 0 ;
  }
  else if ( _v < _voltage_low_limiter )
  {
    _i = _current_discharge * ( _v - _voltage_lowest ) ;
    _i /= _voltage_low_limiter - _voltage_lowest ;
    _di_dv = _current_discharge ;
    _di_dv /= _voltage_low_limiter - _voltage_lowest ;
  }
  else if ( _v < _voltage_discharge_th_low )
  {
    _i = _current_discharge ;
    _di_dv = 0 ;
  }
  else if ( _v < _voltage_discharge_th_high )
  {
    _i = _current_floating - _current_discharge ;
    _i *= _v - _voltage_discharge_th_low ;
    _i /= _voltage_discharge_th_high - _voltage_discharge_th_low ;
    _i += _current_discharge ;
    _di_dv = _current_floating - _current_discharge ;
    _di_dv /= _voltage_discharge_th_high - _voltage_discharge_th_low ;
  }
  else if ( _v < _voltage_charge_th_low )
  {
    _i = _current_floating ;
    _di_dv = 0 ;
  }
  else if ( _v < _voltage_charge_th_high )
  {
    _i = _current_charge - _current_floating ;
    _i *= _v - _voltage_charge_th_low ;
    _i /= _voltage_charge_th_high - _voltage_charge_th_low ;
    _i += _current_floating ;
    _di_dv = _current_charge - _current_floating ;
    _di_dv /= _voltage_charge_th_high - _voltage_charge_th_low ;
  }
  else if ( _v < _voltage_high_limiter )
  {
    _i = _current_charge ;
    _di_dv = 0 ;
  }
  else if ( _v < _voltage_maximum )
  {
    _i = - _current_charge ;
    _i *= _v - _voltage_high_limiter ;
    _i /= _voltage_maximum - _voltage_high_limiter ;
    _i += _current_charge ;
    _di_dv = - _current_charge ;
    _di_dv /= _voltage_maximum - _voltage_high_limiter ;
  }
  else
  {
    _i = 0 ;
    _di_dv = 0 ;
  }
  _di_dth = _di_dv * _dv_dth ;

  // ----
  // The maximum charge / discharge power of the energy storage device plus
  // DC-DC converter losses will set the limit to the charge / discharge
  // current of the ESS.
  // ----
#ifdef DEBUG_TRN_ESS
  l_ofs << "TRN_ESS(V): _i, _di_dth before processESDMaximumLimits: "
        << _i << ", " << _di_dth << endl ;
#endif
  processESDMaximumLimits () ;

  // ----
  // Add _i and _di_dth with the main circuit current and its derivatlves.
  // _i と _di_dth を主回路の電流およびその微分値と合計してみる.
  // ----
  double _trn_a = _pf -> getCurrent () ;
  double _total_current = _i + _trn_a ;
#ifdef DEBUG_TRN_ESS
  l_ofs << " _total (1), _i, _trn_a, max_regen, max_accel = "
        << _total_current << ", " << _i << ", " << _trn_a
        << ", " << _max_regenerating_current << ", "
        << _max_accelerating_current << endl ;
#endif

  // ----
  // Maximum current checks.
  // The maximum charge / discharge current limit of the energy storage system
  // to be imposed in low velocity region. Note: Charge current is NEGATIVE.
  // ----
  double _max_a = _max_accelerating_current ;
  double _max_r = _max_regenerating_current ;
  if ( _vel < _lowest_velocity_threshold )
  {
    _max_a = _max_accelerating_current_low_speed ;
    _max_r = _max_regenerating_current_low_speed ;
  }
  else if ( _vel < _low_velocity_threshold )
  {
    _max_a -= _max_accelerating_current_low_speed ;
    _max_r -= _max_regenerating_current_low_speed ;
    _max_a *= _vel - _lowest_velocity_threshold ;
    _max_r *= _vel - _lowest_velocity_threshold ;
    _max_a /= _low_velocity_threshold
      - _lowest_velocity_threshold ;
    _max_r /= _low_velocity_threshold
      - _lowest_velocity_threshold ;
    _max_a += _max_accelerating_current_low_speed ;
    _max_r += _max_regenerating_current_low_speed ;
  }
  if ( _total_current > _max_r )
  {
#ifdef DEBUG_TRN_ESS
    l_ofs << " _total (1) > _max_regen = " << _max_r << endl ;
#endif

    // Set _pf -> __a and _pf -> __di
    _pf -> setCurrent ( _max_r ) ;
    _pf -> set_Di_Dtheta ( 0 ) ;
#ifdef DEBUG_TRN_ESS
    l_ofs << " _total (2) = " << _pf -> getCurrent () << endl ;
#endif

    // Setting _i and (where necessary) _pf -> __noshibo
    _di_dth = 0 ;

    // ###############################################
    // Maximum-ESD-current limiter must be included in
    // getMaximumChargeCurrent () member function.
    // ###############################################
    double _max_c = getMaximumChargeCurrent () ;
    double _i_red = _total_current - _max_r ;
#ifdef DEBUG_TRN_ESS
    l_ofs << " _i, _trn_a , _max_c, _i_red = " << _i << ", " << _trn_a
          << ", " << _max_c << ", " << _i_red << endl ;
#endif
    if ( _i - _i_red > _max_c )
    {
      _i -= _i_red ;
    }
    else
    {
      double _i_red_obess = _i - _max_c ;
      _i = _max_c ;
      _trn_a -= _i_red - _i_red_obess ;
      if ( _trn_a < 0 )
      {
        cerr << "Warning: in OBESS_Voltage_Controlled:" << endl
             << "  Main circuit current below zero in regeneration" << endl ;
        _trn_a = 0 ;
      }

      // Setting _pf -> __noshibo and _pf -> __a_main_circuit
      _pf -> setCurrentWithoutLimiter ( _trn_a ) ;
      _pf -> setMainCircuitCurrent ( _trn_a ) ;

      // Setting _pf -> __rnotch_for_capper
      _pf -> setNotchRateForCapper
        ( _trn_a / _pf -> getCurrentWithoutCapper () ) ;
    }
#ifdef DEBUG_TRN_ESS
    l_ofs << " _i, _trn_a changed to = " << _i << ", " << _trn_a << endl
          << " Notch rage for capper: " << _pf -> getNotchRateForCapper ()
          << endl ;
    l_ofs << " _i, __a_mc, __noshibo, __a = " << _i << ", "
          << _pf -> getMainCircuitCurrent () << ", "
          << _pf -> getCurrentWithoutLimiter () << ", "
          << _pf -> getCurrent () << endl ;
#endif
  }
  else if ( _total_current < - _max_a )
  {
#ifdef DEBUG_TRN_ESS
    l_ofs << " _total (1) > _max_accel = " << _max_a << endl ;
#endif

    // Set _pf -> __a and _pf -> __di
    _pf -> setCurrent ( - _max_a ) ;
    _pf -> set_Di_Dtheta ( 0 ) ;
#ifdef DEBUG_TRN_ESS
    l_ofs << " _total (2) = " << _pf -> getCurrent () << endl ;
#endif

    // Setting _i and (where necessary) _pf -> __noshibo
    _di_dth = 0 ;
    // ###############################################
    // Maximum-ESD-current limiter must be included in
    // getMaximumDischargeCurrent () member function.
    // ###############################################
    double _max_d = getMaximumDischargeCurrent () ;
    double _i_minc = _total_current + _max_a ;
#ifdef DEBUG_TRN_ESS
    l_ofs << " _i, _trn_a , _max_d, _i_minc = " << _i << ", " << _trn_a
          << ", " << _max_d << ", " << _i_minc << endl ;
#endif
    if ( _i - _i_minc < _max_d )
    {
      _i -= _i_minc ;
    }
    else
    {
      double _i_minc_obess = _i - _max_d ;
      _i = _max_d ;
      _trn_a -= _i_minc - _i_minc_obess ;
      if ( _trn_a > 0 )
      {
        cerr << "Warning: in OBESS_Voltage_Controlled:" << endl
             << "  Main circuit current above zero in acceleration" << endl ;
        _trn_a = 0 ;
      }

      // Setting _pf -> __noshibo and _pf -> __a_main_circuit
      _pf -> setCurrentWithoutLimiter ( _trn_a ) ;
      _pf -> setMainCircuitCurrent ( _trn_a ) ;

      // Setting _pf -> __rnotch_for_capper
      _pf -> setNotchRateForCapper
        ( _trn_a / _pf -> getCurrentWithoutCapper () ) ;
    }
#ifdef DEBUG_TRN_ESS
    l_ofs << " _i, _trn_a changed to = " << _i << ", " << _trn_a << endl
          << " Notch rage for capper: " << _pf -> getNotchRateForCapper ()
          << endl ;
    l_ofs << " _i, __a_mc, __noshibo, __a = " << _i << ", "
          << _pf -> getMainCircuitCurrent () << ", "
          << _pf -> getCurrentWithoutLimiter () << ", "
          << _pf -> getCurrent () << endl ;
#endif
  }
  else
  {
    _pf -> setCurrent ( _total_current ) ;
    double _di_out = _pf -> get_Di_Dtheta () + _di_dth ;
    _pf -> set_Di_Dtheta ( _di_out ) ;
    _pf -> setNotchRateForCapper ( 1.0 ) ;
#ifdef DEBUG_TRN_ESS
    l_ofs << " _i, _trn_a changed to = " << _i << ", " << _trn_a << endl
          << " Notch rage for capper: " << _pf -> getNotchRateForCapper ()
          << endl ;
    l_ofs << "car " << _pf -> getCarNumber ()
          << ": OBESS Voltage, VI cal" << endl ;
    l_ofs << " _i, __a_mc, __noshibo, __a = " << _i << ", "
          << _pf -> getMainCircuitCurrent () << ", "
          << _pf -> getCurrentWithoutLimiter () << ", "
          << _pf -> getCurrent () << endl ;
#endif
  }
#ifdef DEBUG_TRN_ESS
  l_ofs << "car " << _pf -> getCarNumber ()
        << ": OBESS Voltage, VI cal end" << endl ;
  l_ofs << " _i, __a_mc, __noshibo, __a = " << _i << ", "
        << _pf -> getMainCircuitCurrent () << ", "
        << _pf -> getCurrentWithoutLimiter () << ", "
        << _pf -> getCurrent () << endl ;
#endif
}




// -----
// Process maximum charge/discharge limit imposed by the ESD. This will
// supersede the I-V characteristics given by the reference SOC curve
// and other characteristic parameters.
// -----
void
OBESS_Voltage_Controlled :: processESDMaximumLimits
()
{
#ifdef DEBUG_TRN_ESS
  l_ofs << "TRN_ESS(V): in ORSC::processESDMaximumLimits" << endl ;
#endif
  // ----
  // To be modified: _i and _di_dth.
  // When to modify them: when fabs ( _i * _v - (DC-DC conv losses) )
  //  > fabs (ESD max power).
  // Assumption: DC-DC converter can accept maximum charge/discharge power
  //  from the ESD at all conditions, i.e. ESD maximum power is constant.
  // How to do it: DC-DC converter losses are unknown. 
  // Note: Discharge power is positive.
  // ----

  // ----
  // ESD max power, and voltage & current when accepting this max power.
  // ----
  double _v_dev_mc = 0 ;
  double _i_dev_mc = 0 ;
  double _max_esd_power_c
    = _esd -> getMaximumChargePower ( _v_dev_mc , _i_dev_mc ) ;

  double _v_dev_md = 0 ;
  double _i_dev_md = 0 ;
  double _max_esd_power_d
    = _esd -> getMaximumDischargePower ( _v_dev_md , _i_dev_md ) ;
#ifdef DEBUG_TRN_ESS
  l_ofs << "TRN_ESS(V): max Pc, Pd: " << _max_esd_power_c << ", "
        << _max_esd_power_d << endl ;
#endif

  // ----
  // Maximum power seen at the other end of DC-DC converter.
  // ----
  double _max_ddcl_c
    = _ddcl -> getLosses ( _v_dev_mc * _i_dev_mc , _v , _v_dev_mc , false ) ;
  double _max_power_c = - _max_esd_power_c - _max_ddcl_c ;
  double _max_ddcl_d
    = _ddcl -> getLosses ( _v_dev_md * _i_dev_md , _v , _v_dev_md , false ) ;
  double _max_power_d = _max_esd_power_d - _max_ddcl_d ;

  // ----
  // Check if the device power is not exceeding maximum ...
  // Note that discharge power is positive and charge power is negative, i.e.
  // power must be between _max_power_c and _max_power_d.
  // ----
  double _p_ess = _v * _i ;
#ifdef DEBUG_TRN_ESS
  l_ofs << "TRN_ESS(V): ess power = " << _p_ess << endl ;
#endif
  if ( _p_ess < _max_power_c )
  {
#ifdef DEBUG_TRN_ESS
    l_ofs << "TRN_ESS(V): charge dev power capping" << endl ;
#endif
    _i = _max_power_c / _v ;
    _di_dth = - _i * _dv_dth / _v ;
#ifdef DEBUG_TRN_ESS
    l_ofs << "TRN_ESS(V): _i, _di_dth: " << _i << ", " << _di_dth << endl ;
#endif
  }
  else if ( _p_ess > _max_power_d )
  {
#ifdef DEBUG_TRN_ESS
    l_ofs << "TRN_ESS(V): discharge dev power capping" << endl ;
#endif
    _i = _max_power_d / _v ;
    _di_dth = - _i * _dv_dth / _v ;
#ifdef DEBUG_TRN_ESS
    l_ofs << "TRN_ESS(V): _i, _di_dth: " << _i << ", " << _di_dth << endl ;
#endif
  }
  else
  {
#ifdef DEBUG_TRN_ESS
    l_ofs << "TRN_ESS(V): no power capping necessary" << endl ;
#endif
  }
}



// -----
// Modify system state (voltage and current) after regen limiter.
// 回生絞込に対応した状態（電圧・電流）補正.
// -----
void
OBESS_Voltage_Controlled :: processRegenerationLimiter
( train_ParamFunc * _pf )
{
  // (4) _pf -> __a < _pf -> __noshibo + _i であれば何かする。
#ifdef DEBUG_TRN_ESS
  l_ofs << "car " << _pf -> getCarNumber ()
        << ": OBESS Voltage, procRegenLim" << endl ;
  l_ofs << " _i, __a_mc, __noshibo, __a = " << _i << ", "
        << _pf -> getMainCircuitCurrent () << ", "
        << _pf -> getCurrentWithoutLimiter () << ", "
        << _pf -> getCurrent () << endl ;
#endif
  double _old_total_current = _pf -> getCurrentWithoutLimiter () + _i ;
  double _new_total_current = _pf -> getCurrent () ;
  if ( _new_total_current > _old_total_current + INVLIM )
  {
    // The new total current must be equal to or LESS THAN the old value.
    cerr << "Error in OBESS_Voltage_Controlled:" << endl
         << "  Total current increased after regeneration limiter process"
         << endl ;
    exit ( 1 ) ;
  }
  if ( _new_total_current < _old_total_current )
  {
    double _max_c = getMaximumChargeCurrent () ;
    if ( _i + _new_total_current - _old_total_current < _max_c )
    {
      _i = _max_c ;
    }
    else
    {
      _i += _new_total_current - _old_total_current ;
    }
  }
  _pf -> setMainCircuitCurrent ( _new_total_current - _i ) ;
}




// -----
// Calculate ESD voltage and current.
// -----
void
OBESS_Voltage_Controlled :: calculateESDVoltageAndCurrent
( train_ParamFunc * _pf )
{
  // ----
  // The device voltage.
  // 素子電圧。
  // ----
  double _vi = 0 ;

  // ----
  // The device current.
  // 素子電流。
  // ----
  double _idev = 0 ;

  // ----
  // Execute the Newton-Raphson routine to get _vi and _idev.
  // ----
  getESDVoltageAndCurrent ( _v , _i , _vi , _idev ) ;

  // ----
  // Renewing states of the DC-DC converter.
  // DC-DC コンバータの状態を更新。
  // ----
  _ddcl -> calculateESDVoltageAndCurrent ( _vi , _idev ) ;

  // ----
  // Renewing states of the energy storage device.
  // エネルギー蓄積素子の状態を更新。
  // ----
  _esd -> calculateESDVoltageAndCurrent ( _idev ) ;
}




// -----
// Determine the voltage and current of the ESD using the Newton-Raphson
// method.
// -----
void
OBESS_Voltage_Controlled :: getESDVoltageAndCurrent
( double _v_in ,
  double _i_in ,
  double & _vi ,
  double & _idev )
  const
{
  // ----
  // If the value is in cache, return it.
  // ----
  if ( _v_in == _mc_v_in && _i_in == _mc_i_in )
  {
    _vi = _mc_vi ;
    _idev = _mc_idev ;
    return ;
  }

  _mc_v_in = _v_in ;
  _mc_i_in = _i_in ;

  // -----
  // The device voltage to start the Newton-Raphson method with. No-load
  // voltage (voltage when current is zero).
  // 素子電圧の Newton-Raphson 法初期解。無負荷時電圧（電流ゼロ時電圧）。
  // -----
  _mc_vi = _vi = _esd -> getDevVoltage () ;

  // -----
  // The system output power.
  // エネルギー蓄積装置の出力電力。
  // -----
  double p_in = _v_in * _i_in ;

  // -----
  // The device current. Having set _vi to the initial value, this must be
  // exactly zero...
  // 素子電流。素子電圧 _vi を上記のような初期値にしたのだから，ここではゼ
  // ロにならないとおかしい…
  // -----
  _mc_idev = _idev = _esd -> getDevCurrent ( _vi ) ;

  // -----
  // Function that should be zero for the final solution of _vi and _idev.
  // 最終解に対してゼロとなるべき関数。
  // -----
  double f = p_in + _ddcl -> getLosses ( p_in , _v_in , _vi ) - _vi * _idev ;

  // -----
  // The number of iteration.
  // 繰り返し計算の回数。
  // -----
  int cyc_devcur = 0 ;

  // -----
  // Newton-Raphson method loop.
  // Newton-Raphson 法のループ。
  // -----
#ifdef DEBUG_TRN_ESS
  l_ofs << "TRN_ESS: OVC::gEVC: " << cyc_devcur << ": vi, idev: "
        << _vi << " * " << _idev << " = " << _vi * _idev
        << ", f = " << f << endl ;
#endif
  vector < pair < double , double > > _sol_history ;
  _sol_history . clear () ;
  double _v_bl = 0 ;
  double _v_bh = 0 ;
  double _f_bl = 0 ;
  double _f_bh = 0 ;
  double f_old = fabs ( f ) * 2 + 10 ;
  bool _sw_cyc = false ;
  while ( fabs ( f ) > 0.1 )
  {
    ++ cyc_devcur ;

    // ----
    // Finding if the process is being trapped in a "limit cycle".
    // ----
    if ( ! _sw_cyc )
    {
      _sol_history . push_back ( make_pair ( _vi , f ) ) ;
      if ( _sol_history . size () > 3 )
      {
        vector < pair < double , double > > :: reverse_iterator
          ii = _sol_history . rbegin () ;
        vector < pair < double , double > > :: reverse_iterator
          ij = ii + 2 ;
        vector < pair < double , double > > :: size_type _n_cyc = 2 ;
        if ( fabs ( f_old ) < fabs ( f ) )
        {
          for ( ; ij < _sol_history . rend () ; ++ ij , ++ _n_cyc )
          {
            if ( fabs ( ij -> first - ii -> first ) < 0.01 )
            {
              _sw_cyc = true ;
              break ;
            }
          }
        }
        if ( _sw_cyc )
        {
          _v_bl = _v_bh = ii -> first ;
          _f_bl = _f_bh = ii -> second ;
          for ( vector < pair < double , double > > :: size_type ix = 0 ;
                ix < _n_cyc ; ++ ix )
          {
            if ( fabs ( ( ij + ix ) -> first - ( ii + ix ) -> first ) >= 0.1 )
            {
              _sw_cyc = false ;
              break ;
            }
            // ----
            // Find maximum and minimum for bisection method.
            // ----
            if ( _v_bl > ( ii + ix ) -> first )
            {
              _v_bl = ( ii + ix ) -> first ;
              _f_bl = ( ii + ix ) -> second ;
            }
            if ( _v_bh < ( ii + ix ) -> first )
            {
              _v_bh = ( ii + ix ) -> first ;
              _f_bh = ( ii + ix ) -> second ;
            }
          }
        }
      }
    }

    // -----
    // Up to 200 iterations.
    // 繰り返し計算は200回まで。
    // -----
    if ( cyc_devcur > 200 )
    {
      cerr << "Error: calculation failed, ESS current" << endl ;
      exit ( 11 ) ;
    }
    f_old = f ;
    if ( _sw_cyc )
    {
      if ( _f_bl * _f_bh > 0 )
      {
        cerr << "Error: calculation failed, ESS current" << endl ;
        exit ( 2 ) ;
      }
      _mc_vi = _vi = ( _v_bl + _v_bh ) / 2.0 ;
      _mc_idev = _idev = _esd -> getDevCurrent ( _vi ) ;
      f = p_in + _ddcl -> getLosses ( p_in , _v_in , _vi ) - _vi * _idev ;
      if ( f * _f_bl < 0 )
      {
        _v_bh = _vi ;
        _f_bh = f ;
      }
      else
      {
        _v_bl = _vi ;
        _f_bl = f ;
      }
#ifdef DEBUG_TRN_ESS
      l_ofs << "TRN_ESS: OVC::gEVC: " << cyc_devcur << "(BS): vi, idev: "
            << _vi << " * " << _idev << " = " << _vi * _idev
            << ", f = " << f << endl ;
#endif
    }
    else
    {
      double _idevx = _esd -> getDevCurrent ( _vi - 1 ) ;
      double fx = p_in + _ddcl -> getLosses ( p_in , _v_in , _vi - 1 )
        - ( _vi - 1 ) * _idevx ;
      _mc_vi = _vi -= f / ( f - fx ) ;
      _mc_idev = _idev = _esd -> getDevCurrent ( _vi ) ;
      f = p_in + _ddcl -> getLosses ( p_in , _v_in , _vi ) - _vi * _idev ;
#ifdef DEBUG_TRN_ESS
      l_ofs << "TRN_ESS: OVC::gEVC: " << cyc_devcur << ": vi, idev: "
            << _vi << " * " << _idev << " = " << _vi * _idev
            << ", f = " << f << endl ;
#endif
    }
  }
}




// -----
// Renew the state of the ESS.
// システムの内部状態（SOCなど）の更新
// -----
void
OBESS_Voltage_Controlled :: renewElectricalStates
( train_ParamFunc * _pf )
{
  // -----
  // The device voltage.
  // 素子電圧。
  // -----
  double _vi = 0 ;

  // -----
  // The device current.
  // -----
  double _idev = 0 ;

  // -----
  // Getting _vi and _idev using the Newton-Raphson method loop.
  // -----
  getESDVoltageAndCurrent ( _v , _i , _vi , _idev ) ;

  // -----
  // Renewing states of the DC-DC converter.
  // DC-DC コンバータの状態を更新。
  // -----
  _ddcl -> renewElectricalStates ( _vi , _idev ) ;

  // -----
  // Renewing states of the energy storage device.
  // エネルギー蓄積素子の状態を更新。
  // -----
  _esd -> renewElectricalStates ( _idev ) ;
}




// -----
// Write data to a CSV file.
// CSV ファイルにデータを書き出す.
// -----
void
OBESS_Voltage_Controlled :: writeToCSV
( ostream & f_in ,
  bool sw_csv )
  const
{
  if ( sw_csv )
  {
    string __quot = g_sw_csv_without_quotation ? "" : "\"" ;
    f_in << "," << __quot << getCurrent () << __quot ;
  }
  _esd -> writeToCSV ( f_in , sw_csv ) ;
  _ddcl -> writeToCSV ( f_in , sw_csv ) ;
}



// -----
// Write a header line to a CSV file.
// CSV ファイルにヘッダ行を書き出す.
// -----
void
OBESS_Voltage_Controlled :: writeHeaderToCSV
( ostream & f_in ,
  bool sw_csv ,
  const string & h_in )
  const
{
  if ( sw_csv )
  {
    string __quot = g_sw_csv_without_quotation ? "" : "\"" ;
    f_in << "," << __quot << h_in << " current" << __quot ;
  }
  _esd -> writeHeaderToCSV ( f_in , sw_csv , h_in ) ;
  _ddcl -> writeHeaderToCSV ( f_in , sw_csv , h_in ) ;
}



// -----
// Maximum charge current. Returns non-positive value.
// 最大充電電流. 非正の値を返す.
// -----
double
OBESS_Voltage_Controlled :: getMaximumChargeCurrent
()
  const
{
  double _soc = getSOC () ;
  double _ret_val = 0 ;
  if ( _soc < _max_charge_soc_low_threshold )
  {
    _ret_val = - _max_charge_current ;
  }
  else if ( _soc < _max_charge_soc_high_threshold )
  {
    _ret_val = _max_charge_current * ( _soc - _max_charge_soc_high_threshold )
      / ( _max_charge_soc_high_threshold - _max_charge_soc_low_threshold ) ;
  }
  else
  {
    _ret_val = 0 ;
  }
  double _v_d = 0 ;
  double _i_d = 0 ;
  double _p_d = _esd -> getMaximumChargePower ( _v_d , _i_d ) ;
  double _max_ddcl = _ddcl -> getLosses ( _v_d * _i_d , _v , _v_d , false ) ;
  double _max_power_c = - _p_d - _max_ddcl ;
  if ( _ret_val * _v < _max_power_c )
  {
    _ret_val = _max_power_c / _v ;
  }
  return _ret_val ;
}



// -----
// Maximum discharge current. Returns non-negative value.
// 最大放電電流. 非負の値を返す.
// -----
double
OBESS_Voltage_Controlled :: getMaximumDischargeCurrent
()
  const
{
  double _soc = getSOC () ;
  double _ret_val = 0 ;
  if ( _soc < _max_discharge_soc_low_threshold )
  {
    _ret_val = 0 ;
  }
  else if ( _soc < _max_discharge_soc_high_threshold )
  {
    _ret_val = _max_discharge_current
      * ( _soc - _max_discharge_soc_low_threshold )
      / ( _max_discharge_soc_high_threshold
          - _max_discharge_soc_low_threshold ) ;
  }
  else
  {
    _ret_val = _max_discharge_current ;
  }
  double _v_d = 0 ;
  double _i_d = 0 ;
  double _p_d = _esd -> getMaximumDischargePower ( _v_d , _i_d ) ;
  double _max_ddcl = _ddcl -> getLosses ( _v_d * _i_d , _v , _v_d , false ) ;
  double _max_power_d = _p_d - _max_ddcl ;
  if ( _ret_val * _v > _max_power_d )
  {
    _ret_val = _max_power_d / _v ;
  }
  return _ret_val ;
}
