// This may look like C code, but it is really -*- C++ -*-
// RTSS --- Railway Total System Simulator
// (c) TAKAGI Ryo (at Kogakuin University)
// elecchar.cc --- class elecchar functions
// -----
// ChangeLog:
// 2008. 2. 2
//  Added ESS_Substation creator to elecchar::readfile_xml() function.
// 2008. 1. 18
//  Added elecchar::writeToCSV(), elecchar::writeHeaderToCSV() functions.
// 2008. 1. 17
//  Added variable elecchar::suppress_csv.
// 2007. 12. 5
//  Added teta_vi_core() and teta_vi_ESS() in class elecchar.
// 2007. 12. 4
//  Added elecchar::sub_ess.
// 2007. 11. 21
//  Redirected log messages to l_file.
// 2007. 11. 20
//  Added elecchar::scvits. Completed XML initialisation.
// 2007. 11. 16
//  New input function sschar::readxml_vichars(...) and
//  sschar::readxml_ratedcurrent(...) defined.
// 2007. 11. 8
//  New input function "elecchar::readfile_xml()" defined.
// -----


#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>

using std :: cerr ;
using std :: endl ;
using std :: string ;
using std :: stringstream ;


#ifdef SJIS_ICONV
#include "rtss_iconv.hh"
#endif
#include "elecchar.hh"
#include "rtss_path.hh"
#include "StrPrintf.hh"
#include "SuppressCSV.hh"

// リミットサイクル発見後は修正量を FAILSUB に制限 (変電所).
// Default = 1000.0
#define FAILSUB gc_ccalfail_failsub

//#define DEBUG
//#define DEBUG_ESS

//#define LOOSE_DV_DI	// crisp な dv, di の値を求めない

#define INVLIM 1e-5

// 電圧電流の計算
double avcal
(double sai, double saj, double tt, double sti, double stj) {
    return saj + ( sai - saj ) * ( tt - stj ) / ( sti - stj );
}


// -----
// From teta (parameter variable) to volt (voltage) and ampere (current).
// teta を volt, ampere へ.
// -----
void
elecchar :: teta_vi
()
{
  teta_vi_core () ;
  teta_vi_ESS () ;
}



// -----
// The core of teta_vi, doing main conversion from the parameter teta to
// volt, ampere, dv and di for the substation converters / inverters.
// teta_vi の中心部分。媒介変数 teta から volt, ampere, dv および di への
// 変換のうち変電所のコンバータ/インバータ部分についての変換を行う。
// -----
void
elecchar :: teta_vi_core
()
{
  // 変換する
  int subm = subc . size () - 1 ;

#ifdef DEBUG
  cerr << "submax = " << subc . number () << endl ;
#endif
  // tt の領域外への飛び出し禁止
  if ( tt < subc [ 0 ] . teta ) tt = subc [ 0 ] . teta ;
  if ( tt > subc [ subm ] . teta ) tt = subc [ subm ] . teta ;
  double xtt ;
  if ( tt + 100 > subc [ subm ] . teta )
  {
    xtt = tt - 100 ;
  }
  else
  {
    xtt = tt + 100 ;
  }
  // 電圧、電流の決定
  for ( int i = 1 ; i <= subm ; ++ i )
  {
    if ( ( tt < subc [ i ] . teta ) || i == subm )
    {
      SubstationControlData_VI scx ;
      if ( scvits )
      {
        // -----
        // Get subchar control value.
        // 制御用変数を取得.
        // -----
        while ( scvits -> timeIsAfterRegion ( t_sim ) )
        {
          scvits -> incrementCycle ( t_cyc ) ;
        }
        while ( scvits -> timeIsBeforeRegion ( t_sim ) )
        {
          scvits -> decrementCycle ( t_cyc ) ;
        }
        scx = scvits -> getData ( t_sim ) ;
      }
      int j = i - 1 ;
      double ampi = subc [ i ] . ampere ;
      double ampj = subc [ j ] . ampere ;
      if ( scvits )
      {
        ampi -= ( subc [ i ] . ampere - subc [ i ] . amplow )
          * ( 1.0 - scx . _i ) ;
        ampj -= ( subc [ j ] . ampere - subc [ j ] . amplow )
          * ( 1.0 - scx . _i ) ;
      }
      // これ以外の場合は何もする必要がない
      a = avcal
        ( ampi , ampj , tt , subc [ i ] . teta , subc [ j ] . teta ) ;
      double volti = subc [ i ] . volt ;
      double voltj = subc [ j ] . volt ;
      if ( g_sw_substn_ctl_a )
      {
        volti -= ( subc [ i ] . volt - subc [ i ] . voltlow )
          * ( 1.0 - subcntl ) ;
        voltj -= ( subc [ j ] . volt - subc [ j ] . voltlow )
          * ( 1.0 - subcntl ) ;
      }
      else if ( scvits )
      {
        volti -= ( subc [ i ] . volt - subc [ i ] . voltlow )
          * ( 1.0 - scx . _v ) ;
        voltj -= ( subc [ j ] . volt - subc [ j ] . voltlow )
          * ( 1.0 - scx . _v ) ;
      }
      // これ以外の場合は何もする必要がない
      v = avcal
        ( volti , voltj , tt , subc [ i ] . teta , subc [ j ] . teta ) ;
      di = ampi - ampj ;
      di /= subc [ i ] . teta - subc [ j ] . teta ;
      dv = volti - voltj ;
      dv /= subc [ i ] . teta - subc [ j ] . teta ;
      break ;
    }
  }
#ifdef LOOSE_DV_DI
  double xa , xv ;
  for ( int i = 1 ; i <= subm ; ++ i )
  {
    // 電圧、電流の決定
    if ( ( xtt < subc [ i ] . teta ) || i == subm )
    {
      int j = i - 1 ;
      xa = avcal ( subc [ i ] . ampere , subc [ j ] . ampere , xtt ,
                   subc [ i ] . teta , subc [ j ] . teta ) ;
      xv = avcal ( subc [ i ] . volt , subc [ j ] . volt , xtt ,
                   subc [ i ] . teta , subc [ j ] . teta ) ;
      di = ( a - xa ) / ( tt - xtt ) ;
      dv = ( v - xv ) / ( tt - xtt ) ;
      break ;
    }
  }
#endif /* LOOSE_DV_DI */
#ifdef DEBUG
  cerr << "sub: v, a, teta = "
       << std :: setiosflags ( std :: ios :: scientific )
       << std :: setprecision ( 1 ) << v
       << std :: setiosflags ( std :: ios :: scientific )
       << std :: setprecision ( 1 ) << a
       << std :: setiosflags ( std :: ios :: scientific )
       << std :: setprecision ( 2 ) << tt << endl ;
#endif
}


// -----
// Subprogram of teta_vi. ESS-related.
// teta_vi のサブプログラム。エネルギー蓄積装置がらみの仕事。
// -----
void
elecchar :: teta_vi_ESS
()
{
  // -----
  // We assume that the characteristics of the ESS is defined solely by the
  // bus voltage. This subroutine is therefore called after teta_vi_core(),
  // and it assumes that the voltage (variable volt) is already calculated.
  // エネルギー蓄積装置の特性は母線電圧のみにより規定されると仮定する。ゆえ
  // に，このサブルーチンは teta_vi_core() 関数の後で呼ばれ，電圧はすでに計
  // 算されているものとする。
  // -----
  a_conv = a ;
  di_conv = di ;
  // -----
  // NOTE::: ESS charge current is NEGATIVE. Therefore, we can simply add
  // ESS current to the substation current, which is positive when supplying
  // current to the DC feeding network.
  // 注意★★★エネルギー蓄積装置の充電電流は負となる。従って，蓄積装置の
  // 電流をここでは変電所電流（直流饋電系に電流供給（力行）しているときは
  // 正）に加えればよい。
  // -----
  sub_ess -> calculateVoltagesAndCurrents
    ( volt () , ampere () , dvi () , dii () ) ;
  a += sub_ess -> getCurrent () ;
  di += sub_ess -> getDeltaI () ;
#ifdef DEBUG_ESS
  l_ofs << "sub: teta, v, a, di, a_conv, di_conv = "
        << std :: setprecision ( 2 ) << tt << ", "
        << std :: setprecision ( 1 ) << v << ", "
        << std :: setprecision ( 1 ) << a << ", "
        << std :: setprecision ( 3 ) << di << ", "
        << std :: setprecision ( 1 ) << a_conv << ", "
        << std :: setprecision ( 3 ) << di_conv << endl ;
#endif
}



// Cc , Cl の計算
void
elecchar :: cccl
()
{
  if ( fabs ( a ) < INVLIM )
  {
    ccv = 10000.0 ;
    clv = 10000.0 ;
  }
  else
  {
    ccv = subc . ar * subc . isc / a ;
    clv = subc . ar * subc . isl / a ;
  }
#ifdef CVPRINT
  cerr << "SS No." << std :: setw ( 2 ) << csno << ": Is = "
       << std :: setw ( 7 ) << std :: setprecision ( 1 )
       << std :: setiosflags ( std :: ios :: scientific )
       << a << " [A], cc,cl=" << std :: setprecision ( 1 )
       << std :: setiosflags ( std :: ios :: scientific ) << cc () << " "
       << std :: setprecision ( 1 )
       << std :: setiosflags ( std :: ios :: scientific ) << cl () << endl ;
#endif
}


// メンバコピー
void
sschar :: membercopy
( const sschar & x )
{
  ar = x . ar ;			isl = x . isl ;
  isc = x . isc ;		ism = x . ism ;
  already_set = x . already_set ;
}


// X(X&)
sschar :: sschar
( const sschar & x )
  : vector < subchar > ( x )
{
  sschar :: membercopy ( x ) ;
}


// 代入のオーバーロード
sschar &
sschar :: operator=
( const sschar & x )
{
  if ( & x == this ) return * this ;
  vector < subchar > :: operator= ( x ) ;
  sschar :: membercopy ( x ) ;
  return * this ;
}


// ファイルリード
int
sschar :: readfile
( FILE * fl ,
  char * fls )
{
  getcommand ( fl , fls ) ;
  cmpcommand ( "subchar" , fls ) ;
  int max_subchar ;
  getint ( fl , fls , max_subchar ) ;
  l_ofs << StrPrintf ( "number of subchar data = %i" , max_subchar ) << endl ;
  reserve ( max_subchar ) ;		// ここで配列記憶領域確保
  for ( int i = 0 ; i < max_subchar ; ++ i )
  {
    subchar xsbc ;
    getthreedbls ( fl , fls , xsbc . teta , xsbc . volt , xsbc . ampere ) ;
    cerr << "subc[ " << i << " ] = " << std :: setprecision ( 3 )
         << std :: setiosflags ( std :: ios :: scientific )
         << xsbc . teta << " " << std :: setprecision ( 1 )
         << std :: setiosflags ( std :: ios :: scientific )
         << xsbc . volt << " " << std :: setprecision ( 1 )
         << std :: setiosflags ( std :: ios :: scientific )
         << xsbc . ampere << endl ;
    // -----
    // Assume two or more "control" scheme is "on" at the same time.
    // 同時に Aタイプとそれ以外が true にならないように配慮されている
    // ことを仮定して以下のルーチンを構成
    // -----
    if ( g_sw_substn_ctl_a )
    {
      // Aタイプ
      getcommand ( fl , fls ) ;
      cerr << " " << tmpch ;
      if ( cmpcommand ( "true" ) || cmpcommand ( "TRUE" )
           || cmpcommand ( "True" ) || cmpcommand ( "1" ) )
      {
//         xsbc . controlnext = true ;
        getdouble ( fl , fls , xsbc . voltlow ) ;
        cerr << " " << std :: setprecision ( 1 )
             << std :: setiosflags ( std :: ios :: scientific )
             << xsbc . voltlow ;
      }
      else if ( cmpcommand ( "false" ) || cmpcommand ( "FALSE" )
                || cmpcommand ( "False" ) || cmpcommand ( "0" ) )
      {
//         xsbc . controlnext = false ;
        xsbc . voltlow = xsbc . volt ;
      }
      else
      {
        cerr << endl ;
        err_eof ( fls ) ;
      }
    }
    else
    {
      // 制御しない
//       xsbc . controlnext = false ;
      xsbc . voltlow = xsbc . volt ;
    }
    cerr << endl ;

    // データを加える
    push_back ( xsbc ) ;
  }

  getcommand ( fl , fls ) ;
  cmpcommand ( "ratedcurrent" , fls ) ;
  gettwodbls ( fl , fls , ar , isl ) ;
  gettwodbls ( fl , fls , isc , ism ) ;
  cerr << "substation rated current: " << std :: setprecision ( 1 )
       << std :: setw ( 8 ) << std :: setiosflags ( std :: ios :: scientific )
       << ar << " A, " << std :: setprecision ( 2 )
       << std :: setw ( 5 ) << std :: setiosflags ( std :: ios :: scientific )
       << isl << " " << std :: setprecision ( 2 )
       << std :: setw ( 5 ) << std :: setiosflags ( std :: ios :: scientific )
       << isc << " " << std :: setprecision ( 2 )
       << std :: setw ( 5 ) << std :: setiosflags ( std :: ios :: scientific )
       << ism << " pu" << endl ;
  return 1 ;
}



// -----
// Reading XML file.
// XML形式のファイルリード。
// -----
int
elecchar :: readfile_xml
( const TiXmlNode * tn_in )
{
  // -----
  // The TiXmlNode argument here will be of tag "substation".
  // This tag must have, as an only attribute, its name. Also, as subdata,
  // "vichars", "ratedcurrent", "energy_storage" and "subchar_vi_file" tags
  // may appear ("vichars" tag must).
  // ここで与えられる TiXmlNode 型の引数は "substation" タグである。
  // このタグにおいては，属性の形で名前が指定される。また，子データとして
  // "vichars", "ratedcurrent", "energy_storage" および "subchar_vi_file"
  // タグが現れうる("vichars" タグは必ず現れる).
  // -----
  string tnin_val = string ( tn_in -> Value () ) ;
  if ( tnin_val != "substation" )
  {
    cerr << "Error: \"" << tnin_val
         << "\" tag given to function elecchar::readfile_xml(...)." << endl ;
    exit ( 1 ) ;
  }

  // -----
  // Get the name of the substation.
  // 変電所名を得る。
  // -----
  const TiXmlAttribute * attr = tn_in -> ToElement () -> FirstAttribute () ;
  while ( attr )
  {
    if ( string ( attr -> Name () ) == "name" )
    {
      // Attribute "name"
      name_utf8 = attr -> ValueStr () ;
#ifdef SJIS_ICONV
      // Enable this on Japanese Windows environment only
      iconv_t ixx = iconv_open ( "SHIFT_JIS" , "UTF-8" ) ;
      if ( ixx == ( iconv_t ) ( - 1 ) )
      {
        cerr << "ERROR: ICONV initialisation failed" << endl ;
        exit ( 1 ) ;
      }
      string :: size_type len = name_utf8 . length () ;
      char * buf_out = new char [ len + 1 ] ;
      convertFromUTF8ToSJIS ( name_utf8 . c_str () , buf_out , len ) ;
      name_sjis = string ( buf_out ) ;
      delete [] buf_out ;
#else
      name_sjis = name_utf8 ;
#endif // SJIS_ICONV
      l_ofs << "Substation name: " << name_sjis << endl ;
    }
    else
    {
      cerr << "ERROR: tag <departingtrain> with incorrect attribute "
           << attr -> Name () << endl ;
      exit ( 1 ) ;
    }
    attr = attr -> Next () ;
  }

  // -----
  // Process subdata.
  // 子データを処理する。
  // -----
  bool sw_vichars = true ;

  for ( const TiXmlNode * tn_ch = tn_in -> FirstChild () ;
        tn_ch ; tn_ch = tn_ch -> NextSibling () )
  {
    // -----
    // Ignore non-Element node.
    // エレメント以外は無視。
    // -----
    if ( tn_ch -> Type () != TiXmlNode :: TINYXML_ELEMENT )
      continue ;
    // -----
    // Check tag name.
    // タグ名チェック。
    // -----
    string tnch_val = string ( tn_ch -> Value () ) ;
    if ( tnch_val == "vichars" )
    {
      if ( ! sw_vichars )
      {
        cerr << "ERROR: multiple <vichars> tags in tag <substation>"
             << endl ;
        exit ( 1 ) ;
      }

      // -----
      // Processing <vichars> tag. If the "vichars" tag has the attribute
      // "suppress_csv" set to "true", then the suppress_csv flag (bool
      // variable) will be set.
      // <vichars> タグを処理. もし，このタグに "suppress_csv" 属性があり
      // "true" にセットされていれば，suppress_csv フラグ (bool 変数) を
      // セットする。
      // -----
      suppress_csv = findSuppressCSV ( tn_ch ) ;
      if ( subc . readxml_vichars ( tn_ch ) )
      {
        cerr << "ERROR: error in parsing tag <" << tnch_val << ">" << endl ;
        exit ( 1 ) ;
      }
      sw_vichars = false ;
    }
    else if ( tnch_val == "ratedcurrent" )
    {
      // -----
      // Processing <ratredcurrent> tag.
      // <ratredcurrent> タグを処理.
      // -----
      if ( ! subc . readxml_ratedcurrent ( tn_ch ) )
      {
        cerr << "ERROR: error in parsing tag <" << tnch_val << ">" << endl ;
        exit ( 2 ) ;
      }
    }
    else if ( tnch_val == "energystorage" )
    {
      // -----
      // Processing <energystorage> tag.
      // <energystorage> タグを処理.
      // -----
      bool sw_gc = true ;
      for ( const TiXmlNode * tn_gc = tn_ch -> FirstChild () ;
            tn_gc ; tn_gc = tn_gc -> NextSibling () )
      {
        // -----
        // Ignore non-Element node.
        // エレメント以外は無視。
        // -----
        if ( tn_gc -> Type () != TiXmlNode :: TINYXML_ELEMENT )
          continue ;
        // -----
        // First element will be used to create a ESS_Substation object.
        // Because the default constructor assigns an No_ESS_Substation
        // class instance to sub_ess, it must be destructed first.
        // 最初のエレメントで ESS_Substation オブジェクトをつくる。デフォルト
        // コンストラクタが sub_ess に No_ESS_Substation クラスのインスタンス
        // を割り当ててしまっているため，これをまず破壊する必要がある。
        // -----
        delete sub_ess ;
        sub_ess = ESS_Expander :: create ( tn_gc -> Value () , tn_gc ) ;
        sw_gc = false ;
      }
      if ( sw_gc )
      {
        cerr << "ERROR: error in parsing tag <" << tnch_val << ">" << endl ;
        exit ( 3 ) ;
      }
    }
    else if ( tnch_val == "subchar_vi_file" )
    {
      // -----
      // Processing <subchar_vi_file> tag.
      // <subchar_vi_file> タグを処理.
      // -----
      if ( scvits )
      {
        // -----
        // Error: scvits already defined
        // エラー: scvits already defined
        // -----
        cerr << "ERROR: <subchar_vi_file> tag specified more than once"
             << endl ;
        exit ( 1 ) ;
      }
      if ( g_sw_substn_ctl_a )
      {
        // -----
        // Error: unsafe to specify subchar_vi_file with Substation Control
        // type A flag
        // エラー: 変電所リアルタイム制御タイプAフラグと subchar_vi_file を
        // 共存させるのは安全ではない
        // -----
        cerr << "ERROR: <subchar_vi_file> tag specified when substation "
             << "real-time control type A is turned on" << endl ;
        exit ( 1 ) ;
      }
      // -----
      // Getting file name.
      // ファイル名を取得.
      // -----
      const TiXmlAttribute * atvi
        = tn_ch -> ToElement () -> FirstAttribute () ;
      while ( atvi )
      {
        if ( string ( atvi -> Name () ) != "name" )
        {
          cerr << "ERROR: tag <subchar_vi_file> with incorrect attribute \""
               << atvi -> Name () << "\"" << endl ;
          exit ( 1 ) ;
        }
        RTSS_Path_String vifn ( atvi -> Value () ) ;
        cerr << "subchar_vi vifn: " << vifn << endl ;
        string vi_drive = "" ;
        string vi_dir = "" ;
        string vi_file = "" ;
        if ( ! vifn . processPath ( is_backslash , s_drive_str , s_dir_str ,
                                    vi_drive , vi_dir , vi_file ) )
        {
          cerr << "ERROR: unknown error in processPath at elecchar.cc"
               << endl ;
          exit ( 1 ) ;
        }
        string vi_copy_filename = vi_drive ;
        vi_copy_filename += vi_dir ;
        if ( is_backslash )
        {
          vi_copy_filename += "\\" ;
        }
        else
        {
          vi_copy_filename += "/" ;
        }
        vi_copy_filename += vi_file ;
        cerr << "subchar_vi filename: " << vi_copy_filename << endl ;

        // -----
        // Constructing the object.
        // オブジェクトを構成.
        // -----
        scvits
          = new Substation_Control_VI_TS ( vi_copy_filename . c_str () ) ;
        atvi = atvi -> Next () ;
      }
    }
    else
    {
      cerr << "Error: \"" << tnch_val << "\" tag not allowed." << endl ;
      exit ( 1 ) ;
    }
  }
  if ( sw_vichars )
  {
    cerr << "ERROR: tag <vichars> missing in tag <substation>" << endl ;
    exit ( 1 ) ;
  }
  cerr << "Substation " << name_sjis << " read all done" << endl ;
}



// -----
// Interpreting "vichars" tag in an XML file.
// XML 形式ファイル中の "vichars" タグを解釈する。
// -----
int
sschar :: readxml_vichars
( const TiXmlNode * tn_in )
{
  // -----
  // Node check.
  // ノードチェック.
  // -----
  string tnin_val = string ( tn_in -> Value () ) ;
  if ( tnin_val != "vichars" )
  {
    cerr << "Error: TiXmlNode with value \"vichars\" "
         << "must be fed to function int sschar::readxml_vichars(...)"
         << endl ;
    exit ( 1 ) ;
  }

  // -----
  // No attributes will be checked if any. Only children of tag "vichar"
  // is to be present.
  // 属性はないことになっているのでチェックしない。"vichar" タグの子データ
  // のみがあることになっている。
  // -----
  for ( const TiXmlNode * tn_ch = tn_in -> FirstChild () ;
        tn_ch ; tn_ch = tn_ch -> NextSibling () )
  {
    // -----
    // Ignore non-Element node.
    // エレメント以外は無視。
    // -----
    if ( tn_ch -> Type () != TiXmlNode :: TINYXML_ELEMENT )
      continue ;
    // -----
    // Check tag name.
    // タグ名チェック。
    // -----
    string tnch_val = string ( tn_ch -> Value () ) ;
    if ( tnch_val == "vichar" )
    {
      // -----
      // Processing <vichar> tag.
      // <vichar> タグを処理.
      // -----
      subchar * subc_xp = new subchar ( tn_ch ) ;
      push_back ( * subc_xp ) ;
      delete subc_xp ;
    }
    else
    {
      cerr << "Error: \"" << tnch_val << "\" tag not allowed." << endl ;
      exit ( 1 ) ;
    }
  }
  return 0 ;
}



// -----
// Interpreting "ratedcurrent" tag in an XML file.
// XML 形式ファイル中の "ratedcurrent" タグを解釈する。
// -----
int
sschar :: readxml_ratedcurrent
( const TiXmlNode * tn_in )
{
  // -----
  // Node check.
  // ノードチェック.
  // -----
  string tnin_val = string ( tn_in -> Value () ) ;
  if ( tnin_val != "ratedcurrent" )
  {
    l_ofs << "Error: TiXmlNode with value \"ratedcurrent\" "
          << "must be fed to function int sschar::readxml_ratedcurrent(...)"
          << endl ;
    cerr << "Error: TiXmlNode with value \"ratedcurrent\" "
         << "must be fed to function int sschar::readxml_ratedcurrent(...)"
         << endl ;
    exit ( 1 ) ;
  }

  // -----
  // No subdata will be checked if any.
  // 子データはないことになっているのでチェックしない。
  // -----
  for ( const TiXmlAttribute * attr
          = tn_in -> ToElement () -> FirstAttribute () ; attr ;
        attr = attr -> Next () )
  {
    if ( string ( attr -> Name () ) == "value" )
    {
      // Attribute "value"
      sscanf ( attr -> Value () , "%lf" , & ar ) ;
      l_ofs << " rated current = " << ar << endl ;
    }
    else if ( string ( attr -> Name () ) == "low" )
    {
      // Attribute "low"
      sscanf ( attr -> Value () , "%lf" , & isl ) ;
      l_ofs << " low current: pu < " << isl << endl ;
    }
    else if ( string ( attr -> Name () ) == "high" )
    {
      // Attribute "high"
      sscanf ( attr -> Value () , "%lf" , & isc ) ;
      l_ofs << " high current: pu >= " << isc << endl ;
    }
    else if ( string ( attr -> Name () ) == "voltage_z" )
    {
      // Attribute "max"
      sscanf ( attr -> Value () , "%lf" , & ism ) ;
      l_ofs << " max current: pu = " << ism << endl ;
    }
    else
    {
      l_ofs << "ERROR: tag <ratedcurrent> with incorrect attribute "
            << attr -> Name () << endl ;
      cerr << "ERROR: tag <ratedcurrent> with incorrect attribute "
           << attr -> Name () << endl ;
      exit ( 1 ) ;
    }
  }
}



// コンストラクタ
ssfeedconnect :: ssfeedconnect
()
{
  nfline = csno = 0 ;
  pos = sttpower [ 0 ] = sttpower [ 1 ] = endpower [ 0 ] = endpower [ 1 ]
    = 0.0 ;
  sttcurr = sttenrgy = sttpeak = sttnpeak = 0.0 ;
  endcurr = endenrgy = endpeak = endnpeak = 0.0 ;
}



// メンバコピー
void
ssfeedconnect :: membercopy
( ssfeedconnect const & x )
{
  nfline = x . nfline ;
  csno = x . csno ;
  pos = x . pos ;
  sttcurr = x . sttcurr ;
  endcurr = x . endcurr ;
  for ( int i = 0 ; i < 2 ; ++ i )
  {
    sttpower [ i ] = x . sttpower [ i ] ;
    endpower [ i ] = x . endpower [ i ] ;
  }
  sttenrgy = x . sttenrgy ;
  endenrgy = x . endenrgy ;
  sttpeak = x . sttpeak ;
  endpeak = x . endpeak ;
  sttnpeak = x . sttnpeak ;
  endnpeak = x . endnpeak ;
}



// X(X&)
ssfeedconnect :: ssfeedconnect
( ssfeedconnect const & x )
{
  membercopy ( x ) ;
}



// 代入演算子
ssfeedconnect &
ssfeedconnect :: operator=
( ssfeedconnect const & x )
{
  if ( & x == this ) return * this ;
  membercopy ( x ) ;
  return * this ;
}



// 型変換
ssfeedconnect :: ssfeedconnect
( feedpos const & x )
{
  nfline = x . nfline ;
  csno = x . csno ;
  pos = x . pos ;
  sttpower [ 0 ] = sttpower [ 1 ] = endpower [ 0 ] = endpower [ 1 ] = 0.0 ;
  sttcurr = sttenrgy = sttpeak = sttnpeak = 0.0 ;
  endcurr = endenrgy = endpeak = endnpeak = 0.0 ;
}



// 代入
ssfeedconnect &
ssfeedconnect :: operator=
( feedpos const & x )
{
  nfline = x . nfline ;
  csno = x . csno ;		// 初期化はされているので不要！
  pos = x . pos ;
  return * this ;
}



// -----
// Default constructor
// デフォルトコンストラクタ
// -----
elecchar :: elecchar
()
{
  enrgy = renrgy = tt = v = amx = amy = a = a_conv = dv = di = di_conv = 0.0 ;
  pwr [ 0 ] = pwr [ 1 ] = rpwr [ 0 ] = rpwr [ 1 ] = 0.0 ;
  sw_voltpeak = true ;
  subcntl = 1.0 ;	// default = 1.0 でないと困るだろうな
  scvits = 0 ;
  sub_ess = new No_ESS_Substation ;
}



// -----
// X(X&)
// -----
elecchar :: elecchar
( const elecchar & x )
  : subc ( x . subc ) ,
    ssfeedcon ( x . ssfeedcon )
{
  membercopy ( x ) ;
}



// -----
// Substitution operator.
// 代入演算子.
// -----
elecchar &
elecchar :: operator=
( const elecchar & x )
{
  if ( & x == this ) return * this ;
  membercopy ( x ) ;
  subc = x . subc ;
  ssfeedcon = x . ssfeedcon ;
  return * this ;
}



void
elecchar :: membercopy
( const elecchar & x )
{
  ccv = x . ccv ;		clv = x . clv ;
  mode = x . mode ;		tt = x . tt ;
  v = x . v ;			a = x . a ;
  aax = x . aax ;		v_old = x . v_old ;
  a_old = x . a_old ;		tt_old = x . tt_old ;
  dv = x . dv ;			di = x . di ;
  diax = x . diax ;		cmd_main = x . cmd_main ;
  amx = x . amx ;		amy = x . amy ;
  ccmd = x . ccmd ;		csno = x . csno ;
  voltpeak = x . voltpeak ;
  voltbottom = x . voltbottom ;
  sw_voltpeak = x . sw_voltpeak ;
  subcntl = x . subcntl ;

  // -----
  // Copying scvits.
  // scvits ポインタのコピー処理
  // -----
  Substation_Control_VI_TS * scvits_tmp = scvits ;
  if ( x . scvits )
  {
    scvits = new Substation_Control_VI_TS ( * x . scvits ) ;
    if ( scvits_tmp )
    {
      delete scvits_tmp ;
    }
  }
  else
  {
    // -----
    // x.scvits is 0 (null pointer).
    // x.scvits はナル(NULL)ポインタ 
    // -----
    if ( scvits )
    {
      delete scvits ;
    }
    scvits = 0 ;
  }

  // -----
  // Copying sub_ess.
  // sub_ess ポインタのコピー処理
  // -----
  ESS_Substation * sub_ess_tmp = sub_ess ;
  if ( x . sub_ess )
  {
    sub_ess = x . sub_ess -> getMyClone () ;
    if ( sub_ess_tmp )
    {
      delete sub_ess_tmp ;
    }
  }
  else
  {
    // -----
    // x.sub_ess is 0 (null pointer). Error.
    // x.sub_ess はナル(NULL)ポインタ: エラー.
    // -----
    cerr << "Error: elecchar::sub_ess must not be null." << endl ;
    exit ( 1 ) ;
  }
}



// ブランチ電流を受信
void
elecchar :: directional_curr_start
( int xfline ,
  double xpos ,
  double brcurr )
{
  bool sw_x = false ;
  for ( int i = 0 ; i < ssfeedcon . number () ; ++ i )
  {
    if ( ssfeedcon [ i ] . nfline == xfline && ssfeedcon [ i ] . pos == xpos )
    {
      ssfeedcon [ i ] . sttcurr = brcurr ;
      // ピーク電流をセット
      if ( ssfeedcon [ i ] . sttcurr > ssfeedcon [ i ] . sttpeak )
      {
        ssfeedcon [ i ] . sttpeak = ssfeedcon [ i ] . sttcurr ;
      }
      if ( - ssfeedcon [ i ] . sttcurr > ssfeedcon [ i ] . sttnpeak )
      {
        ssfeedcon [ i ] . sttnpeak = - ssfeedcon [ i ] . sttcurr ;
      }
      sw_x = true ;
      break ;
    }
  }
  if ( ! sw_x ) {
    l_ofs << "Serious Warning: No identical feedline found "
          << "in directional_curr_start" << endl ;
    cerr << "Serious Warning: No identical feedline found "
         << "in directional_curr_start" << endl ;
  }
}


// ブランチ電流を受信
void
elecchar :: directional_curr_end
( int xfline ,
  double xpos ,
  double brcurr )
{
  bool sw_x = false ;
  for ( int i = 0 ; i < ssfeedcon .number () ; ++ i )
  {
    if ( ssfeedcon [ i ] . nfline == xfline && ssfeedcon [ i ] . pos == xpos )
    {
      ssfeedcon [ i ] . endcurr = - brcurr ;	// 流れ込むからマイナス
      // ピーク電流をセット
      if ( ssfeedcon [ i ] . endcurr > ssfeedcon [ i ] . endpeak )
      {
        ssfeedcon [ i ] . endpeak = ssfeedcon [ i ] . endcurr ;
      }
      if ( - ssfeedcon [ i ] . endcurr > ssfeedcon [ i ] . endnpeak )
      {
        ssfeedcon [ i ] . endnpeak = - ssfeedcon [ i ] . endcurr ;
      }
      sw_x = true ;
      break ;
    }
  }
  if ( ! sw_x ) {
    l_ofs << "Serious Warning: No identical feedline found "
          << "in directional_curr_end" << endl ;
    cerr << "Serious Warning: No identical feedline found "
         << "in directional_curr_end" << endl ;
  }
}

// ピーク電流・電圧値のセット
void elecchar::setpeak
() {
    if (amx < a) amx = a;
    if (amy > a) amy = a;
    if (sw_voltpeak) {
	voltpeak = voltbottom = v;
	sw_voltpeak = false;
    } else {
	if (voltpeak < v) voltpeak = v;
	if (voltbottom > v) voltbottom = v;
    }
}



// subcntl セット
void
elecchar :: setsubcntl
( double x )
{
  subcntl = x ;
  if ( subcntl > 1.0 || subcntl < 0.0 )
  {
    cerr << "Error: illegal value for subcntl" << endl ;
    exit ( 17 ) ;
  }
}



// subcntl セット
void
elecchar :: addtosubcntl
( double x )
{
  subcntl += x ;
  if ( subcntl > 1.0 )
    subcntl = 1.0 ;
  if ( subcntl < 0.0 )
    subcntl = 0.0 ;
}


// teta に加える
void
elecchar :: add_to_teta
( double tx ,
  bool sw_fail )
{
  if ( sw_fail )
  {
    if ( tx > FAILSUB ) tx = FAILSUB ;
    if ( tx < - FAILSUB ) tx = - FAILSUB ;
  }
  tt += tx ;
}



// -----
// Default constructor
// デフォルトコンストラクタ
// -----
subchar :: subchar
()
{
  teta = volt = ampere = 0 ;
  voltlow = amplow = 0 ;
}



// -----
// XML DOM node constructor
// XML の DOM ノードによるコンストラクタ
// -----
subchar :: subchar
( const TiXmlNode * tn_in )
{
  // -----
  // Node check.
  // ノードチェック.
  // -----
  string tnin_val = string ( tn_in -> Value () ) ;
  if ( tnin_val != "vichar" )
  {
    cerr << "Error: TiXmlNode with value \"vichar\" "
         << "must be fed to function int subchar::subchar(...)"
         << endl ;
    exit ( 1 ) ;
  }

  // -----
  // No subdata will be checked if any.
  // 子データはないことになっているのでチェックしない。
  // -----
  bool sw_v , sw_i , sw_t , sw_vz , sw_iz ;
  sw_v = sw_i = sw_t = sw_vz = sw_iz = true ;
  const TiXmlAttribute * attr = tn_in -> ToElement () -> FirstAttribute () ;
  while ( attr )
  {
    if ( string ( attr -> Name () ) == "voltage" )
    {
      // Attribute "voltage"
      sscanf ( attr -> Value () , "%lf" , & volt ) ;
      l_ofs << " subchar volt = " << volt << endl ;
      sw_v = false ;
    }
    else if ( string ( attr -> Name () ) == "current" )
    {
      // Attribute "current"
      sscanf ( attr -> Value () , "%lf" , & ampere ) ;
      l_ofs << " subchar ampere = " << ampere << endl ;
      sw_i = false ;
    }
    else if ( string ( attr -> Name () ) == "parameter" )
    {
      // Attribute "parameter"
      sscanf ( attr -> Value () , "%lf" , & teta ) ;
      l_ofs << " subchar teta = " << teta << endl ;
      sw_t = false ;
    }
    else if ( string ( attr -> Name () ) == "voltage_z" )
    {
      // Attribute "voltage_z"
      sscanf ( attr -> Value () , "%lf" , & voltlow ) ;
      l_ofs << " subchar voltlow = " << voltlow << endl ;
      sw_vz = false ;
    }
    else if ( string ( attr -> Name () ) == "current_z" )
    {
      // Attribute "current_z"
      sscanf ( attr -> Value () , "%lf" , & amplow ) ;
      l_ofs << " subchar amplow = " << amplow << endl ;
      sw_iz = false ;
    }
    else
    {
      cerr << "ERROR: tag <departingtrain> with incorrect attribute "
           << attr -> Name () << endl ;
      l_ofs << "ERROR: tag <departingtrain> with incorrect attribute "
            << attr -> Name () << endl ;
      exit ( 1 ) ;
    }
    attr = attr -> Next () ;
  }
  if ( sw_v || sw_i || sw_t )
  {
    cerr  << "Error: data missing in tag <vichar>" << endl ;
    l_ofs << "Error: data missing in tag <vichar>" << endl ;
    exit ( 1 ) ;
  }
  if ( sw_vz )
  {
    voltlow = volt ;
  }
  if ( sw_iz )
  {
    amplow = ampere ;
  }
}



// -----
// Output "header" to CSV file.
// Boolean argument: suppress leading comma if false.
// CSVファイルへの「ヘッダ」の出力.
// 論理値引数: 偽ならカンマの出力を抑制.
// -----
bool
elecchar :: writeHeaderToCSV
( ostream & x_out ,
  bool sw_cm /* = true */ )
  const
{
  if ( ! getSuppressCSVFlag () )
  {
    string __quot = g_sw_csv_without_quotation ? "" : "\"" ;
    if ( sw_cm )
    {
      x_out << "," ;
    }
    x_out << __quot << "SUB " << csno << " V" << __quot << "," << __quot
          << "SUB " << csno << " I" << __quot ;
    stringstream h_ss_csv ;
    h_ss_csv << "SUB " << csno << " ESS" ;
    string h_csv = h_ss_csv . str () ;
    sub_ess -> writeHeaderToCSV ( x_out , true , h_csv ) ;
    if ( g_sw_ss_direction )
    {
      // Substation Directional Current Headers
      for ( int j = 0 ; j < feedcon () . number () ; ++ j )
      {
        int i_fln = feedcon () [ j ] . nfline ;
        double __pos_c = feedcon () [ j ] . pos ;
        x_out << "," << __quot << "SUB " << csno << " FLN " << i_fln
              << " " << __pos_c << " STT" << __quot << "," << __quot
              << "SUB " << csno << " FLN " << i_fln << " " << __pos_c
              << " END" << __quot ;
      }
    }
  }
  return true ;
}



// -----
// Output to CSV file. Boolean argument: suppress leading comma if false.
// CSVファイルへの出力. 論理値引数: 偽ならカンマの出力を抑制.
// -----
bool
elecchar :: writeToCSV
( ostream & x_out ,
  bool sw_cm /* = true */ )
  const
{
  if ( ! getSuppressCSVFlag () )
  {
    string __quot = g_sw_csv_without_quotation ? "" : "\"" ;
    if ( sw_cm )
    {
      x_out << "," ;
    }
    x_out << __quot << volt () << __quot << ","
          << __quot << ampere () << __quot ;
    sub_ess -> writeToCSV ( x_out , true ) ;
    if ( g_sw_ss_direction )
    {
      // Substation Directional Current values
      for ( int j = 0 ; j < feedcon () . number () ; ++ j )
      {
        x_out << "," << __quot << feedcon () [ j ] . sttcurr << __quot
              << "," << __quot << feedcon () [ j ] . endcurr << __quot ;
      }
    }
  }
  return true ;
}



// -----
// Renew the electrical state variables.
// 電気的状態変数を更新。
// -----
void
elecchar :: renewElectricalStates
()
{
  sub_ess -> renewElectricalStates ( volt () , ampere () ) ;
}



// -----
// Calculate voltage and current of the ESS.
// -----
void
elecchar :: calculateESDVoltageAndCurrent
()
{
  sub_ess -> calculateESDVoltageAndCurrent ( volt () , ampere () ) ;
}
