// This may look like C code, but it is really -*- C++ -*-
// RTSS --- Railway Total System Simulator
// (c) TAKAGI Ryo (at Kogakuin University)
// EnergyStorage.cc --- implementation of energy storage related classes
// -----
// ChangeLog:
// 2007. 12. 8
//  File created.
// -----


#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <string>
#include <stdexcept>
#include <algorithm>
#include "EnergyStorage.hh"
#include "StrPrintf.hh"
#include "train.hh"
#include "Ref_SOC_Curve.hh"
#include "globvar.hh"

using std :: cerr ;
using std :: endl ;
using std :: setprecision ;

#define DEBUG_SUB_ESS_AFTER_ENDCCALRESULT
//#define DEBUG_SUB_ESS
//#define DEBUG_SUB_ESS_MAX_DEV_POWER
//#define DEBUG_TRN_ESS
//#define DEBUG_TRN_ESS_A1



// -----
// Constructor of class SimpleEDLCModel using a DOM node. ESD_Initialiser
// is typedef'ed to TiXmlNode * .
// SimpleEDLCModel クラスを DOM ノードで初期化する. ESD_Initialiser は
// TiXmlNode * に typedef されている。
// -----
SimpleEDLCModel :: SimpleEDLCModel
( const ESD_Initialiser & d_in )
  : EnergyStorageDevice () ,
    ESD_Expander () ,
    _soc_init ( 0.0 ) ,
    _soc_max ( 0.0 ) ,
    _soc_min ( 0.0 ) ,
    _max_power_c ( 0.0 ) ,
    _max_power_c_at_v ( 0.0 ) ,
    _max_power_c_at_i ( 0.0 ) ,
    _max_power_c_vcur ( - 1.0 ) ,
    _max_power_d ( 0.0 ) ,
    _max_power_d_at_v ( 0.0 ) ,
    _max_power_d_at_i ( 0.0 ) ,
    _max_power_d_vcur ( - 1.0 )
{
  // -----
  // Checking if d_in is of tag "simple_edlc".
  // d_in が "simple_edlc" タグであることを確認する。
  // -----
  string d_val = string ( d_in -> Value () ) ;
  if ( d_val != "simple_edlc" )
  {
    cerr << "Error: \"" << d_val
         << "\" tag not allowed for construction of SimpleEDLC." << endl ;
    exit ( 1 ) ;
  }

  // -----
  // Reading attributes of tag "simple_edlc".
  // "simple_edlc" タグの属性を読み取る。
  // -----
  bool _b_c = true ;
  bool _b_ri = true ;
  bool _b_sdr = true ;
  bool _b_vmin = true ;
  bool _b_vmax = true ;
  bool _b_icm = true ;
  bool _b_idm = true ;
  bool _b_vcur = true ;
  for ( const TiXmlAttribute * attr
          = d_in -> ToElement () -> FirstAttribute () ;
        attr ; attr = attr -> Next () )
  {
    if ( string ( attr -> Name () ) == "capacitance" )
    {
      _b_c = false ;
      sscanf ( attr -> Value () , "%lf" , & _c ) ;
    }
    else if ( string ( attr -> Name () ) == "internal_resistance" )
    {
      _b_ri = false ;
      sscanf ( attr -> Value () , "%lf" , & _ri ) ;
    }
    else if ( string ( attr -> Name () ) == "self_discharge_resistance" )
    {
      _b_sdr = false ;
      sscanf ( attr -> Value () , "%lf" , & _sdr ) ;
    }
    else if ( string ( attr -> Name () ) == "minimum_voltage" )
    {
      _b_vmin = false ;
      sscanf ( attr -> Value () , "%lf" , & _vmin ) ;
    }
    else if ( string ( attr -> Name () ) == "maximum_voltage" )
    {
      _b_vmax = false ;
      sscanf ( attr -> Value () , "%lf" , & _vmax ) ;
    }
    else if ( string ( attr -> Name () ) == "maximum_charge_current" )
    {
      _b_icm = false ;
      sscanf ( attr -> Value () , "%lf" , & _icm ) ;
    }
    else if ( string ( attr -> Name () ) == "maximum_discharge_current" )
    {
      _b_idm = false ;
      sscanf ( attr -> Value () , "%lf" , & _idm ) ;
    }
    else if ( string ( attr -> Name () ) == "initial_voltage" )
    {
      _b_vcur = false ;
      sscanf ( attr -> Value () , "%lf" , & _vcur ) ;
    }
    else
    {
      cerr << "ERROR: tag <simple_edlc> with incorrect attribute "
           << attr -> Name () << endl ;
      exit ( 1 ) ;
    }
  }
  if ( _b_c || _b_ri || _b_sdr || _b_vmin || _b_vmax || _b_icm
       || _b_idm || _b_vcur )
  {
    cerr << "ERROR: <simple_edlc> data incorrect... missing attribute?"
         << endl ;
    exit ( 1 ) ;
  }
  if ( _vmin >= _vmax )
  {
    cerr << "ERROR: minimum voltage must be smaller than maximum in "
         << "<simple_edlc>" << endl ;
    exit ( 1 ) ;
  }

  // -----
  // Calculate constants based on _vmin and _vmax.
  // _vmin と _vmax の値に基づき定数を計算.
  // -----
  _vmin_sq = _vmin * _vmin ;
  _vmax_sq_minus_vmin_sq = _vmax * _vmax - _vmin_sq ;

  _storeable = _c * _vmax_sq_minus_vmin_sq / 2.0 ;
#ifdef DEBUG_TRN_ESS_A1
  l_ofs << "Initialising simple ELDC model: storeable = " << _storeable
        << endl ;
#endif
}



// -----
// Copy constructor.
// コピーコンストラクタ.
// -----
SimpleEDLCModel :: SimpleEDLCModel
( const SimpleEDLCModel & e_in )
  : EnergyStorageDevice		() ,
    ESD_Expander		() ,
    _c  			( e_in . _c ) ,
    _ri 			( e_in . _ri ) ,
    _sdr			( e_in . _sdr ) ,
    _vmin			( e_in . _vmin ) ,
    _vmax			( e_in . _vmax ) ,
    _icm			( e_in . _icm ) ,
    _idm			( e_in . _idm ) ,
    _vcur			( e_in . _vcur ) ,
    _storeable			( e_in . _storeable ) ,
    _vmax_sq_minus_vmin_sq	( e_in . _vmax_sq_minus_vmin_sq ) ,
    _vmin_sq			( e_in . _vmin_sq ) ,
    _soc_init			( e_in . _soc_init ) ,
    _soc_max			( e_in . _soc_max ) ,
    _soc_min			( e_in . _soc_min ) ,
    _max_power_c		( e_in . _max_power_c ) ,
    _max_power_c_at_v		( e_in . _max_power_c_at_v ) ,
    _max_power_c_at_i		( e_in . _max_power_c_at_i ) ,
    _max_power_c_vcur		( e_in . _max_power_c_vcur ) ,
    _max_power_d		( e_in . _max_power_d ) ,
    _max_power_d_at_v		( e_in . _max_power_d_at_v ) ,
    _max_power_d_at_i		( e_in . _max_power_d_at_i ) ,
    _max_power_d_vcur		( e_in . _max_power_d_vcur )
{
}



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



// -----
// Write a header line to a CSV file.
// CSV ファイルにヘッダ行を書き出す.
// -----
void
SimpleEDLCModel :: 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 << " SOC" << __quot ;
  }
}




// -----
// Calculate and return the SOC of this device. Return value in [%].
// この素子の SOC を算出して返す。単位は [%].
// -----
double
SimpleEDLCModel :: getDevSOC
()
  const
{
  return 100 * ( _vcur * _vcur - _vmin_sq ) / _vmax_sq_minus_vmin_sq ;
}




// -----
// Calculate and return the maximum charge power of this device. The result
// is dependent on the SOC (voltage) only. Returns positive value, unit [W].
// The two arguments are also used to return values --- voltage [V] and
// current [A] of the EDLC at which the maximum power is achieved. Current
// is negative when charging.
// -----
double
SimpleEDLCModel :: getMaximumChargePower
( double & _v_dev ,
  double & _i_dev )
  const
{
  // ########################################################################
  // NOTE: _icm may be SOC dependent, and therefore may be replaced by a
  // SOCDependent data.
  // ########################################################################
  // Self-discharge current is not considered.

  // Use data in cache
  if ( _vcur == _max_power_c_vcur )
  {
    _v_dev = _max_power_c_at_v ;
    _i_dev = _max_power_c_at_i ;
    return _max_power_c ;
  }

  _max_power_c_vcur = _vcur ;

  // Find the maximum power using golden section search (necessary??)
  // Charge current: negative when calling getDevVoltage().

  double _gr = ( 3 - sqrt ( static_cast < double > ( 5 ) ) ) / 2 ;
  double _i_min = - _icm ;
  double _v_min = getDevVoltage ( _i_min ) ;
  double _p_min = - _v_min * _i_min ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SEM::gMCP: vmin, imin, pmin: " << _v_min << ", "
        << _i_min << ", " << _p_min << endl ;
#endif
  double _i_max = - _icm * 0.95 ;
  double _v_max = getDevVoltage ( _i_max ) ;
  double _p_max = - _v_max * _i_max ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SEM::gMCP: vmax, imax, pmax: " << _v_max << ", "
        << _i_max << ", " << _p_max << endl ;
#endif
  double _i_mx = _i_max ;
  double _v_mx = _v_max ;
  double _p_mx = _p_max ;
  while ( _p_max > _p_min )
  {
    _i_max = _i_mx ;
    _v_max = _v_mx ;
    _p_max = _p_mx ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
    l_ofs << "SUB_ESS: SEM::gMCP: vmax, imax, pmax: " << _v_max << ", "
          << _i_max << ", " << _p_max << endl ;
#endif
    if ( _p_mx < _p_max || _i_mx > - INVLIM )
    {
      break ;
    }
    _i_mx = ( _i_max - _i_min ) * 2 + _i_min ;
    if ( _i_mx > 0 )
    {
      _i_mx = 0 ;
    }
    _v_mx = getDevVoltage ( _i_mx ) ;
    _p_mx = - ( getDevVoltage ( _i_mx ) * _i_mx ) ;
  }
  double _i_gr_l = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
  double _v_gr_l = getDevVoltage ( _i_gr_l ) ;
  double _p_gr_l = - _v_gr_l * _i_gr_l ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SEM::gMCP: v_l, i_l, p_l: " << _v_gr_l << ", "
        << _i_gr_l << ", " << _p_gr_l << endl ;
#endif
  double _i_gr_h = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
  double _v_gr_h = getDevVoltage ( _i_gr_h ) ;
  double _p_gr_h = - _v_gr_h * _i_gr_h ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SEM::gMCP: v_h, i_h, p_h: " << _v_gr_h << ", "
        << _i_gr_h << ", " << _p_gr_h << endl ;
#endif
  while ( _i_max - _i_min >= 0.1 )
  {
    if ( _p_gr_l < _p_gr_h )
    {
      _i_min = _i_gr_l ;
      _v_min = _v_gr_l ;
      _p_min = _p_gr_l ;
      _i_gr_l = _i_gr_h ;
      _v_gr_l = _v_gr_h ;
      _p_gr_l = _p_gr_h ;
      _i_gr_h = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
      _v_gr_h = getDevVoltage ( _i_gr_h ) ;
      _p_gr_h = - _v_gr_h * _i_gr_h ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
      l_ofs << "SUB_ESS: SEM::gMCP: _h renew: " << _v_gr_h << ", "
            << _i_gr_h << ", " << _p_gr_h << endl ;
#endif
    }
    else
    {
      _i_max = _i_gr_h ;
      _v_max = _v_gr_h ;
      _p_max = _p_gr_h ;
      _i_gr_h = _i_gr_l ;
      _v_gr_h = _v_gr_l ;
      _p_gr_h = _p_gr_l ;
      _i_gr_l = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
      _v_gr_l = getDevVoltage ( _i_gr_l ) ;
      _p_gr_l = - _v_gr_l * _i_gr_l ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
      l_ofs << "SUB_ESS: SEM::gMCP: _l renew: " << _v_gr_l << ", "
            << _i_gr_l << ", " << _p_gr_l << endl ;
#endif
    }
  }
  _max_power_c = _p_min ;
  _v_dev = _max_power_c_at_v = _v_min ;
  _i_dev = _max_power_c_at_i = _i_min ;
  if ( _p_gr_l > _max_power_c )
  {
    _max_power_c = _p_gr_l ;
    _v_dev = _max_power_c_at_v = _v_gr_l ;
    _i_dev = _max_power_c_at_i = _i_gr_l ;
  }
  if ( _p_gr_h > _max_power_c )
  {
    _max_power_c = _p_gr_h ;
    _v_dev = _max_power_c_at_v = _v_gr_h ;
    _i_dev = _max_power_c_at_i = _i_gr_h ;
  }
  if ( _p_max > _max_power_c )
  {
    _max_power_c = _p_max ;
    _v_dev = _max_power_c_at_v = _v_max ;
    _i_dev = _max_power_c_at_i = _i_max ;
  }
  return _max_power_c ;
//   return ( _vcur + _icm * _ri ) * _icm ;
}




// -----
// Calculate and return the maximum discharge power of this device. The
// result is dependent on the SOC (voltage) only. Returns positive value,
// unit [W].
// -----
double
SimpleEDLCModel :: getMaximumDischargePower
( double & _v_dev ,
  double & _i_dev )
  const
{
  // ########################################################################
  // NOTE: _idm may be SOC dependent, and therefore may be replaced by a
  // SOCDependent data.
  // ########################################################################
  // Self-discharge current is not considered.

  // Use data in cache
  if ( _vcur == _max_power_d_vcur )
  {
    _v_dev = _max_power_d_at_v ;
    _i_dev = _max_power_d_at_i ;
    return _max_power_d ;
  }

  _max_power_d_vcur = _vcur ;

  // Find the maximum power using golden section search (necessary??)
  // Discharge current: positive when calling getDevVoltage().

  double _gr = ( 3 - sqrt ( static_cast < double > ( 5 ) ) ) / 2 ;
  double _i_max = _idm ;
  double _v_max = getDevVoltage ( _i_max ) ;
  double _p_max = _v_max * _i_max ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SEM::gMDP: vmax, imax, pmax: " << _v_max << ", "
        << _i_max << ", " << _p_max << endl ;
#endif
  double _i_min = _idm * 0.95 ;
  double _v_min = getDevVoltage ( _i_min ) ;
  double _p_min = _v_min * _i_min ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SEM::gMDP: vmin, imin, pmin: " << _v_min << ", "
        << _i_min << ", " << _p_min << endl ;
#endif
  double _i_mn = _i_min ;
  double _v_mn = _v_min ;
  double _p_mn = _p_min ;
  while ( _p_min > _p_max )
  {
    _i_min = _i_mn ;
    _v_min = _v_mn ;
    _p_min = _p_mn ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
    l_ofs << "SUB_ESS: SEM::gMDP: vmin, imin, pmin: " << _v_min << ", "
          << _i_min << ", " << _p_min << endl ;
#endif
    if ( _p_mn < _p_min || _i_mn < INVLIM )
    {
      break ;
    }
    _i_mn = _i_max + ( _i_min - _i_max ) * 2 ;
    if ( _i_mn < 0 )
    {
      _i_mn = 0 ;
    }
    _v_mn = getDevVoltage ( _i_mn ) ;
    _p_mn = _v_mn * _i_mn ;
  }
  double _i_gr_l = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
  double _v_gr_l = getDevVoltage ( _i_gr_l ) ;
  double _p_gr_l = _v_gr_l * _i_gr_l ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SEM::gMDP: v_l, i_l, p_l: " << _v_gr_l << ", "
        << _i_gr_l << ", " << _p_gr_l << endl ;
#endif
  double _i_gr_h = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
  double _v_gr_h = getDevVoltage ( _i_gr_h ) ;
  double _p_gr_h = _v_gr_h * _i_gr_h ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SEM::gMDP: v_h, i_h, p_h: " << _v_gr_h << ", "
        << _i_gr_h << ", " << _p_gr_h << endl ;
#endif
  while ( _i_max - _i_min >= 0.1 )
  {
    if ( _p_gr_l < _p_gr_h )
    {
      _i_min = _i_gr_l ;
      _v_min = _v_gr_l ;
      _p_min = _p_gr_l ;
      _i_gr_l = _i_gr_h ;
      _v_gr_l = _v_gr_h ;
      _p_gr_l = _p_gr_h ;
      _i_gr_h = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
      _v_gr_h = getDevVoltage ( _i_gr_h ) ;
      _p_gr_h = _v_gr_h * _i_gr_h ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
      l_ofs << "SUB_ESS: SEM::gMDP: _h renew: " << _v_gr_h << ", "
            << _i_gr_h << ", " << _p_gr_h << endl ;
#endif
    }
    else
    {
      _i_max = _i_gr_h ;
      _v_max = _v_gr_h ;
      _p_max = _p_gr_h ;
      _i_gr_h = _i_gr_l ;
      _v_gr_h = _v_gr_l ;
      _p_gr_h = _p_gr_l ;
      _i_gr_l = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
      _v_gr_l = getDevVoltage ( _i_gr_l ) ;
      _p_gr_l = _v_gr_l * _i_gr_l ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
      l_ofs << "SUB_ESS: SBM::gMDP: _l renew: " << _v_gr_l << ", "
            << _i_gr_l << ", " << _p_gr_l << endl ;
#endif
    }
  }
  _i_dev = _max_power_d_at_i = _i_min ;
  _v_dev = _max_power_d_at_v = _v_min ;
  if ( _p_gr_l > _max_power_d )
  {
    _i_dev = _max_power_d_at_i = _i_gr_l ;
    _v_dev = _max_power_d_at_v = _v_gr_l ;
    _max_power_d = _p_gr_l ;
  }
  if ( _p_gr_h > _max_power_d )
  {
    _i_dev = _max_power_d_at_i = _i_gr_h ;
    _v_dev = _max_power_d_at_v = _v_gr_h ;
    _max_power_d = _p_gr_h ;
  }
  if ( _p_max > _max_power_d )
  {
    _i_dev = _max_power_d_at_i = _i_max ;
    _v_dev = _max_power_d_at_v = _v_max ;
    _max_power_d = _p_max ;
  }
  return _max_power_d ;
//   return ( _vcur - _idm * _ri ) * _idm ;
}




// -----
// Calculate and return the terminal voltage of this device.
// The argument is the current in [A] --- charge NEGATIVE.
// この素子の端子電圧を算出して返す。引数は電流 [A]. ★充電電流が負。
// -----
double
SimpleEDLCModel :: getDevVoltage
( double cur_in /* = 0 */ )
  const
{
  return _vcur - cur_in * _ri ;
}




// -----
// Calculate and return the terminal current of this device.
// The argument is the voltage in [V].
// この素子の端子電流を算出して返す。引数は電圧 [V].
// -----
double
SimpleEDLCModel :: getDevCurrent
( double volt_in /* = 0 */ )
  const
{
  return ( _vcur - volt_in ) / _ri ;
}




// -----
// Renew the "state" of the EDLC. The argument is the current [A].
// EDLC の状態を更新する。引数は電流[A]。
// -----
void
SimpleEDLCModel :: renewElectricalStates
( double cur_in )
{
  // -----
  // Current electric charge in the capacitor.
  // 現在蓄積されている電荷。
  // -----
  double _charge_cur = _vcur * _c ;

  // -----
  // Assuming the leakage current is small...
  // 漏れ電流は小さいと仮定して…
  // -----
  double _leakage_current = _vcur / _sdr ;
#ifdef DEBUG_SUB_ESS_AFTER_ENDCCALRESULT
  l_ofs << "ESD: I: " << cur_in << " + " << _leakage_current ;
#endif

  // -----
  // Discharge current is positive. Note the sign.
  // 放電電流が正……符号に注意
  // -----
  cur_in += _leakage_current ;
#ifdef DEBUG_SUB_ESS_AFTER_ENDCCALRESULT
  l_ofs << ", Q: " << setprecision ( 8 ) << _charge_cur ;
#endif
  _charge_cur -= cur_in * cal_deltah ;
#ifdef DEBUG_SUB_ESS_AFTER_ENDCCALRESULT
  l_ofs << " -> " << setprecision ( 8 ) << _charge_cur ;
#endif

  // -----
  // Renew voltage.
  // 電圧を更新する。
  // -----
#ifdef DEBUG_SUB_ESS_AFTER_ENDCCALRESULT
  l_ofs << ", v: " << setprecision ( 5 ) << _vcur ;
#endif
  _vcur = _charge_cur / _c ;
#ifdef DEBUG_SUB_ESS_AFTER_ENDCCALRESULT
  l_ofs << " -> " << setprecision ( 5 ) << _vcur << endl ;
#endif

  // ----
  // Renew Max and Min SOC stores.
  // ----
  if ( _soc_max < getDevSOC () )
  {
    _soc_max = getDevSOC () ;
  }
  if ( _soc_min > getDevSOC () )
  {
    _soc_min = getDevSOC () ;
  }
  
}




// -----
// Write a line of SOC data to a RES file.
// RES ファイルにSOC行を書き出す.
// -----
void
SimpleEDLCModel :: printSOCStoredResults
( ostream & f_in ,
  ostringstream & h_in ,
  ostringstream & s_in )
  const
{
  f_in << h_in . str () << s_in . str () ;
  h_in . str ( "" ) ;
  f_in << StrPrintf ( "%9.3f[%7.3f], %9.3f, %9.3f, %9.3f[%7.3f]" ,
                      _soc_init * getEnergyCapacity () / 1e8 , _soc_init ,
                      _soc_max * getEnergyCapacity () / 1e8 ,
                      _soc_min * getEnergyCapacity () / 1e8 ,
                      getDevSOC () * getEnergyCapacity () / 1e8 ,
                      getDevSOC () ) << endl ;
}



// -----
// Get the "Thevenin equivalent circuit" parameters.
// The argument is the current [A].
// 「テブナン等価回路」のパラメータを得る。引数は電流[A]。
// -----
TheveninElements
SimpleEDLCModel :: getTheveninElements
( double cur_in )
  const
{
  TheveninElements ret_val ;
  ret_val . _vs = _vcur ;
  ret_val . _ri = _ri ;
  return ret_val ;
}



// -----
// Constructor of class SimpleBatteryModel using a DOM node. ESD_Initialiser
// is typedef'ed to TiXmlNode * .
// SimpleBatteryModel クラスを DOM ノードで初期化する. ESD_Initialiser は
// TiXmlNode * に typedef されている。
// -----
SimpleBatteryModel :: SimpleBatteryModel
( const ESD_Initialiser & d_in )
  : EnergyStorageDevice () ,
    ESD_Expander () ,
    _soc_init ( 0.0 ) ,
    _soc_max ( 0.0 ) ,
    _soc_min ( 0.0 ) ,
    _max_power_c ( 0.0 ) ,
    _max_power_c_at_v ( 0.0 ) ,
    _max_power_c_at_i ( 0.0 ) ,
    _max_power_c_soc ( - 1.0 ) ,
    _max_power_d ( 0.0 ) ,
    _max_power_d_at_v ( 0.0 ) ,
    _max_power_d_at_i ( 0.0 ) ,
    _max_power_d_soc ( - 1.0 )
{
  // -----
  // Checking if d_in is of tag "simple_battery".
  // d_in が "simple_battery" タグであることを確認する。
  // -----
  string d_val = string ( d_in -> Value () ) ;
  if ( d_val != "simple_battery" )
  {
    cerr << "Error: \"" << d_val
         << "\" tag not allowed in construction of SimpleBatteryModel."
         << endl ;
    exit ( 1 ) ;
  }

  // -----
  // Reading attributes of tag "simple_battery".
  // "simple_battery" タグの属性を読み取る。
  // -----
  bool _b_vmin = false ;
  bool _b_vmax = false ;
  bool _b_storeable = true ;
  bool _b_icm = true ;
  bool _b_idm = true ;
  bool _b_soc = true ;
  bool _b_series = true ;
  bool _b_parallel = true ;
  for ( const TiXmlAttribute * attr
          = d_in -> ToElement () -> FirstAttribute () ;
        attr ; attr = attr -> Next () )
  {
    if ( string ( attr -> Name () ) == "storeable" )
    {
      _b_storeable = false ;
      sscanf ( attr -> Value () , "%lf" , & _storeable ) ;
    }
    else if ( string ( attr -> Name () ) == "minimum_voltage" )
    {
      if ( _b_vmin )
      {
        cerr << "Error: two or more \"minimum_voltage\" attributes "
             << "in tag <simple_battery>?" << endl ;
        exit ( 1 ) ;
      }
      _b_vmin = true ;
      cerr << "Warning: \"minimum_voltage\" attribute in tag "
           << "<simple_battery> is obsolete and has no effect" << endl ;
      sscanf ( attr -> Value () , "%lf" , & _vmin ) ;
    }
    else if ( string ( attr -> Name () ) == "maximum_voltage" )
    {
      if ( _b_vmax )
      {
        cerr << "Error: two or more \"maximum_voltage\" attributes "
             << "in tag <simple_battery>?" << endl ;
        exit ( 1 ) ;
      }
      _b_vmax = true ;
      cerr << "Warning: \"maximum_voltage\" attribute in tag "
           << "<simple_battery> is obsolete and has no effect" << endl ;
      sscanf ( attr -> Value () , "%lf" , & _vmax ) ;
    }
    else if ( string ( attr -> Name () ) == "maximum_charge_current" )
    {
      _b_icm = false ;
      sscanf ( attr -> Value () , "%lf" , & _icm ) ;
    }
    else if ( string ( attr -> Name () ) == "maximum_discharge_current" )
    {
      _b_idm = false ;
      sscanf ( attr -> Value () , "%lf" , & _idm ) ;
    }
    else if ( string ( attr -> Name () ) == "initial_soc" )
    {
      _b_soc = false ;
      sscanf ( attr -> Value () , "%lf" , & _soc ) ;
    }
    else if ( string ( attr -> Name () ) == "series" )
    {
      _b_series = false ;
      sscanf ( attr -> Value () , "%d" , & _n_series ) ;
      if ( _n_series <= 0 )
      {
        cerr << "Error: series in <simple_battery> must be 1 or more."
             << endl ;
        exit ( 1 ) ;
      }
    }
    else if ( string ( attr -> Name () ) == "parallel" )
    {
      _b_parallel = false ;
      sscanf ( attr -> Value () , "%d" , & _n_parallel ) ;
      if ( _n_parallel <= 0 )
      {
        cerr << "Error: parallel in <simple_battery> must be 1 or more."
             << endl ;
        exit ( 1 ) ;
      }
    }
    else
    {
      cerr << "ERROR: tag <simple_edlc> with incorrect attribute "
           << attr -> Name () << endl ;
      exit ( 1 ) ;
    }
  }
  if ( _b_storeable || _b_icm || _b_idm || _b_soc
       || _b_series || _b_parallel )
  {
    cerr << "ERROR: <simple_battery> data incorrect... missing attribute?"
         << endl ;
    exit ( 1 ) ;
  }

  // -----
  // Reading child elements of tag "simple_battery", all of which must be
  // of tag "terminal_voltage".
  // "simple_battery" タグの子タグを読み取る。すべて "terminal_voltage" タグ
  // でなければならない。
  // -----
  double _tv_current = 0.0 ;
  double _tv_current_old = 0.0 ;
  bool _not_first_cycle = false ;
  bool _has_second = false ;
  for ( const TiXmlNode * _cc = d_in -> FirstChild () ;
        _cc ; _cc = _cc -> NextSibling () )
  {
    // -----
    // Ignore non-Element node.
    // エレメント以外は無視。
    // -----
    if ( _cc -> Type () != TiXmlNode :: TINYXML_ELEMENT )
    {
      continue ;
    }

    _has_second = _not_first_cycle ;
    _tv_current_old = _tv_current ;

    // -----
    // Check tag name.
    // タグ名チェック。
    // -----
    string _cc_val = string ( _cc -> Value () ) ;
    if ( _cc_val != "terminal_voltage" )
    {
      cerr << "Error: \"" << _cc_val << "\" tag not allowed." << endl ;
      exit ( 1 ) ;
    }


    // -----
    // Reading the attribute of tag "terminal_voltage". One attribute
    // "current" must be present.
    // "terminal_voltage" タグの属性を読み取る。"current" 属性ひとつだけ
    // が存在することが必要。
    // -----
    bool _b_current = true ;
    for ( const TiXmlAttribute * attr
            = _cc -> ToElement () -> FirstAttribute () ;
          attr ; attr = attr -> Next () )
    {
      if ( string ( attr -> Name () ) != "current" )
      {
        cerr << "Error: attribute \"" << string ( attr -> Name () )
             << "\" not allowed in tag \"terminal_voltage\"" << endl ;
        exit ( 1 ) ;
      }
      if ( ! _b_current )
      {
        cerr << "Error: multiple attribute in tag \"terminal_voltage\""
             << endl ;
        exit ( 1 ) ;
      }
      _b_current = false ;
      sscanf ( attr -> Value () , "%lf" , & _tv_current ) ;
    }
    if ( _b_current )
    {
      cerr << "ERROR: <terminal_voltage> data incorrect... missing attribute?"
           << endl ;
      exit ( 1 ) ;
    }

    // ----
    // Read the children and create an SOCDependent object.
    // ----
    SOCDependent * x = new SOCDependent ( _cc ) ;

    // ----
    // Add the SOCDependent object and the corresponding key data
    // (_tv_current) to the end of vector _tv.
    // ----
    if ( _not_first_cycle && _tv_current_old >= _tv_current - INVLIM )
    {
      cerr << "ERROR: following <terminal_voltage> tag must have larger "
           << "current attribute than the preceding one" << endl ;
      exit ( 1 ) ;
    }
    else
    {
      _not_first_cycle = true ;
    }
    _tv . push_back ( make_pair ( _tv_current , x ) ) ;
  }
  if ( ! _has_second )
  {
    cerr << "ERROR: there must be more than one <terminal_voltage> tags"
         << endl ;
    exit ( 1 ) ;
  }
}



// -----
// Copy constructor.
// コピーコンストラクタ.
// -----
SimpleBatteryModel :: SimpleBatteryModel
( const SimpleBatteryModel & e_in )
  : EnergyStorageDevice		() ,
    ESD_Expander		() ,
    _storeable  		( e_in . _storeable ) ,
    _vmin			( e_in . _vmin ) ,
    _vmax			( e_in . _vmax ) ,
    _icm			( e_in . _icm ) ,
    _idm			( e_in . _idm ) ,
    _n_series			( e_in . _n_series ) ,
    _n_parallel			( e_in . _n_parallel ) ,
    _soc			( e_in . _soc ) ,
    _tv				( e_in . _tv ) ,
    _soc_init			( e_in . _soc_init ) ,
    _soc_max			( e_in . _soc_max ) ,
    _soc_min			( e_in . _soc_min ) ,
    _max_power_c		( e_in . _max_power_c ) ,
    _max_power_c_at_v		( e_in . _max_power_c_at_v ) ,
    _max_power_c_at_i		( e_in . _max_power_c_at_i ) ,
    _max_power_c_soc		( e_in . _max_power_c_soc ) ,
    _max_power_d		( e_in . _max_power_d ) ,
    _max_power_d_at_v		( e_in . _max_power_d_at_v ) ,
    _max_power_d_at_i		( e_in . _max_power_d_at_i ) ,
    _max_power_d_soc		( e_in . _max_power_d_soc )
{
}



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



// -----
// Write a header line to a CSV file.
// CSV ファイルにヘッダ行を書き出す.
// -----
void
SimpleBatteryModel :: 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 << " SOC" << __quot ;
  }
}



// -----
// Functor for Ref_SOC_Curve::getData(double).
// Ref_SOC_Curve::getData(double)関数のためのファンクタ
// -----
class SimpleBattery_Comp
{
public :
  bool operator()
  ( pair < double , SOCDependent * > const & x ,
    pair < double , SOCDependent * > const & y ) const
  { return x . first < y . first ; }
} ;



// -----
// Get the "Thevenin equivalent circuit" parameters.
// The argument is the current [A].
// 「テブナン等価回路」のパラメータを得る。引数は電流[A]。
// -----
TheveninElements
SimpleBatteryModel :: getTheveninElements
( double cur_in )
  const
{
  SimpleBattery_Comp _sbc ;
  vector < pair < double , SOCDependent * > > :: const_iterator
    ii = _tv . begin () ;
  ++ ii ;
  vector < pair < double , SOCDependent * > > :: const_iterator
    jj = _tv . end () ;
  -- jj ;
  SOCDependent * _dummy = 0 ;
  pair < double , SOCDependent * > _cur = make_pair
    ( cur_in / static_cast < double > ( _n_parallel ) , _dummy ) ;
  vector < pair < double , SOCDependent * > > :: const_iterator
    ix = lower_bound ( ii , jj , _cur , _sbc ) ;
  double _cur_low = ( ix - 1 ) -> first
    * static_cast < double > ( _n_parallel ) ;
  double _cur_high = ix -> first
    * static_cast < double > ( _n_parallel ) ;
  double _volt_low = ( ix - 1 ) -> second -> getData ( _soc )
    * static_cast < double > ( _n_series ) ;
  double _volt_high = ix -> second -> getData ( _soc )
    * static_cast < double > ( _n_series ) ;
  if ( _cur_low >= _cur_high )
  {
    cerr << "Error: Battery voltage-soc data inconsistent" << endl ;
    exit ( 2 ) ;
  }
  TheveninElements ret_val ;
  ret_val . _vs = ( _volt_low * _cur_high - _volt_high * _cur_low )
    / ( _cur_high - _cur_low ) ;
  ret_val . _ri = ( _volt_low - _volt_high ) / ( _cur_high - _cur_low ) ;
  return ret_val ;
}




// -----
// Calculate and return the maximum charge power of this device. The result
// is dependent on the SOC (voltage) only. Returns positive value, unit [W].
// The two arguments are also used to return values --- voltage [V] and
// current [A] of the EDLC at which the maximum power is achieved. Current
// is negative when charging.
// -----
double
SimpleBatteryModel :: getMaximumChargePower
( double & _v_dev ,
  double & _i_dev )
  const
{
  // ########################################################################
  // NOTE: _icm may be SOC dependent, and therefore may be replaced by a
  // SOCDependent data.
  // ########################################################################

  // Use data in cache
  if ( _soc == _max_power_c_soc )
  {
    _v_dev = _max_power_c_at_v ;
    _i_dev = _max_power_c_at_i ;
    return _max_power_c ;
  }

  _max_power_c_soc = _soc ;

  // Find the maximum power using golden section search (necessary??)
  // Charge current: negative when calling getDevVoltage().

  double _gr = ( 3 - sqrt ( static_cast < double > ( 5 ) ) ) / 2 ;
  double _i_min = - _icm ;
  double _v_min = getDevVoltage ( _i_min ) ;
  double _p_min = - _v_min * _i_min ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SBM::gMCP: vmin, imin, pmin: " << _v_min << ", "
        << _i_min << ", " << _p_min << endl ;
#endif
  double _i_max = - _icm * 0.95 ;
  double _v_max = getDevVoltage ( _i_max ) ;
  double _p_max = - _v_max * _i_max ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SBM::gMCP: vmax, imax, pmax: " << _v_max << ", "
        << _i_max << ", " << _p_max << endl ;
#endif
  double _i_mx = _i_max ;
  double _v_mx = _v_max ;
  double _p_mx = _p_max ;
  while ( _p_max > _p_min )
  {
    _i_max = _i_mx ;
    _v_max = _v_mx ;
    _p_max = _p_mx ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
    l_ofs << "SUB_ESS: SBM::gMCP: vmax, imax, pmax: " << _v_max << ", "
          << _i_max << ", " << _p_max << endl ;
#endif
    if ( _p_mx < _p_max || _i_mx > - INVLIM )
    {
      break ;
    }
    _i_mx = ( _i_max - _i_min ) * 2 + _i_min ;
    if ( _i_mx > 0 )
    {
      _i_mx = 0 ;
    }
    _v_mx = getDevVoltage ( _i_mx ) ;
    _p_mx = - ( getDevVoltage ( _i_mx ) * _i_mx ) ;
  }
  double _i_gr_l = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
  double _v_gr_l = getDevVoltage ( _i_gr_l ) ;
  double _p_gr_l = - _v_gr_l * _i_gr_l ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SBM::gMCP: v_l, i_l, p_l: " << _v_gr_l << ", "
        << _i_gr_l << ", " << _p_gr_l << endl ;
#endif
  double _i_gr_h = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
  double _v_gr_h = getDevVoltage ( _i_gr_h ) ;
  double _p_gr_h = - _v_gr_h * _i_gr_h ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SBM::gMCP: v_h, i_h, p_h: " << _v_gr_h << ", "
        << _i_gr_h << ", " << _p_gr_h << endl ;
#endif
  while ( _i_max - _i_min >= 0.1 )
  {
    if ( _p_gr_l < _p_gr_h )
    {
      _i_min = _i_gr_l ;
      _v_min = _v_gr_l ;
      _p_min = _p_gr_l ;
      _i_gr_l = _i_gr_h ;
      _v_gr_l = _v_gr_h ;
      _p_gr_l = _p_gr_h ;
      _i_gr_h = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
      _v_gr_h = getDevVoltage ( _i_gr_h ) ;
      _p_gr_h = - _v_gr_h * _i_gr_h ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
      l_ofs << "SUB_ESS: SBM::gMCP: _h renew: " << _v_gr_h << ", "
            << _i_gr_h << ", " << _p_gr_h << endl ;
#endif
    }
    else
    {
      _i_max = _i_gr_h ;
      _v_max = _v_gr_h ;
      _p_max = _p_gr_h ;
      _i_gr_h = _i_gr_l ;
      _v_gr_h = _v_gr_l ;
      _p_gr_h = _p_gr_l ;
      _i_gr_l = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
      _v_gr_l = getDevVoltage ( _i_gr_l ) ;
      _p_gr_l = - _v_gr_l * _i_gr_l ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
      l_ofs << "SUB_ESS: SBM::gMCP: _l renew: " << _v_gr_l << ", "
            << _i_gr_l << ", " << _p_gr_l << endl ;
#endif
    }
  }
  _max_power_c = _p_min ;
  _v_dev = _max_power_c_at_v = _v_min ;
  _i_dev = _max_power_c_at_i = _i_min ;
  if ( _p_gr_l > _max_power_c )
  {
    _max_power_c = _p_gr_l ;
    _v_dev = _max_power_c_at_v = _v_gr_l ;
    _i_dev = _max_power_c_at_i = _i_gr_l ;
  }
  if ( _p_gr_h > _max_power_c )
  {
    _max_power_c = _p_gr_h ;
    _v_dev = _max_power_c_at_v = _v_gr_h ;
    _i_dev = _max_power_c_at_i = _i_gr_h ;
  }
  if ( _p_max > _max_power_c )
  {
    _max_power_c = _p_max ;
    _v_dev = _max_power_c_at_v = _v_max ;
    _i_dev = _max_power_c_at_i = _i_max ;
  }
  return _max_power_c ;
}




// -----
// Calculate and return the maximum discharge power of this device. The
// result is dependent on the SOC (voltage) only. Returns positive value,
// unit [W].
// -----
double
SimpleBatteryModel :: getMaximumDischargePower
( double & _v_dev ,
  double & _i_dev )
  const
{
  // ########################################################################
  // NOTE: _idm may be SOC dependent, and therefore may be replaced by a
  // SOCDependent data.
  // ########################################################################

  // Use data in cache
  if ( _soc == _max_power_d_soc )
  {
    _v_dev = _max_power_d_at_v ;
    _i_dev = _max_power_d_at_i ;
    return _max_power_d ;
  }

  _max_power_d_soc = _soc ;

  // Find the maximum power using golden section search (necessary??)
  // Discharge current: positive when calling getDevVoltage().

  double _gr = ( 3 - sqrt ( static_cast < double > ( 5 ) ) ) / 2 ;
  double _i_max = _idm ;
  double _v_max = getDevVoltage ( _i_max ) ;
  double _p_max = _v_max * _i_max ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SBM::gMDP: vmax, imax, pmax: " << _v_max << ", "
        << _i_max << ", " << _p_max << endl ;
#endif
  double _i_min = _idm * 0.95 ;
  double _v_min = getDevVoltage ( _i_min ) ;
  double _p_min = _v_min * _i_min ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SBM::gMDP: vmin, imin, pmin: " << _v_min << ", "
        << _i_min << ", " << _p_min << endl ;
#endif
  double _i_mn = _i_min ;
  double _v_mn = _v_min ;
  double _p_mn = _p_min ;
  while ( _p_min > _p_max )
  {
    _i_min = _i_mn ;
    _v_min = _v_mn ;
    _p_min = _p_mn ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
    l_ofs << "SUB_ESS: SBM::gMDP: vmin, imin, pmin: " << _v_min << ", "
          << _i_min << ", " << _p_min << endl ;
#endif
    if ( _p_mn < _p_min || _i_mn < INVLIM )
    {
      break ;
    }
    _i_mn = _i_max + ( _i_min - _i_max ) * 2 ;
    if ( _i_mn < 0 )
    {
      _i_mn = 0 ;
    }
    _v_mn = getDevVoltage ( _i_mn ) ;
    _p_mn = _v_mn * _i_mn ;
  }
  double _i_gr_l = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
  double _v_gr_l = getDevVoltage ( _i_gr_l ) ;
  double _p_gr_l = _v_gr_l * _i_gr_l ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SBM::gMDP: v_l, i_l, p_l: " << _v_gr_l << ", "
        << _i_gr_l << ", " << _p_gr_l << endl ;
#endif
  double _i_gr_h = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
  double _v_gr_h = getDevVoltage ( _i_gr_h ) ;
  double _p_gr_h = _v_gr_h * _i_gr_h ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
  l_ofs << "SUB_ESS: SBM::gMDP: v_h, i_h, p_h: " << _v_gr_h << ", "
        << _i_gr_h << ", " << _p_gr_h << endl ;
#endif
  while ( _i_max - _i_min >= 0.1 )
  {
    if ( _p_gr_l < _p_gr_h )
    {
      _i_min = _i_gr_l ;
      _v_min = _v_gr_l ;
      _p_min = _p_gr_l ;
      _i_gr_l = _i_gr_h ;
      _v_gr_l = _v_gr_h ;
      _p_gr_l = _p_gr_h ;
      _i_gr_h = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
      _v_gr_h = getDevVoltage ( _i_gr_h ) ;
      _p_gr_h = _v_gr_h * _i_gr_h ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
      l_ofs << "SUB_ESS: SBM::gMDP: _h renew: " << _v_gr_h << ", "
            << _i_gr_h << ", " << _p_gr_h << endl ;
#endif
    }
    else
    {
      _i_max = _i_gr_h ;
      _v_max = _v_gr_h ;
      _p_max = _p_gr_h ;
      _i_gr_h = _i_gr_l ;
      _v_gr_h = _v_gr_l ;
      _p_gr_h = _p_gr_l ;
      _i_gr_l = ( _i_max - _i_min ) * ( 1 - _gr ) + _i_min ;
      _v_gr_l = getDevVoltage ( _i_gr_l ) ;
      _p_gr_l = _v_gr_l * _i_gr_l ;
#ifdef DEBUG_SUB_ESS_GET_MAX_POWER
      l_ofs << "SUB_ESS: SBM::gMDP: _l renew: " << _v_gr_l << ", "
            << _i_gr_l << ", " << _p_gr_l << endl ;
#endif
    }
  }
  _i_dev = _max_power_d_at_i = _i_min ;
  _v_dev = _max_power_d_at_v = _v_min ;
  if ( _p_gr_l > _max_power_d )
  {
    _i_dev = _max_power_d_at_i = _i_gr_l ;
    _v_dev = _max_power_d_at_v = _v_gr_l ;
    _max_power_d = _p_gr_l ;
  }
  if ( _p_gr_h > _max_power_d )
  {
    _i_dev = _max_power_d_at_i = _i_gr_h ;
    _v_dev = _max_power_d_at_v = _v_gr_h ;
    _max_power_d = _p_gr_h ;
  }
  if ( _p_max > _max_power_d )
  {
    _i_dev = _max_power_d_at_i = _i_max ;
    _v_dev = _max_power_d_at_v = _v_max ;
    _max_power_d = _p_max ;
  }
  return _max_power_d ;
}




// -----
// Calculate and return the terminal voltage of this device.
// The argument is the current in [A] --- charge NEGATIVE.
// この素子の端子電圧を算出して返す。引数は電流 [A]. ★充電電流が負。
// -----
double
SimpleBatteryModel :: getDevVoltage
( double cur_in /* = 0 */ )
  const
{
  TheveninElements _te_x = getTheveninElements ( cur_in ) ;
  return _te_x . _vs - _te_x . _ri * cur_in ;
}




// -----
// Calculate and return the terminal current of this device.
// The argument is the voltage in [V].
// この素子の端子電流を算出して返す。引数は電圧 [V].
// -----
double
SimpleBatteryModel :: getDevCurrent
( double volt_in /* = 0 */ )
  const
{
  vector < pair < double , SOCDependent * > > :: const_iterator
    ii = _tv . begin () ;
  double _volt_high = ii -> second -> getData ( _soc )
    * static_cast < double > ( _n_series ) ;
  double _curr_high = ii -> first
    * static_cast < double > ( _n_parallel ) ;
  double _volt_low ;
  double _curr_low ;
  ++ ii ;
  do 
  {
    _volt_low = _volt_high ;
    _curr_low = _curr_high ;
    _volt_high = ii -> second -> getData ( _soc )
      * static_cast < double > ( _n_series ) ;
    _curr_high = ii -> first
      * static_cast < double > ( _n_parallel ) ;
    if ( _volt_high >= _volt_low )
    {
      cerr << "Error: Battery voltage-soc data inconsistent" << endl ;
      exit ( 1 ) ;
    }
    if ( _volt_high < volt_in )
    {
      break ;
    }
    ++ ii ;
  } while ( ii < _tv . end () ) ;
  return ( _curr_high * _volt_low - _volt_high * _curr_low
           - volt_in * ( _curr_high - _curr_low ) )
    / ( _volt_low - _volt_high ) ;
}




// -----
// Renew the "state" of the battery. The argument is the current [A].
// 電池の状態を更新する。引数は電流[A]。
// -----
void
SimpleBatteryModel :: renewElectricalStates
( double cur_in )
{
#ifdef DEBUG_SUB_ESS_AFTER_ENDCCALRESULT
  l_ofs << "ESD: I: " << cur_in ;
#endif

  // -----
  // Zero-current voltage.
  // 電流ゼロでの電圧.
  // -----
  double _volt_zero = getDevVoltage () ;

  // -----
  // Discharge current is positive. Note the sign.
  // 放電電流が正……符号に注意
  // -----
  double _power_out = cur_in * _volt_zero ;
#ifdef DEBUG_SUB_ESS_AFTER_ENDCCALRESULT
  l_ofs << ", P: " << setprecision ( 8 ) << _power_out ;
  l_ofs << ", SOC: " << setprecision ( 5 ) << _soc ;
#endif

  // ----
  // Energy currently in the battery.
  // ----
  double _energy_cur = getDevSOC () * getEnergyCapacity () / 100 ;

  // -----
  // Renew soc.
  // SOC を更新する。
  // -----
  _soc = 100 * ( _energy_cur - _power_out * cal_deltah )
    / getEnergyCapacity () ;
#ifdef DEBUG_SUB_ESS_AFTER_ENDCCALRESULT
  l_ofs << " -> " << setprecision ( 5 ) << getDevSOC () << endl ;
#endif

  // ----
  // Renew Max and Min SOC stores.
  // ----
  if ( _soc_max < getDevSOC () )
  {
    _soc_max = getDevSOC () ;
  }
  if ( _soc_min > getDevSOC () )
  {
    _soc_min = getDevSOC () ;
  }
  
}




// -----
// Write a line of SOC data to a RES file.
// RES ファイルにSOC行を書き出す.
// -----
void
SimpleBatteryModel :: printSOCStoredResults
( ostream & f_in ,
  ostringstream & h_in ,
  ostringstream & s_in )
  const
{
  f_in << h_in . str () << s_in . str () ;
  h_in . str ( "" ) ;
  f_in << StrPrintf ( "%9.3f[%7.3f], %9.3f, %9.3f, %9.3f[%7.3f]" ,
                      _soc_init * getEnergyCapacity () / 1e8 , _soc_init ,
                      _soc_max * getEnergyCapacity () / 1e8 ,
                      _soc_min * getEnergyCapacity () / 1e8 ,
                      getDevSOC () * getEnergyCapacity () / 1e8 ,
                      getDevSOC () ) << endl ;
}




// -----
// Constructor of class SOCDependentNode using a TiXmlNode.
// SOCDependentNode クラスを1つの TiXmlNode で初期化する。
// -----
SOCDependentNode :: SOCDependentNode
( const TiXmlNode * d_in )
{
  // -----
  // To avoid being undefined...
  // 不定値になるのを避けるためのおまじない
  // -----
  _indep = false ;
  _soc = 0 ;

  // -----
  // x must be the TiXmlNode of tag "soc_dependent".
  // x は "soc_dependent" タグの TiXmlNode でなければならない。
  // -----
  string d_val = string ( d_in -> Value () ) ;
  if ( d_val != "soc_dependent" )
  {
    cerr << "Error: \"" << d_val << "\" tag not allowed for construction of"
         << " class SOCDepdendentData." << endl ;
    exit ( 1 ) ;
  }

  // -----
  // Scan attributes.
  // 属性をスキャンする。
  // -----
  bool _sw_value = true ;
  bool _sw_soc = true ;
  for ( const TiXmlAttribute * attr
          = d_in -> ToElement () -> FirstAttribute () ;
        attr ; attr = attr -> Next () )
  {
    string a_n = string ( attr -> Name () ) ;
    if ( a_n == "value" )
    {
      _sw_value = false ;
      sscanf ( attr -> Value () , "%lf" , & _data ) ;
    }
    else if ( a_n == "soc" )
    {
      if ( _sw_soc )
      {
        _sw_soc = false ;
        sscanf ( attr -> Value () , "%lf" , & _soc ) ;
      }
      else
      {
        cerr << "ERROR: attribute \"soc\" must not coincide with "
             << "attribute \"independent\" in tag <soc_dependent>" << endl ;
        exit ( 1 ) ;
      }
    }
    else if ( a_n == "independent" )
    {
      string indep_str = string ( attr -> Value () ) ;
      if ( indep_str == "true" || indep_str == "True" || indep_str == "TRUE" )
      {
        if ( _sw_soc )
        {
          _sw_soc = false ;
          _indep = true ;
        }
        else
        {
          cerr << "ERROR: attribute \"independent\" must not coincide with "
               << "attribute \"soc\" in tag <soc_dependent>" << endl ;
          exit ( 2 ) ;
        }
      }
    }
    else
    {
      cerr << "ERROR: tag <soc_dependent> with incorrect attribute "
           << a_n << endl ;
      exit ( 1 ) ;
    }
  }
  if ( _sw_value || _sw_soc )
  {
    cerr << "ERROR: <soc_dependent> data incorrect... missing attribute?"
         << endl ;
    exit ( 1 ) ;
  }
}



// -----
// Constructor of class SOCDependent using a TiXmlNode. The allowed tags
// will be "g_ess_voltage" and "g_ess_current". No tag checks (tag name
// verification + scanning of attributes) will be done for d_in.
// SOCDependent クラスをひとつの TiXmlNode によって初期化。初期化に使える
// タグは "g_ess_voltage" および "g_ess_current" である。d_in については，
// タグのチェック（タグ名確認＋属性スキャン）は行わない。
// -----
SOCDependent :: SOCDependent
( const TiXmlNode * d_in )
{
  // -----
  // Getting child elements of d_in. All tags must be <soc_dependent>.
  // d_in の子を取得. すべて <soc_dependent> タグでなければならない。
  // -----
  bool sw_indep = false ;
  bool sw_not_first = false ;
  double _soc_prev = 0 ;
  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.
    // タグ名チェック。
    // -----
    string _cc_val = string ( _cc -> Value () ) ;
    if ( _cc_val != "soc_dependent" )
    {
      cerr << "Error: \"" << _cc_val << "\" tag not allowed." << endl ;
      exit ( 1 ) ;
    }
    if ( sw_indep )
    {
      cerr << "Error: \"" << _cc_val << "\" tag not allowed after another "
           << "with the \"independent\" attribute" << endl ;
      exit ( 1 ) ;
    }

    SOCDependentNode * _dget = new SOCDependentNode ( _cc ) ;

    // -----
    // Create another object when "independent" attribute is set.
    // "independent" 属性がセットされているときは，もう一つのオブジェクトを
    // 作成する。
    // -----
    if ( _dget -> _indep )
    {
      if ( sw_not_first )
      {
        cerr << "Error: \"" << _cc_val << "\" tag with \"independent\" tag"
             << " not allowed after another one without it" << endl ;
        exit ( 1 ) ;
      }
      sw_indep = true ;
      _dget -> _indep = false ;
      _dget -> _soc = 0 ;
      SOCDependentNode * _dcpy = _dget ;
      _dt . push_back ( _dcpy ) ;
      _dget = new SOCDependentNode ( _dcpy -> _data , 100 , false ) ;
    }
    _dt . push_back ( _dget ) ;
    sw_not_first = true ;
  }

  _pcur = 0 ;
}




// -----
// Copy constructor.
// コピーコンストラクタ.
// -----
SOCDependent :: SOCDependent
( const SOCDependent & e_in )
{
  for ( vector < SOCDependentNode * > :: const_iterator ii
          = e_in . _dt . begin () ;
        ii < e_in . _dt . end () ; ++ ii )
  {
    SOCDependentNode * _dget = new SOCDependentNode ( * * ii ) ;
    _dt . push_back ( _dget ) ;
  }
  _pcur = e_in . _pcur ;
}



// -----
// Getting data for the SOC given as an argument.
// 引数に与えた SOC に対応するデータを取得。
// -----
double
SOCDependent :: getData
( double _soc_in )
  const
{
  try
  {
    while ( _pcur > 0 && _dt . at ( _pcur ) -> _soc > _soc_in )
    {
      -- _pcur ;
    }
  }
  catch ( std :: out_of_range )
  {
    cerr << "Error: at the data search in SOCDependent object (underflow)"
         << endl ;
    exit ( 1 ) ;
  }
  try
  {
    while ( _pcur < _dt . size () - 2
            && _dt . at ( _pcur + 1 ) -> _soc < _soc_in )
    {
      ++ _pcur ;
    }
  }
  catch ( std :: out_of_range )
  {
    cerr << "Error: at the data search in SOCDependent object (overflow)"
         << endl ;
    exit ( 1 ) ;
  }
  double _sh = _dt . at ( _pcur + 1 ) -> _soc ;
  double _sl = _dt . at ( _pcur ) -> _soc ;
  double _dh = _dt . at ( _pcur + 1 ) -> _data ;
  double _dl = _dt . at ( _pcur ) -> _data ;
  return _dl + ( _dh - _dl ) * ( _soc_in - _sl ) / ( _sh - _sl ) ;
}



// -----
// Destructor of class SOCDependent.
// SOCDependent クラスのデストラクタ。
// -----
SOCDependent :: ~SOCDependent
()
{
  for ( vector < SOCDependentNode * > :: iterator ii = _dt . begin () ;
        ii < _dt . end () ; ++ ii )
  {
    delete ( * ii ) ;
  }
}







// -----
// Constructor of class Fixed_Percentage_Losses_Model using a DOM node.
// DC_DC_Initialiser is typedef'ed to TiXmlNode * .
// Fixed_Percentage_Losses_Model クラスを DOM ノードで初期化する.
// DC_DC_Initialiser は TiXmlNode * に typedef されている。
// -----
Fixed_Percentage_Losses_Model :: Fixed_Percentage_Losses_Model
( const DC_DC_Initialiser & d_in )
  : DC_DC_Converter_Losses () ,
    DC_DC_Expander ()
{
  _device_current = 0 ;
  _device_voltage = 0 ;

  // -----
  // Checking if d_in is of tag "fixed_percentage".
  // d_in が "fixed_percentage" タグであることを確認する。
  // -----
  string d_val = string ( d_in -> Value () ) ;
  if ( d_val != "fixed_percentage" )
  {
    cerr << "Error: \"" << d_val << "\" tag not allowed for construction of"
         << " Fixed_Percentage_Losses_Model." << endl ;
    exit ( 1 ) ;
  }

  // -----
  // Reading attributes of tag "fixed_percentage".
  // "fixed_percentage" タグの属性を読み取る。
  // -----
  bool _sw_percentage = true ;
  bool _sw_percentage_charge = true ;
  bool _sw_percentage_discharge = true ;
  for ( const TiXmlAttribute * attr
          = d_in -> ToElement () -> FirstAttribute () ;
        attr ; attr = attr -> Next () )
  {
    string attr_str = string ( attr -> Name () ) ;
    if ( attr_str == "percentage" )
    {
      if ( ! _sw_percentage )
      {
        cerr << "Error: attribute \"percentage\" appeared twice in "
             << "tag <fixed_percentage>?" << endl ;
        exit ( 1 ) ;
      }
      if ( ! _sw_percentage_charge || ! _sw_percentage_discharge )
      {
        cerr << "Error: attribute \"percentage\" must not coincide with "
             << "\"percentage_(charge|discharge)\" in "
             << "tag <fixed_percentage>" << endl ;
        exit ( 1 ) ;
      }
      _sw_percentage = false ;
      sscanf ( attr -> Value () , "%lf" , & _percentage_c ) ;
      _percentage_d = _percentage_c ;
    }
    else if ( attr_str == "percentage_charge" )
    {
      if ( ! _sw_percentage )
      {
        cerr << "Error: attribute \"percentage_charge\" must not coincide "
             << "with \"percentage\" in tag <fixed_percentage>" << endl ;
        exit ( 1 ) ;
      }
      if ( ! _sw_percentage_charge )
      {
        cerr << "Error: attribute \"percentage_charge\" appeared twice in "
             << "tag <fixed_percentage>?" << endl ;
        exit ( 1 ) ;
      }
      _sw_percentage_charge = false ;
      sscanf ( attr -> Value () , "%lf" , & _percentage_c ) ;
    }
    else if ( attr_str == "percentage_discharge" )
    {
      if ( ! _sw_percentage )
      {
        cerr << "Error: attribute \"percentage_discharge\" must not coincide "
             << "with \"percentage\" in tag <fixed_percentage>" << endl ;
        exit ( 1 ) ;
      }
      if ( ! _sw_percentage_discharge )
      {
        cerr << "Error: attribute \"percentage_discharge\" appeared twice in "
             << "tag <fixed_percentage>?" << endl ;
        exit ( 1 ) ;
      }
      _sw_percentage_discharge = false ;
      sscanf ( attr -> Value () , "%lf" , & _percentage_d ) ;
    }
    else
    {
      cerr << "ERROR: tag <fixed_percentage> with incorrect attribute "
           << attr_str << endl ;
      exit ( 1 ) ;
    }
  }
  if ( ! _sw_percentage )
  {
    _sw_percentage_charge = _sw_percentage_discharge = false ;
  }
  if ( ! _sw_percentage_charge && ! _sw_percentage_discharge )
  {
    _sw_percentage = false ;
  }
  if ( _sw_percentage || _sw_percentage_charge || _sw_percentage_discharge )
  {
    cerr << "ERROR: <fixed_percentage> data incorrect... "
         << "missing attribute(s)?" << endl ;
    exit ( 1 ) ;
  }
  if ( _percentage_c < 0.0 || _percentage_c > 100.0
       || _percentage_d < 0.0 || _percentage_d > 100.0 )
  {
    cerr << "Error: losses percentage out of range in construction of "
         << "Fixed_Percentage_Losses_Model." << endl ;
    exit ( 1 ) ;
  }
}



// -----
// Copy constructor.
// コピーコンストラクタ.
// -----
Fixed_Percentage_Losses_Model :: Fixed_Percentage_Losses_Model
( const Fixed_Percentage_Losses_Model & e_in )
  : DC_DC_Converter_Losses	() ,
    DC_DC_Expander		() ,
    _percentage_c 		( e_in . _percentage_c ) ,
    _percentage_d 		( e_in . _percentage_d ) ,
    _device_current 		( e_in . _device_current ) ,
    _device_voltage 		( e_in . _device_voltage )
{
}




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



// -----
// Write a header line to a CSV file.
// CSV ファイルにヘッダ行を書き出す.
// -----
void
Fixed_Percentage_Losses_Model :: 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 << " devvolt" << __quot ;
    f_in << "," << __quot << h_in << " devcurr" << __quot ;
  }
}



// -----
// Calculate (and set) ESD voltage and current.
// -----
void
Fixed_Percentage_Losses_Model :: calculateESDVoltageAndCurrent
( double _v_in ,
  double _c_in )
{
  _device_voltage = _v_in ;
  _device_current = _c_in ;
}



// -----
// Renew the state (if any) of this model.
// 状態がもしあれば，それを更新する。
// -----
void
Fixed_Percentage_Losses_Model :: renewElectricalStates
( double _v_in ,
  double _c_in )
{
  if ( _device_voltage != _v_in || _device_current != _c_in )
  {
    l_ofs << "Warning: voltage and current not set before FPLM::renewES"
          << endl ;
  }
  _device_voltage = _v_in ;
  _device_current = _c_in ;
}




// -----
// Get the losses in [W]. Power will be positive when discharging.
// Arguments: Power [W], Line Voltage [V], Device Voltage [V], Switch.
// Power is positive when discharging. If Switch is true then the power
// is assumed to be the input power (power at the main circuit = pantograph
// side); if false then it is assumed to be the output power (power at the
// ESD side).
// -----
double
Fixed_Percentage_Losses_Model :: getLosses
( double power_in ,
  double v_line_in ,
  double v_esd_in ,
  bool _sw_in /* = true */ )
  const
{
  double _ret_val ;
  if ( _sw_in )
  {
    // ----
    // power_in shows power at the main circuit side.
    // ----
    if ( power_in > 0 )
    {
      // power_in: discharge
      _ret_val = power_in * _percentage_d / ( 100 - _percentage_d ) ;
    }
    else
    {
      // power_in: charge
      _ret_val = - power_in * _percentage_c / 100 ;
    }
  }
  else
  {
    // ----
    // power_in shows power at the ESD side.
    // ----
    if ( power_in > 0 )
    {
      // power_in: discharge
      _ret_val = power_in * _percentage_d / 100 ;
    }
    else
    {
      // power_in: charge
      _ret_val = - power_in * _percentage_c / ( 100 - _percentage_c ) ;
    }
  }
  return _ret_val ;
}




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

  // -----
  // Accessing subdata.
  // 子データにアクセスする。
  // -----
  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 = string ( _cc -> Value () ) ;
    bool sw_volt = true ;
    if ( _cc_val == "dc_dc_converter_losses" )
    {
      // -----
      // Accessing sub-subdata.
      // 孫データにアクセスする。
      // -----
      bool sw_dc_dc = false ;
      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: two or more elements within tag \"" << _cc_val
               << "\" 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 ;
    }
    if ( _cc_val == "energystoragedevice" )
    {
      // -----
      // Accessing sub-subdata.
      // 孫データにアクセスする。
      // -----
      bool sw_esd = false ;
      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: 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 ;
    }
    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 ;
    }
    else
    {
      cerr << "Error: \"" << _cc_val << "\" tag not allowed for construction"
           << " of a SOCDependent class object." << endl ;
      exit ( 1 ) ;
    }

    // -----
    // Scan attributes.
    // 属性をスキャンする。
    // -----
    bool _sw_type = true ;
    string type_attr ;
    for ( const TiXmlAttribute * attr
            = _cc -> ToElement () -> FirstAttribute () ;
          attr ; attr = attr -> Next () )
    {
      if ( string ( attr -> Name () ) != "type" )
      {
        cerr << "Error: \"" << attr -> Name () << "\" attribute not allowed"
             << " in tag <" << _cc_val << ">" << endl ;
        exit ( 1 ) ;
      }
      if ( ! _sw_type )
      {
        cerr << "Error: \"" << attr -> Name () << "\" in tag <" << _cc_val
             << ">; appeared twice???" << endl ;
        exit ( 1 ) ;
      }
      _sw_type = false ;
      type_attr = string ( attr -> Value () ) ;
    }
    if ( _sw_type )
    {
      cerr << "ERROR: 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" )
      {
        _g_ess_voltage_lowest = sd_x ;
      }
      else if ( type_attr == "low_limiter" )
      {
        _g_ess_voltage_low_limiter = sd_x ;
      }
      else if ( type_attr == "discharge_th_low" )
      {
        _g_ess_voltage_discharge_th_low = sd_x ;
      }
      else if ( type_attr == "discharge_th_high" )
      {
        _g_ess_voltage_discharge_th_high = sd_x ;
      }
      else if ( type_attr == "charge_th_low" )
      {
        _g_ess_voltage_charge_th_low = sd_x ;
      }
      else if ( type_attr == "charge_th_high" )
      {
        _g_ess_voltage_charge_th_high = sd_x ;
      }
      else if ( type_attr == "high_limiter" )
      {
        _g_ess_voltage_high_limiter = sd_x ;
      }
      else if ( type_attr == "maximum" )
      {
        _g_ess_voltage_maximum = sd_x ;
      }
      else
      {
        cerr << "ERROR: tag <" << _cc_val << "> with incorrect type \""
             << type_attr << "\"" << endl ;
        exit ( 1 ) ;
      }
    }
    else
    {
      if ( type_attr == "discharge" )
      {
        _g_ess_current_discharge = sd_x ;
      }
      else if ( type_attr == "floating" )
      {
        _g_ess_current_floating = sd_x ;
      }
      else if ( type_attr == "charge" )
      {
        _g_ess_current_charge = sd_x ;
      }
      else
      {
        cerr << "ERROR: tag <" << _cc_val << "> with incorrect type \""
             << type_attr << "\"" << endl ;
        exit ( 1 ) ;
      }
    }
  }
}




// -----
// Copy constructor.
// コピーコンストラクタ.
// -----
Generic_ESS_Substation :: Generic_ESS_Substation
( const Generic_ESS_Substation & e_in )
  : ESS_Substation	( e_in ) ,
    ESS_Expander	()
{
  _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.
// デストラクタ.
// -----
Generic_ESS_Substation :: ~Generic_ESS_Substation
()
{
  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 ;
}




// -----
// Calculate the state (voltage and current) of the system.
// システムの状態（電圧・電流）の計算
// -----
void
Generic_ESS_Substation :: calculateVoltagesAndCurrents
( double _v_in ,
  double _i_in ,
  double _dv_dth_in ,
  double _di_dth_in )
{
  // -----
  // Setting parameters.
  // パラメータのセット.
  // -----
  _v = _v_in ;
  _dv_dth = _dv_dth_in ;
  double _soc = getSOC () ;
  _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: Generic_ESS_Substation: 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: Generic_ESS_Substation: 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: Generic_ESS_Substation: 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: Generic_ESS_Substation: 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: Generic_ESS_Substation: 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: Generic_ESS_Substation: 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: Generic_ESS_Substation: 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.
  // _i と _di_dth の計算。
  // -----
  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_SUB_ESS
  l_ofs << "SUB_ESS: _i, _di_dth before processESDMaximumLimits: "
        << _i << ", " << _di_dth << endl ;
#endif
  processESDMaximumLimits () ;
}




// -----
// Process maximum charge/discharge limit imposed by the ESD. This will
// supersede the I-V characteristics given by the _g_ess_voltage_* and
// _g_ess_current_* variables in class Generic_ESS_Substation.
// -----
void
Generic_ESS_Substation :: processESDMaximumLimits
()
{
#ifdef DEBUG_SUB_ESS
  l_ofs << "SUB_ESS: in 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_SUB_ESS
  l_ofs << "SUB_ESS: 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.
  // dev power must be between _max_power_c and _max_power_d.
  // ----
  double _p_ess = _v * _i ;
#ifdef DEBUG_SUB_ESS
  l_ofs << "SUB_ESS: ess power = " << _p_ess << endl ;
#endif
  if ( _p_ess < _max_power_c )
  {
#ifdef DEBUG_SUB_ESS
    l_ofs << "SUB_ESS: charge dev power capping" << endl ;
#endif
    _i = _max_power_c / _v ;
    _di_dth = - _i * _dv_dth / _v ;
#ifdef DEBUG_SUB_ESS
    l_ofs << "SUB_ESS: _i, _di_dth: " << _i << ", " << _di_dth << endl ;
#endif
  }
  else if ( _p_ess > _max_power_d )
  {
#ifdef DEBUG_SUB_ESS
    l_ofs << "SUB_ESS: discharge dev power capping" << endl ;
#endif
    _i = _max_power_d / _v ;
    _di_dth = - _i * _dv_dth / _v ;
#ifdef DEBUG_SUB_ESS
    l_ofs << "SUB_ESS: _i, _di_dth: " << _i << ", " << _di_dth << endl ;
#endif
  }
  else
  {
#ifdef DEBUG_SUB_ESS
    l_ofs << "SUB_ESS: no power capping necessary" << endl ;
#endif
  }
}




// -----
// Determine the voltage and current of the ESD using the Newton-Raphson
// method.
// -----
void
Generic_ESS_Substation :: 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_SUB_ESS
  l_ofs << "SUB_ESS: GES::gEVC: " << cyc_devcur << ": vi, idev: "
        << _vi << " * " << _idev << " = " << _vi * _idev
        << ", f = " << f << endl ;
#endif
  bool _sw_chlim = true ;
  vector < pair < double , double > > _sol_history ;
  _sol_history . clear () ;
  bool _sw_newton = true ;
  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 ) ) ;
      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 ( 1 ) ;
    }
    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_SUB_ESS
      l_ofs << "SUB_ESS: GES::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_SUB_ESS
      l_ofs << "SUB_ESS: GES::gEVC: " << cyc_devcur << ": vi, idev: "
            << _vi << " * " << _idev << " = " << _vi * _idev
            << ", f = " << f << endl ;
#endif
    }
  }
}




// -----
// Calculate ESD voltage and current.
// -----
void
Generic_ESS_Substation :: calculateESDVoltageAndCurrent
( double _v_in ,
  double _i_in )
{
  // -----
  // The device voltage to start the Newton-Raphson method with.
  // Initialisation will be re-done in getESDVoltageAndCurrent () member
  // subfunction.
  // -----
  double _vi = 0 ;

  // -----
  // The device current. Initialisation will be re-done in
  // getESDVoltageAndCurrent () member subfunction.
  // -----
  double _idev = 0 ;

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

  // -----
  // Tell the DC-DC converter ESD voltage and current.
  // -----
  _ddcl -> calculateESDVoltageAndCurrent ( _vi , _idev ) ;

  // -----
  // Tell the ESD its voltage and current.
  // -----
  _esd -> calculateESDVoltageAndCurrent ( _idev ) ;
}




// -----
// Renew the state of the ESS.
// システムの内部状態（SOCなど）の更新
// -----
void
Generic_ESS_Substation :: renewElectricalStates
( double _v_in ,
  double _i_in )
{
  // -----
  // The device voltage to start the Newton-Raphson method with.
  // Initialisation will be re-done in getESDVoltageAndCurrent () member
  // subfunction.
  // -----
  double _vi = 0 ;

  // -----
  // The device current. Initialisation will be re-done in
  // getESDVoltageAndCurrent () member subfunction.
  // -----
  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 -> renewElectricalStates ( _vi , _idev ) ;

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



// -----
// Write data to a CSV file.
// CSV ファイルにデータを書き出す.
// -----
void
Generic_ESS_Substation :: 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
Generic_ESS_Substation :: 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 ) ;
}




// -----
// Regeneration limiter processing.
// 回生絞込システムへの対応。
// -----
void
No_ESS_OnBoard :: processRegenerationLimiter
( train_ParamFunc * _pf )
{
  // Main circuit current = pantograph current
  _pf -> setMainCircuitCurrent () ;
}




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

  // -----
  // Accessing subdata.
  // 子データにアクセスする。
  // -----
  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.
      // 孫データにアクセスする。
      // -----
      bool sw_dc_dc = false ;
      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: two or more elements within tag \"" << _cc_val
               << "\" tag are not allowed." << endl ;
          exit ( 2 ) ;
        }
        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.
      // 孫データにアクセスする。
      // -----
      bool sw_esd = false ;
      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: two or more elements within tag \"" << _cc_val
               << "\" tag are not allowed." << endl ;
          exit ( 2 ) ;
        }
        sw_esd = true ;

        // -----
        // Create an object.
        // オブジェクトをつくる。
        // -----
        EnergyStorageDevice * p_esd
          = ESD_Expander :: create ( _gc -> Value () , _gc ) ;
        _esd = p_esd ;
      }
      continue ;
    }
    else if ( _cc_val != "parameters" )
    {
      cerr << "Error: \"" << _cc_val << "\" tag not allowed for construction"
           << " of a OBESS_RefSOC_Controlled class object." << endl ;
      exit ( 1 ) ;
    }

    // -----
    // Tag _cc must now be <parameters>. Scan attributes.
    // ここではタグ _cc は必ず <patameters>。属性をスキャンする。
    // -----
    bool _sw_follower_max_discharge_current = false ;
    bool _sw_follower_max_discharge_current_low_speed = false ;
    bool _sw_follower_delta_soc_max_discharge_threshold = false ;
    bool _sw_follower_delta_soc_discharge_threshold = false ;
    bool _sw_follower_max_charge_current = false ;
    bool _sw_follower_max_charge_current_low_speed = false ;
    bool _sw_follower_lowest_velocity_threshold = false ;
    bool _sw_follower_low_velocity_threshold = false ;
    bool _sw_follower_delta_soc_max_charge_threshold = false ;
    bool _sw_follower_delta_soc_charge_threshold = false ;
    bool _sw_follower_delta_soc_lowest_nofollow_threshold = false ;
    bool _sw_follower_delta_soc_low_nofollow_threshold = false ;
    bool _sw_follower_delta_soc_high_nofollow_threshold = false ;
    bool _sw_follower_delta_soc_highest_nofollow_threshold = false ;
    bool _sw_max_accelerating_current = false ;
    bool _sw_max_regenerating_current = false ;
    bool _sw_max_discharge_current = false ;
    bool _sw_max_discharge_soc_low_threshold = false ;
    bool _sw_max_discharge_soc_high_threshold = false ;
    bool _sw_max_charge_current = false ;
    bool _sw_max_charge_soc_low_threshold = false ;
    bool _sw_max_charge_soc_high_threshold = false ;
    for ( const TiXmlAttribute * attr
            = _cc -> ToElement () -> FirstAttribute () ;
          attr ; attr = attr -> Next () )
    {
      string _atn = string ( attr -> Name () ) ;
      string _atv = string ( attr -> Value () ) ;
      if ( _atn == "follower_max_discharge_current" )
      {
        // Attribute "follower_max_discharge_current"
        //  -- for variable _follower_max_discharge_current
        if ( _sw_follower_max_discharge_current )
        {
          cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute \""
               << "follower_max_discharge_current\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf", & _follower_max_discharge_current ) ;
        l_ofs << StrPrintf
          ( "RefSOC OBESS: _follower_max_discharge_current = %.2f" ,
            _follower_max_discharge_current ) << endl ;
        _sw_follower_max_discharge_current = true ;
      }
      else if ( _atn == "follower_max_discharge_current_low_speed" )
      {
        // Attribute "follower_max_discharge_current_low_speed"
        //  -- for variable _follower_max_discharge_current_low_speed
        if ( _sw_follower_max_discharge_current_low_speed )
        {
          cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute \""
               << "follower_max_discharge_current_low_speed\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _follower_max_discharge_current_low_speed ) ;
        l_ofs << StrPrintf
          ( "RefSOC OBESS: _follower_max_discharge_current_low_speed = %.2f" ,
            _follower_max_discharge_current_low_speed ) << endl ;
        _sw_follower_max_discharge_current_low_speed = true ;
      }
      else if ( _atn == "follower_delta_soc_max_discharge_threshold" )
      {
        // Attribute "follower_delta_soc_max_discharge_threshold"
        //  -- for variable _follower_delta_soc_max_discharge_threshold
        if ( _sw_follower_delta_soc_max_discharge_threshold )
        {
          cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute "
               << "\"follower_delta_soc_max_discharge_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _follower_delta_soc_max_discharge_threshold ) ;
        l_ofs << "RefSOC OBESS: " << StrPrintf
          ( "_follower_delta_soc_max_discharge_threshold = %.2f" ,
            _follower_delta_soc_max_discharge_threshold ) << endl ;
        _sw_follower_delta_soc_max_discharge_threshold = true ;
      }
      else if ( _atn == "follower_delta_soc_discharge_threshold" )
      {
        // Attribute "follower_delta_soc_discharge_threshold"
        //  -- for variable _follower_delta_soc_discharge_threshold
        if ( _sw_follower_delta_soc_discharge_threshold )
        {
          cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute "
               << "\"follower_delta_soc_discharge_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _follower_delta_soc_discharge_threshold ) ;
        l_ofs << "RefSOC OBESS: " << StrPrintf
          ( "_follower_delta_soc_discharge_threshold = %.2f" ,
            _follower_delta_soc_discharge_threshold ) << endl ;
        _sw_follower_delta_soc_discharge_threshold = true ;
      }
      else if ( _atn == "follower_max_charge_current" )
      {
        // Attribute "follower_max_charge_current"
        //  -- for variable _follower_max_charge_current
        if ( _sw_follower_max_charge_current )
        {
          cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute "
               << "\"follower_max_charge_current\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf" ,
                 & _follower_max_charge_current ) ;
        l_ofs << "RefSOC OBESS: " << StrPrintf
          ( "_follower_max_charge_current = %.2f" ,
            _follower_max_charge_current ) << endl ;
        _sw_follower_max_charge_current = true ;
      }
      else if ( _atn == "follower_max_charge_current_low_speed" )
      {
        // Attribute "follower_max_charge_current_low_speed"
        //  -- for variable _follower_max_charge_current_low_speed
        if ( _sw_follower_max_charge_current_low_speed )
        {
          cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute \""
               << "follower_max_charge_current_low_speed\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf" ,
                 & _follower_max_charge_current_low_speed ) ;
        l_ofs << StrPrintf
          ( "RefSOC OBESS: _follower_max_charge_current_low_speed = %.2f" ,
            _follower_max_charge_current_low_speed ) << endl ;
        _sw_follower_max_charge_current_low_speed = true ;
      }
      else if ( _atn == "follower_delta_soc_max_charge_threshold" )
      {
        // Attribute "follower_delta_soc_max_charge_threshold"
        //  -- for variable _follower_delta_soc_max_charge_threshold
        if ( _sw_follower_delta_soc_max_charge_threshold )
        {
          cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute "
               << "\"follower_delta_soc_max_charge_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _follower_delta_soc_max_charge_threshold ) ;
        l_ofs << "RefSOC OBESS: " << StrPrintf
          ( "_follower_delta_soc_max_charge_threshold = %.2f" ,
            _follower_delta_soc_max_charge_threshold ) << endl ;
        _sw_follower_delta_soc_max_charge_threshold = true ;
      }
      else if ( _atn == "follower_delta_soc_charge_threshold" )
      {
        // Attribute "follower_delta_soc_charge_threshold"
        //  -- for variable _follower_delta_soc_charge_threshold
        if ( _sw_follower_delta_soc_charge_threshold )
        {
          cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute "
               << "\"follower_delta_soc_charge_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _follower_delta_soc_charge_threshold ) ;
        l_ofs << "RefSOC OBESS: " << StrPrintf
          ( "_follower_delta_soc_charge_threshold = %.2f" ,
            _follower_delta_soc_charge_threshold ) << endl ;
        _sw_follower_delta_soc_charge_threshold = true ;
      }
      else if ( _atn == "follower_lowest_velocity_threshold" )
      {
        // Attribute "follower_lowest_velocity_threshold"
        //  -- for variable _follower_lowest_velocity_threshold
        if ( _sw_follower_lowest_velocity_threshold )
        {
          cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute "
               << "\"follower_lowest_velocity_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf" ,
                 & _follower_lowest_velocity_threshold ) ;
        l_ofs << "RefSOC OBESS: " << StrPrintf
          ( "_follower_lowest_velocity_threshold = %.2f" ,
            _follower_lowest_velocity_threshold ) << endl ;
        _sw_follower_lowest_velocity_threshold = true ;
      }
      else if ( _atn == "follower_low_velocity_threshold" )
      {
        // Attribute "follower_low_velocity_threshold"
        //  -- for variable _follower_low_velocity_threshold
        if ( _sw_follower_low_velocity_threshold )
        {
          cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute "
               << "\"follower_low_velocity_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf" ,
                 & _follower_low_velocity_threshold ) ;
        l_ofs << "RefSOC OBESS: " << StrPrintf
          ( "_follower_low_velocity_threshold = %.2f" ,
            _follower_low_velocity_threshold ) << endl ;
        _sw_follower_low_velocity_threshold = true ;
      }
      else if ( _atn == "follower_delta_soc_lowest_nofollow_threshold" )
      {
        // Attribute "follower_delta_soc_lowest_nofollow_threshold"
        //  -- for variable _follower_delta_soc_lowest_nofollow_threshold
        if ( _sw_follower_delta_soc_lowest_nofollow_threshold )
        {
          cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute "
               << "\"follower_delta_soc_lowest_nofollow_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _follower_delta_soc_lowest_nofollow_threshold ) ;
        l_ofs << "RefSOC OBESS: " << StrPrintf
          ( "_follower_delta_soc_lowest_nofollow_threshold = %.2f" ,
            _follower_delta_soc_lowest_nofollow_threshold ) << endl ;
        _sw_follower_delta_soc_lowest_nofollow_threshold = true ;
      }
      else if ( _atn == "follower_delta_soc_low_nofollow_threshold" )
      {
        // Attribute "follower_delta_soc_low_nofollow_threshold"
        //  -- for variable _follower_delta_soc_low_nofollow_threshold
        if ( _sw_follower_delta_soc_low_nofollow_threshold )
        {
          cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute "
               << "\"follower_delta_soc_low_nofollow_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _follower_delta_soc_low_nofollow_threshold ) ;
        l_ofs << "RefSOC OBESS: " << StrPrintf
          ( "_follower_delta_soc_low_nofollow_threshold = %.2f" ,
            _follower_delta_soc_low_nofollow_threshold ) << endl ;
        _sw_follower_delta_soc_low_nofollow_threshold = true ;
      }
      else if ( _atn == "follower_delta_soc_high_nofollow_threshold" )
      {
        // Attribute "follower_delta_soc_high_nofollow_threshold"
        //  -- for variable _follower_delta_soc_high_nofollow_threshold
        if ( _sw_follower_delta_soc_high_nofollow_threshold )
        {
          cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute "
               << "\"follower_delta_soc_high_nofollow_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _follower_delta_soc_high_nofollow_threshold ) ;
        l_ofs << "RefSOC OBESS: " << StrPrintf
          ( "_follower_delta_soc_high_nofollow_threshold = %.2f" ,
            _follower_delta_soc_high_nofollow_threshold ) << endl ;
        _sw_follower_delta_soc_high_nofollow_threshold = true ;
      }
      else if ( _atn == "follower_delta_soc_highest_nofollow_threshold" )
      {
        // Attribute "follower_delta_soc_highest_nofollow_threshold"
        //  -- for variable _follower_delta_soc_highest_nofollow_threshold
        if ( _sw_follower_delta_soc_highest_nofollow_threshold )
        {
          cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute "
               << "\"follower_delta_soc_highest_nofollow_threshold\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _follower_delta_soc_highest_nofollow_threshold ) ;
        l_ofs << "RefSOC OBESS: " << StrPrintf
          ( "_follower_delta_soc_highest_nofollow_threshold = %.2f" ,
            _follower_delta_soc_highest_nofollow_threshold ) << endl ;
        _sw_follower_delta_soc_highest_nofollow_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_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute "
               << "\"max_accelerating_current\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _max_accelerating_current ) ;
        l_ofs << "RefSOC OBESS: " << StrPrintf
          ( "_max_accelerating_current = %.2f" ,
            _max_accelerating_current ) << 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_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute "
               << "\"max_regenerating_current\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _max_regenerating_current ) ;
        l_ofs << "RefSOC OBESS: " << StrPrintf
          ( "_max_regenerating_current = %.2f" ,
            _max_regenerating_current ) << endl ;
        _sw_max_regenerating_current = 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_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute "
               << "\"max_discharge_current\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _max_discharge_current ) ;
        l_ofs << "RefSOC OBESS: " << StrPrintf
          ( "_max_discharge_current = %.2f" ,
            _max_discharge_current ) << 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_RefSOC_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 << "RefSOC OBESS: " << StrPrintf
          ( "_max_discharge_soc_low_threshold = %.2f" ,
            _max_discharge_soc_low_threshold ) << 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_RefSOC_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 << "RefSOC OBESS: " << StrPrintf
          ( "_max_discharge_soc_high_threshold = %.2f" ,
            _max_discharge_soc_high_threshold ) << endl ;
        _sw_max_discharge_soc_high_threshold = 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_RefSOC_Controlled in P file:"
               << endl << "  Duplicate attribute "
               << "\"max_charge_current\"?" << endl ;
          exit ( 1 ) ;
        }
        sscanf ( _atv . c_str () , "%lf",
                 & _max_charge_current ) ;
        l_ofs << "RefSOC OBESS: " << StrPrintf
          ( "_max_charge_current = %.2f" ,
            _max_charge_current ) << 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_RefSOC_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 << "RefSOC OBESS: " << StrPrintf
          ( "_max_charge_soc_low_threshold = %.2f" ,
            _max_charge_soc_low_threshold ) << 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_RefSOC_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 << "RefSOC OBESS: " << StrPrintf
          ( "_max_charge_soc_high_threshold = %.2f" ,
            _max_charge_soc_high_threshold ) << endl ;
        _sw_max_charge_soc_high_threshold = true ;
      }
      else
      {
        cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
             << endl
             << "  Attribute \"" << _atn << "\" not allowed" << endl ;
        exit ( 1 ) ;
      }
    }
    if ( ! ( _sw_follower_max_discharge_current
             && _sw_follower_max_discharge_current_low_speed
             && _sw_follower_delta_soc_max_discharge_threshold
             && _sw_follower_delta_soc_discharge_threshold
             && _sw_follower_max_charge_current
             && _sw_follower_max_charge_current_low_speed
             && _sw_follower_delta_soc_max_charge_threshold
             && _sw_follower_delta_soc_charge_threshold
             && _sw_follower_lowest_velocity_threshold
             && _sw_follower_low_velocity_threshold
             && _sw_follower_delta_soc_lowest_nofollow_threshold
             && _sw_follower_delta_soc_low_nofollow_threshold
             && _sw_follower_delta_soc_high_nofollow_threshold
             && _sw_follower_delta_soc_highest_nofollow_threshold
             && _sw_max_accelerating_current
             && _sw_max_regenerating_current
             && _sw_max_discharge_current
             && _sw_max_discharge_soc_low_threshold
             && _sw_max_discharge_soc_high_threshold
             && _sw_max_charge_current
             && _sw_max_charge_soc_low_threshold
             && _sw_max_charge_soc_high_threshold ) )
    {
      cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
           << endl << "  Some of the required attribute(s) missing" << endl ;
      exit ( 1 ) ;
    }
    // ----
    // Data check.
    // ----
    if ( _follower_max_discharge_current < 0 )
    {
      cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
           << endl << "  _follower_max_discharge_current must be positive"
           << endl ;
      exit ( 1 ) ;
    }
    if ( _follower_max_discharge_current_low_speed < 0 )
    {
      cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
           << endl
           << "  _follower_max_discharge_current_low_speed must be positive"
           << endl ;
      exit ( 1 ) ;
    }
    if ( _follower_delta_soc_max_discharge_threshold > 110
         || ( _follower_delta_soc_max_discharge_threshold
              < _follower_delta_soc_discharge_threshold )
         || _follower_delta_soc_discharge_threshold < 0 )
    {
      cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
           << endl << "  _follower_delta_soc(*)_discharge_threshold "
           << "inconsistently configured" << endl ;
      exit ( 1 ) ;
    }
    if ( _follower_max_charge_current < 0 )
    {
      cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
           << endl << "  _follower_max_charge_current must be positive"
           << endl ;
      exit ( 1 ) ;
    }
    if ( _follower_max_charge_current_low_speed < 0 )
    {
      cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
           << endl
           << "  _follower_max_charge_current_low_speed must be positive"
           << endl ;
      exit ( 1 ) ;
    }
    if ( _follower_delta_soc_max_charge_threshold > 110
         || _follower_delta_soc_max_charge_threshold
         < _follower_delta_soc_charge_threshold
         || _follower_delta_soc_charge_threshold < 0 )
    {
      cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
           << endl << "  _follower_delta_soc(*)_charge_threshold "
           << "inconsistently configured" << endl ;
      exit ( 1 ) ;
    }
    if ( _follower_lowest_velocity_threshold < INVLIM
         || _follower_lowest_velocity_threshold
         > _follower_low_velocity_threshold )
    {
      cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
           << endl << "  _follower_low(*)_velocity_threshold "
           << "inconsistently configured" << endl ;
      exit ( 1 ) ;
    }
    if ( _follower_delta_soc_lowest_nofollow_threshold
         > _follower_delta_soc_low_nofollow_threshold
         || _follower_delta_soc_low_nofollow_threshold
         > _follower_delta_soc_high_nofollow_threshold
         || _follower_delta_soc_high_nofollow_threshold
         > _follower_delta_soc_highest_nofollow_threshold
         || _follower_delta_soc_lowest_nofollow_threshold < - 110
         || _follower_delta_soc_highest_nofollow_threshold > 110 )
    {
      cerr << "Error initialising OBESS_RefSOC_Controlled in P file:"
           << endl << "  _follower_delta_soc_(*)_nofollow_threshold "
           << "inconsistently configured" << endl ;
      exit ( 1 ) ;
    }
    if ( _max_accelerating_current < 0 )
    {
      cerr << "Error initialising OBESS_RefSOC_Controlled in P file:" << endl
           << "  _max_accelerating_current must be positive" << endl ;
      exit ( 1 ) ;
    }
    if ( _max_regenerating_current < 0 )
    {
      cerr << "Error initialising OBESS_RefSOC_Controlled in P file:" << endl
           << "  _max_regenerating_current must be positive" << endl ;
      exit ( 1 ) ;
    }
    if ( _max_discharge_current < 0 )
    {
      cerr << "Error initialising OBESS_RefSOC_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_RefSOC_Controlled in P file:"
           << endl << "  _max_discharge_soc_(*)_threshold "
           << "inconsistently configured" << endl ;
      exit ( 1 ) ;
    }
    if ( _max_charge_current < 0 )
    {
      cerr << "Error initialising OBESS_RefSOC_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_RefSOC_Controlled in P file:"
           << endl << "  _max_charge_soc_(*)_threshold "
           << "inconsistently configured" << endl ;
      exit ( 1 ) ;
    }
  }
}




// -----
// Copy constructor.
// コピーコンストラクタ.
// -----
OBESS_RefSOC_Controlled :: OBESS_RefSOC_Controlled
( OBESS_RefSOC_Controlled const & e_in )
  : ESS_OnBoard	( e_in ) ,
    OBESS_Expander () ,
    _follower_max_discharge_current
    ( e_in . _follower_max_discharge_current ) ,
    _follower_max_discharge_current_low_speed
    ( e_in . _follower_max_discharge_current_low_speed ) ,
    _follower_delta_soc_max_discharge_threshold
    ( e_in . _follower_delta_soc_max_discharge_threshold ) ,
    _follower_delta_soc_discharge_threshold
    ( e_in . _follower_delta_soc_discharge_threshold ) ,
    _follower_max_charge_current ( e_in . _follower_max_charge_current ) ,
    _follower_max_charge_current_low_speed
    ( e_in . _follower_max_charge_current_low_speed ) ,
    _follower_lowest_velocity_threshold
    ( e_in . _follower_lowest_velocity_threshold ) ,
    _follower_low_velocity_threshold
    ( e_in . _follower_low_velocity_threshold ) ,
    _follower_delta_soc_max_charge_threshold
    ( e_in . _follower_delta_soc_max_charge_threshold ) ,
    _follower_delta_soc_charge_threshold
    ( e_in . _follower_delta_soc_charge_threshold ) ,
    _follower_delta_soc_lowest_nofollow_threshold
    ( e_in . _follower_delta_soc_lowest_nofollow_threshold ) ,
    _follower_delta_soc_low_nofollow_threshold
    ( e_in . _follower_delta_soc_low_nofollow_threshold ) ,
    _follower_delta_soc_high_nofollow_threshold
    ( e_in . _follower_delta_soc_high_nofollow_threshold ) ,
    _follower_delta_soc_highest_nofollow_threshold
    ( e_in . _follower_delta_soc_highest_nofollow_threshold ) ,
    _max_accelerating_current ( e_in . _max_accelerating_current ) ,
    _max_regenerating_current ( e_in . _max_regenerating_current ) ,
    _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 ) ,
    _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 ) ,
    _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 () ;
}




// -----
// Destructor.
// デストラクタ.
// -----
OBESS_RefSOC_Controlled :: ~OBESS_RefSOC_Controlled
()
{
  delete _esd ;
  delete _ddcl ;
}




// -----
// Substitution operator.
// 代入演算子.
// -----
OBESS_RefSOC_Controlled &
OBESS_RefSOC_Controlled :: operator=
( ESS_OnBoard const & y )
{
  try
  {
    OBESS_RefSOC_Controlled const & x
      = dynamic_cast < OBESS_RefSOC_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_RefSOC_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_RefSOC_Controlled :: calculateVoltagesAndCurrents
( train_ParamFunc * _pf )
{
#ifdef DEBUG_TRN_ESS
  l_ofs << "car " << _pf -> getCarNumber ()
        << ": OBESS RefSOC, 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 _storeable = getEnergyCapacity () ;	// Energy Capacity [J]

  double _pos = _pf -> getPosition () ;	// 列車位置
  double _vel = _pf -> getVelocity () ;	// 列車速度

  nextsta const * _nxx = _pf -> getNextsta () ;
  int _direc = _nxx -> direction () ;

#ifdef DEBUG_TRN_ESS
  l_ofs << " _pos, _vel, _nxx = " << _pos << ", " << _vel
        << ", " << _nxx -> dpttbl () << endl ;
#endif

  SOC_FeedForward_Data const * _scurve = _nxx -> get_SOC_Curve () ;
  if ( ! _scurve )
  {
    cerr << "Error: SOC curve null pointer" << endl ;
    exit ( 1 ) ;
  }

  SOC_FeedForward_Data :: _Data _sref = _scurve -> getData ( _pos ) ;

  // -----
  // From Amano's program.
  // 天野くんのプログラムから.
  // -----

  // (A) Reference SOC value: _sref . _soc
  // (B) Reference SOC derived by x: _sref . _dsoc_dx
  // (C) Charge/discharge power based on Reference SOC data:
  //     (B) x (train velocity) x (energy capacity)
  double _p1 = _sref . _dsoc_dx * _vel * _direc * _storeable / 3.6e5 ;

  double _a1 = - _p1 / _v ;
  double _da1_dv = _p1 / ( _v * _v ) ;

#ifdef DEBUG_TRN_ESS_A1
  l_ofs << "car " << _pf -> getCarNumber () << ":"
        << " p|v|S|dS|a1|p1|EC = " << _pos << "|" << _vel
        << "|" << _sref . _soc << "|" << _sref . _dsoc_dx << "|"
        << _a1 << "|" << _p1 << "|" << _storeable << endl ;
#endif
#ifdef DEBUG_TRN_ESS
  l_ofs << " _a1, _da1_dv, _dsoc_dx = " << _a1 << ", " << _da1_dv
        << ", " << _sref . _dsoc_dx << endl ;
#endif

  // _delta_soc: negative -> current _soc too high, discharge.
  // _delta_soc: positive -> current _soc too low, charge.
  double _delta_soc = _sref . _soc - _soc ;

#ifdef DEBUG_TRN_ESS
  l_ofs << " _soc, ref SOC , _delta_soc = " << _soc << ", " << _sref . _soc
        << ", " << _delta_soc << endl ;
#endif

  double _a2_mdc = _follower_max_discharge_current ;
  double _a2_mcc = _follower_max_charge_current ;
  if ( _vel < _follower_lowest_velocity_threshold )
  {
    _a2_mdc = _follower_max_discharge_current_low_speed ;
    _a2_mcc = _follower_max_charge_current_low_speed ;
  }
  else if ( _vel < _follower_low_velocity_threshold )
  {
    _a2_mdc -= _follower_max_discharge_current_low_speed ;
    _a2_mcc -= _follower_max_charge_current_low_speed ;
    _a2_mdc *= _vel - _follower_lowest_velocity_threshold ;
    _a2_mcc *= _vel - _follower_lowest_velocity_threshold ;
    _a2_mdc /= _follower_low_velocity_threshold
      - _follower_lowest_velocity_threshold ;
    _a2_mcc /= _follower_low_velocity_threshold
      - _follower_lowest_velocity_threshold ;
    _a2_mdc += _follower_max_discharge_current_low_speed ;
    _a2_mcc += _follower_max_charge_current_low_speed ;
  }

  double _a2 = 0 ;
  if ( _delta_soc < - _follower_delta_soc_max_discharge_threshold )
  {
    _a2 = _a2_mdc ;
  }
  else if ( _delta_soc < - _follower_delta_soc_discharge_threshold )
  {
    _a2 = _a2_mdc ;
    _a2 *= - _delta_soc - _follower_delta_soc_discharge_threshold ;
    _a2 /= _follower_delta_soc_max_discharge_threshold
      - _follower_delta_soc_discharge_threshold ;
  }
  else if ( _delta_soc > _follower_delta_soc_max_charge_threshold )
  {
    _a2 = - _a2_mcc ;
  }
  else if ( _delta_soc > _follower_delta_soc_charge_threshold )
  {
    _a2 = - _a2_mcc ;
    _a2 *= _delta_soc - _follower_delta_soc_charge_threshold ;
    _a2 /= _follower_delta_soc_max_charge_threshold
      - _follower_delta_soc_charge_threshold ;
  }

  double _amp = 1 ;
  if ( _delta_soc >= _follower_delta_soc_lowest_nofollow_threshold )
  {
    if ( _delta_soc < _follower_delta_soc_low_nofollow_threshold )
    {
      _amp = _delta_soc - _follower_delta_soc_low_nofollow_threshold ;
      _amp /= _follower_delta_soc_lowest_nofollow_threshold
        - _follower_delta_soc_low_nofollow_threshold ;
    }
    else if ( _delta_soc < _follower_delta_soc_high_nofollow_threshold )
    {
      _amp = 0 ;
    }
    else if ( _delta_soc < _follower_delta_soc_highest_nofollow_threshold )
    {
      _amp = _delta_soc - _follower_delta_soc_high_nofollow_threshold ;
      _amp /= _follower_delta_soc_highest_nofollow_threshold
        - _follower_delta_soc_high_nofollow_threshold ;
    }
  }
#ifdef DEBUG_TRN_ESS
  l_ofs << " _a2 , _amp = " << _a2 << ", " << _amp << endl ;
#endif

  _i = _a1 * _amp + _a2 ;
  _di_dth = _da1_dv * _dv_dth * _amp ;

  // ----
  // 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.
  // ----
  processESDMaximumLimits () ;

  // (2) _i と _di_dth を主回路のぶんと合計してみる
  double _trn_a = _pf -> getCurrent () ;
  double _trn_a_old = _trn_a ;
  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
  if ( _total_current > _max_regenerating_current )
  {
#ifdef DEBUG_TRN_ESS
    l_ofs << " _total (1) > _max_regen = " << _max_regenerating_current
          << endl ;
#endif

    // Set _pf -> __a and _pf -> __di
    _pf -> setCurrent ( _max_regenerating_current ) ;
    _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_regenerating_current ;
#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_RefSOC_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_accelerating_current )
  {
#ifdef DEBUG_TRN_ESS
    l_ofs << " _total (1) > _max_accel = " << _max_accelerating_current
          << endl ;
#endif

    // Set _pf -> __a and _pf -> __di
    _pf -> setCurrent ( - _max_accelerating_current ) ;
    _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_accelerating_current ;
#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_RefSOC_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 RefSOC, 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 RefSOC, 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_RefSOC_Controlled :: processESDMaximumLimits
()
{
#ifdef DEBUG_TRN_ESS
  l_ofs << "TRN_ESS: 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: 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: ess power = " << _p_ess << endl ;
#endif
  if ( _p_ess < _max_power_c )
  {
#ifdef DEBUG_TRN_ESS
    l_ofs << "TRN_ESS: 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: _i, _di_dth: " << _i << ", " << _di_dth << endl ;
#endif
  }
  else if ( _p_ess > _max_power_d )
  {
#ifdef DEBUG_TRN_ESS
    l_ofs << "TRN_ESS: 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: _i, _di_dth: " << _i << ", " << _di_dth << endl ;
#endif
  }
  else
  {
#ifdef DEBUG_TRN_ESS
    l_ofs << "TRN_ESS: no power capping necessary" << endl ;
#endif
  }
}



// -----
// Modify system state (voltage and current) after regen limiter.
// 回生絞込に対応した状態（電圧・電流）補正.
// -----
void
OBESS_RefSOC_Controlled :: processRegenerationLimiter
( train_ParamFunc * _pf )
{
  // (4) _pf -> __a < _pf -> __noshibo + _i であれば何かする。
#ifdef DEBUG_TRN_ESS
  l_ofs << "car " << _pf -> getCarNumber ()
        << ": OBESS RefSOC, 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_RefSOC_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_RefSOC_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_RefSOC_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: ORC::gEVC: " << cyc_devcur << ": vi, idev: "
        << _vi << " * " << _idev << " = " << _vi * _idev
        << ", f = " << f << endl ;
#endif
  bool _sw_chlim = true ;
  vector < pair < double , double > > _sol_history ;
  _sol_history . clear () ;
  bool _sw_newton = true ;
  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 ) ) ;
      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: ORC::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: ORC::gEVC: " << cyc_devcur << ": vi, idev: "
            << _vi << " * " << _idev << " = " << _vi * _idev
            << ", f = " << f << endl ;
#endif
    }
  }
}




// -----
// Renew the state of the ESS.
// システムの内部状態（SOCなど）の更新
// -----
void
OBESS_RefSOC_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_RefSOC_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_RefSOC_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_RefSOC_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_RefSOC_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 ;
}
