// This may look like C code, but it is really -*- C++ -*-
// RTSS --- Railway Total System Simulator
// (c) TAKAGI Ryo (at Kogakuin University)
// train.cc --- class train functions
// -----
// ChangeLog:
// 2010. 1. 19
//  Removed sw_dtracf member variable.
// 2009. 11. 26
//  Added train::trn_ess member variable.
// 2008. 1. 18
//  Added train::writeToCSV(), train::writeHeaderToCSV() functions.
// 2007. 11. 22
//  Redirected log messages to l_file.
// -----

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <sstream>

#include "train.hh"
#include "StrPrintf.hh"
#include "EnergyStorage.hh"

#define INVLIM 1e-5

//#define DEBUG
//#define CVPRINT	// V1, V2 の値を吐き出す

#define NO_JERK

#define MINCL	10.0


using std :: stringstream ;



train :: train
( string const * x )
  : train_type_key ( x ) ,
    trn_ess ( 0 )
{
  suppress_csv = false ;
  sw_btws = sw_regendead = is_limiting_regen = false ;
  is_limiting_max_curr = false ;
  sw_x_btws = true ;
  _sw_mech_power = false ;
  _mech_power = 0 ;
  _mech_power_motor_ratio = 0 ;
  nxx = 0 ;
  rnotch = 0 ;
  a_wo_capper = 0 ;
  a_main_circuit = 0 ;
  rnotch_for_capper = 1 ;
  zerovolt = 0 ;
  auxcurr = 0 ;
  sw_aux_power = false ;
  sw_torque_shibori = false ;
  sw_shibori_parallel = false ;
  sw_regenoffantei = false ;
  sw_anteimotor = false ;
  stpos = 0.0 ;
  cpsw = cpsww = false ;
  b_jerk = false ;
}


// X(X&)
train :: train
( train const & x )
{
// まずは単独メンバのコピーから
  a_wo_capper = x . a_wo_capper ;
  a_main_circuit = x . a_main_circuit ;
  rnotch_for_capper = x . rnotch_for_capper ;
  train_type_key = x . train_type_key ;
  trn_ess = x . trn_ess -> getMyClone () ;
  suppress_csv = x . suppress_csv ;
  _sw_mech_power = x . _sw_mech_power ;
  _mech_power = x . _mech_power ;
  _mech_power_motor_ratio = x . _mech_power_motor_ratio ;
  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;	dv = x.dv;	di = x.di;
    diax = x.diax;	cmd_main = x.cmd_main;	amx = x.amx;
    ccmd = x.ccmd;	csno = x.csno;
    membercopy(x);
    abh = x.abh;	setnum = x.setnum;	conges = x.conges;
    dtracf = x.dtracf;
    sw_regendead = x.sw_regendead;
    is_limiting_regen = x . is_limiting_regen ;
    is_limiting_max_curr = x . is_limiting_max_curr ;
    zerovolt = x.zerovolt;
    auxcurr = x . auxcurr ;	sw_aux_power = x . sw_aux_power ;
    ontprec = x.ontprec;
    cpsww = x.cpsww;	cpsw = x.cpsw;	/* emccal = x.emccal; */
    lenrun = x.lenrun;	stpos = x.stpos;	b_jerk = x.b_jerk;
    ssno = x.ssno;	sis = x.sis;	nosss = x.nosss;
    iss = x.iss;	seno = x.seno;	sie = x.sie;
    nosse = x.nosse;	ise = x.ise;	carno = x.carno;
    pdata = x.pdata;	bdata = x.bdata;	adata = x.adata;
    pos = x.pos;	vel = x.vel;	stat = x.stat;
    stat_old = x.stat_old;	tdept = x.tdept;	taudx = x.taudx;
    cmd_aux = x.cmd_aux;	rnotch = x.rnotch;	dnch = x.dnch;
    rnotchold = x.rnotchold;	pgrad = x.pgrad;	noshibo = x.noshibo;
    brakev = x.brakev;	iamconst = x.iamconst;
    sw_torque_shibori = x . sw_torque_shibori ;
    sw_shibori_parallel = x . sw_shibori_parallel ;
    sw_regenoffantei = x . sw_regenoffantei ;
    sw_anteimotor = x . sw_anteimotor ;
    
// 配列データの初期化
    nss = x.nss;
    if (nss > 0) {
	delete sc;
	sc = new sschar[ nss ];
	for (register int i = 0; i < nss; i++)
	    sc[i] = x.sc[i];
    }
    nxx = x.nxx;	// 次駅データは配列ではなくポインタを渡してある
}



// 代入
train &
train :: operator=
( train & x )
{
  if ( & x == this ) return * this ;

  // 単独メンバのコピー
  a_wo_capper = x . a_wo_capper ;
  a_main_circuit = x . a_main_circuit ;
  rnotch_for_capper = x . rnotch_for_capper ;
  train_type_key = x . train_type_key ;
  trn_ess = x . trn_ess -> getMyClone () ;
  suppress_csv = x . suppress_csv ;
  _sw_mech_power = x . _sw_mech_power ;
  _mech_power = x . _mech_power ;
  _mech_power_motor_ratio = x . _mech_power_motor_ratio ;
    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;	dv = x.dv;	di = x.di;
    diax = x.diax;	cmd_main = x.cmd_main;	amx = x.amx;
    ccmd = x.ccmd;	csno = x.csno;
    membercopy(x);
    abh = x.abh;	setnum = x.setnum;	conges = x.conges;
    dtracf = x.dtracf;
    sw_regendead = x.sw_regendead;
    is_limiting_regen = x . is_limiting_regen ;
    is_limiting_max_curr = x . is_limiting_max_curr ;
    zerovolt = x.zerovolt;
    auxcurr = x . auxcurr ;	sw_aux_power = x . sw_aux_power ;
    ontprec = x.ontprec;
    cpsww = x.cpsww;	cpsw = x.cpsw;	/* emccal = x.emccal; */
    lenrun = x.lenrun;	stpos = x.stpos;	b_jerk = x.b_jerk;
    ssno = x.ssno;	sis = x.sis;	nosss = x.nosss;
    iss = x.iss;	seno = x.seno;	sie = x.sie;
    nosse = x.nosse;	ise = x.ise;	carno = x.carno;
    pdata = x.pdata;	bdata = x.bdata;	adata = x.adata;
    pos = x.pos;	vel = x.vel;	stat = x.stat;
    stat_old = x.stat_old;	tdept = x.tdept;	taudx = x.taudx;
    cmd_aux = x.cmd_aux;	rnotch = x.rnotch;	dnch = x.dnch;
    rnotchold = x.rnotchold;	pgrad = x.pgrad;	noshibo = x.noshibo;
    brakev = x.brakev;	iamconst = x.iamconst;
    sw_torque_shibori = x . sw_torque_shibori ;
    sw_shibori_parallel = x . sw_shibori_parallel ;
    sw_regenoffantei = x . sw_regenoffantei ;
    sw_anteimotor = x . sw_anteimotor ;
// 配列データのコピー
    nss = x.nss;
    if (nss > 0) {
	delete sc;
	sc = new sschar[ nss ];
	for (register int i = 0; i < nss; i++)
	    sc[i] = x.sc[i];
    }
    nxx = x.nxx;	// 次駅データは配列ではなくポインタを渡してある
    return *this;
}

train::~train() {	// destructor
    nxx = 0;
    delete sc;
}

// nxx のセット
void
train :: setNextstaPointer
( nextsta const * nx )
{
  nxx = nx ;
  if ( g_sw_conges_station )
  {
    // true: nextsta object から conges の値を吸い出す
    setconges ( nxx -> congestion () ) ;
  }
  pgrad = nxx -> dpgrad ( pos ) ;
  ontprec = nxx -> get_ontprec () ;	// ontprec を吸い出す
}



// nxx のセット for disttrain
void
train :: setNextstaPointer_for_disttrain
( nextsta const * nx ) {
  setNextstaPointer ( nx ) ;
  if ( g_sw_station_object_valid )
  {
    stnobj_now = nxx -> stnobj () ;	// セットしておく
  }
}


// teta_vi, delta_dvi のためのデータのセット
void train::setpbdata(powerdata p, brakedata b, autodata c) {
    pdata = p; bdata = b; adata = c;
}

// autodata の自動修正
void train::autodreg() {
    double clx, vcl, ccx, vcc;
    if ( ccommand() != Ea_cvauto0 ) return;	// Ea_cvauto0 のみ対象
    double& pm = adata.pminvol;
    double& po = adata.poffvol;			// 参照を定義
    double rnch, dc;
    nr_power(rnch, dc);				// rnotch 計算
    double ar = pm - po;			// pm,po 差は一定に
    double pmx = pm;
    double pox = po;				// pm, po の古い値の保存
    po = v; pm = po + ar;			// v = po のときの
    double rna, rnb;
    nr_power(rna, dc);				// rnotch -> rna
    pm = v; po = pm - ar;			// v = pm のときの
    nr_power(rnb, dc);				// rnotch -> rnb
    if ( cl() > 1.0 ) goto CL;
    if ( cc() < 1.0 ) goto CC;			// 分岐指令
    
  CL:	// 電流増加モード
    if ( fabs(rnch - 1.0) < INVLIM ) {		// r = 1 ならば何もしない
	pm = pmx; po = pox; goto RR;
    }
    clx = rnch * cl();				// rnotch の目標
    if ( clx > 1.0 ) clx = 1.0;			// clx は最大 1
    if ( clx < INVLIM ) clx = cl() / MINCL;	// 最小 cl/MINCL
    if (rna > clx) {				// rna > clx なら
	po = v; pm = po + ar;			// po = v または
	if (po > pox) {po = pox; pm = pmx;}	// 動かさない
	goto RR;
    }
    if ( rnb - rna < INVLIM || clx >= rnb ) {	// rnb == rna なら
	pm = v; po = pm - ar;			// pm = v または
	if (pm > pmx) {po = pox; pm = pmx;}	// 動かさないこともある
	goto RR;
    }
    vcl = ( clx - rna) / ( rnb - rna ) * ar;	// po = v - vclとなるように
    po = v - vcl;				// po, pm を決める
    pm = po + ar;
    if (pm > pmx) {po = pox; pm = pmx;}		// 動かさないこともある
    goto RR;
    
  CC:	// 電流減少モード
    if ( fabs(rnch) < INVLIM ) {		// r = 1 ならば
	pm = pmx; po = pox; goto RR;		// 何もしない
    }
    ccx = rnch * cc();				// rnotch の目標
    if (rna > ccx) {				// rna > ccx なら
	po = v; pm = po + ar;			// po = v または
	if (po < pox) {po = pox; pm = pmx;}	// 動かさないこともある
	goto RR;
    }
    if ( rnb - rna < INVLIM || ccx >= rnb) {	// rnb == rna なら
	po = v; pm = po + ar;			// po = v または
	if (po < pox) {po = pox; pm = pmx;}	// 動かさないこともある
	goto RR;
    }
    vcc = ( ccx - rna) / ( rnb - rna ) * ar;	// po = v - vcc
    po = v - vcc;				// となるように
    pm = po + ar;				// po, pm を決める
    if (pm < pmx) {po = pox; pm = pmx;}		// 動かさないこともある

  RR:
#ifdef CVPRINT
    l_ofs << StrPrintf
      ( "car No.%2i: V4-V1=%6.1f %6.1f %6.1f %6.1f [V], cc,cl=%.1f %.1f" ,
        carno , adata . crfvol , adata . crbvol , pm , po , cc () , cl () )
          << endl ;
#endif
    return ;
}

void train::membercopy(const train& x) {
    rsc_ad = x.rsc_ad;	rsc_bd = x.rsc_bd;	rsc_at = x.rsc_at;
    rsc_bt = x.rsc_bt;	rsc_cc = x.rsc_cc;	rsc_cl = x.rsc_cl;
    wdrivee = x.wdrivee;	wloadd = x.wloadd;	wtraile = x.wtraile;
    wloadt = x.wloadt;	cresist = x.cresist;	wrotate = x.wrotate;
}

// 古い値の保存
void train::setviold
() {
    v_old = v;			a_old = a;
    shibo_old = shibo;
    stat_old = stat;	tt_old = tt;
}

void train::restorevi
() {
    v = v_old;		a = a_old;
    tt = tt_old;
    shibo = shibo_old;
}



// 回生失効の判断と処置
void
train :: regendead
( double ddhh ,
  double & tregendead )
{
  //***********************************************************************
  //* sw_regenoffantei が true のときだけ呼ぶようにすること             *
  //* ただし呼ぶからにはすべてのシミュレーション時間刻みに1度ずつ呼ぶこと *
  //***********************************************************************
  if ( sw_regenoffantei )
  {
    if ( rnotch >= - INVLIM || vel < bdata . regenoff )
    {
      sw_regendead = false ;
      return ;		// car_stat では判断できない！
    }
    if ( sw_regendead )
    {
      tregendead += ddhh ;
      return ;
    }
    if ( sw_anteimotor )
    {
      if ( noshibo > INVLIM )
      {
        double ampmotor = ampmotor_b ;
        double vh = vhigh_b * v / bdata . ec ;
        if ( vel < bdata . regenoff )
        {
          ampmotor = 0.0 ;
        }
        else if ( vel < vh )
        {
          ampmotor *= shibo ;
          ampmotor /= noshibo ;
          ampmotor *= fabs ( rnotch ) ;
        }
        else
        {
          ampmotor *= vh * shibo ;
          ampmotor /= vel * noshibo ;	// 速度に反比例
          ampmotor *= fabs ( rnotch ) ;
        }
        if ( ! sw_regendead && ampmotor < bdata . regendantei
             && shibo < noshibo )
        {
          sw_regendead = true ;
          l_ofs << StrPrintf ( "car No. %i: Regeneration DEAD" , carno )
                << endl ;
          return ;
        }
      }
    }
    else
    {
      if ( ! sw_regendead && shibo < bdata . regendantei
           && shibo < noshibo )
      {
        sw_regendead = true ;
        l_ofs << StrPrintf ( "car No. %i: Regeneration DEAD" , carno )
              << endl ;
        return ;
      }
    }
  }
}




void train::setconges
(double cg) {
    conges = cg;
    // 力行時用
    if (conges >= pdata.pbmid.conges) {
	cg = cgdef(pdata.pbfull.conges, pdata.pbmid.conges);
	vlow_p = cgcal(cg, pdata.pbfull.lowvel, pdata.pbmid.lowvel);
	vhigh_p = cgcal(cg, pdata.pbfull.highvel, pdata.pbmid.highvel);
	constf_p = cgcal(cg, pdata.pbfull.tracf, pdata.pbmid.tracf);
	ampmax_p = cgcal(cg, pdata.pbfull.mcurr, pdata.pbmid.mcurr);
    } else {	// 新しい補間方式、fixed 15 Jan 1994
	cg = cgdef(pdata.pbmid.conges, pdata.pbempty.conges);
	constf_p = cgcal(cg, pdata.pbmid.tracf, pdata.pbempty.tracf);
	vhigh_p = velcal_mid(cg, pdata.pbmid.tracf, pdata.pbmid.highvel,
			   pdata.pbempty.tracf, pdata.pbempty.highvel,
			   constf_p);
	vlow_p = vhigh_p;
	ampmax_p = ampcal_mid
	    (cg, pdata.pbmid.mcurr, pdata.pbmid.highvel,
	     pdata.pbempty.mcurr, pdata.pbempty.highvel,
	     vhigh_p);
    }
    // ブレーキ時用
    if (conges >= pdata.pbmid.conges) {
	cg = cgdef(bdata.pbfull.conges, bdata.pbmid.conges);
	vlow_b = cgcal(cg, bdata.pbfull.lowvel, bdata.pbmid.lowvel);
	vhigh_b = cgcal(cg, bdata.pbfull.highvel, bdata.pbmid.highvel);
	constf_b = cgcal(cg, bdata.pbfull.tracf, bdata.pbmid.tracf);
	ampmax_b = cgcal(cg, bdata.pbfull.mcurr, bdata.pbmid.mcurr);
	ampmotor_b = cgcal(cg, bdata.pbfull.motorcurr,
			 bdata.pbmid.motorcurr);
    } else {
	cg = cgdef(bdata.pbmid.conges, bdata.pbempty.conges);
	ampmotor_b = cgcal(cg, bdata.pbmid.motorcurr,
			 bdata.pbempty.motorcurr);
	constf_b = cgcal(cg, bdata.pbmid.tracf, bdata.pbempty.tracf);
	vhigh_b = velcal_mid(cg, bdata.pbmid.tracf, bdata.pbmid.highvel,
			   bdata.pbempty.tracf, bdata.pbempty.highvel,
			   constf_b);
	vlow_b = vhigh_b;
	ampmax_b = ampcal_mid
	    (cg, bdata.pbmid.mcurr, bdata.pbmid.highvel,
	     bdata.pbempty.mcurr, bdata.pbempty.highvel,
	     vhigh_b);
    }
}



// 現在の回生絞り込み率
double
train :: regenrate
()
  const
{
  if ( fabs ( noshibo ) > INVLIM )
  {
    return shibo / noshibo ;
  }
  else
  {
    return 1.0 ;	// 最大にしておかないとまずかろう
  }
}


// cg の計算
double train::cgdef(double cf, double cm) {
    double cg;
    if ( conges > cf ) cg = cf;
    else cg = conges;
    if ( fabs(cf - cm) >= INVLIM ) {
	cg -= cm;
	cg /= cf - cm;
    } else cg = 1.0;	// ゼロのときはこうして逃げを打つ
    return cg;
}

// cg→定数計算
double train::cgcal
(double cg, double upval, double downval) {
    double retv = upval - downval;
    retv *= cg;
    retv += downval;
    return retv;
}

// Inverter電車の定トルク／フリーラン分界速度
double train::velcal_mid
(double cg, double trf_mid, double vel_mid,
 double trf_emp, double vel_emp, double constf) {
// 分界速度V: V^2 * tf = const.
    double t_v_v = cgcal(cg, trf_mid * vel_mid * vel_mid,
			 trf_emp * vel_emp * vel_emp);
    return sqrt(t_v_v / constf);
}

// Inverter電車の定トルク／フリーラン分界電流
double train::ampcal_mid
(double cg, double mcurr_mid, double vel_mid,
 double mcurr_emp, double vel_emp, double velv) {
// 分界電流A: A^2 * W = zconst.
    double k_iv = cgcal
	(cg, mcurr_mid * vel_mid, mcurr_emp * vel_emp);
    return k_iv / velv;
}



// -----
// Output "header" to CSV file.
// Boolean argument: suppress leading comma if false.
// CSVファイルへの「ヘッダ」の出力.
// 論理値引数: 偽ならカンマの出力を抑制.
// -----
bool
train :: 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 << "TRN " << csno << " V" << __quot << ","
          << __quot << "TRN " << csno << " I" << __quot ;
    if ( g_sw_csv_has_noshibo )
    {
      x_out << "," << __quot << "TRN " << csno << " noshibo" << __quot ;
    }
    if ( g_sw_csv_has_rnotch_for_capper )
    {
      x_out << "," << __quot << "TRN " << csno << " capper-r" << __quot ;
    }
    x_out << "," << __quot << "TRN " << csno << " pos" << __quot << ","
          << __quot << "TRN " << csno << " vel" << __quot ;

    // OBESS
    stringstream h_ss_csv ;
    h_ss_csv << "TRN " << csno << " ESS" ;
    string h_csv = h_ss_csv . str () ;
    trn_ess -> writeHeaderToCSV ( x_out , true , h_csv ) ;
  }
  return true ;
}



// -----
// Output to CSV file. Boolean argument: suppress leading comma if false.
// CSVファイルへの出力. 論理値引数: 偽ならカンマの出力を抑制.
// -----
bool
train :: 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 ;
    if ( g_sw_csv_has_noshibo )
    {
      x_out << "," << __quot << getCurrentWithoutRegenLimiter () << __quot ;
    }
    if ( g_sw_csv_has_rnotch_for_capper )
    {
      x_out << "," << __quot << getNotchRateForCapper () << __quot ;
    }
    x_out << "," << __quot << position () << __quot << ","
          << __quot << velocity () << __quot ;

    // OBESS
    trn_ess -> writeToCSV ( x_out , true ) ;
  }
  return true ;
}



train_ParamFunc :: train_ParamFunc
( int __carno_in ,
  brakedata const & __bd_in ,
  powerdata const & __pd_in ,
  double __vlow_b_in ,
  double __vhigh_b_in ,
  double __constf_b_in ,
  double __ampmax_b_in ,
  double __ampmotor_b_in ,
  double __vlow_p_in ,
  double __vhigh_p_in ,
  double __constf_p_in ,
  double __ampmax_p_in ,
  double __pos_in ,
  double __vel_in ,
  double __tt_in ,
  double __v_in ,
  double __dv_in ,
  double __rnotch_in ,
  double __dnch_in ,
  double __rnotch_for_capper_in ,
  double __a_in ,
  double __a_wo_capper_in ,
  double __a_main_circuit_in ,
  double __di_in ,
  double __noshibo_in ,
  bool __sw_regendead_in ,
  bool __is_limiting_regen_in ,
  bool __sw_torque_shibori_in ,
  bool __sw_shibori_parallel_in ,
  bool __sw_regenoffantei_in ,
  ESS_OnBoard * trn_ess_in ,
  nextsta const * __nxx_in )
  : __carno ( __carno_in ) ,
    __bd ( __bd_in ) ,
    __pd ( __pd_in ) ,
    __vlow_b ( __vlow_b_in ) ,
    __vhigh_b ( __vhigh_b_in ) ,
    __constf_b ( __constf_b_in ) ,
    __ampmax_b ( __ampmax_b_in ) ,
    __ampmotor_b ( __ampmotor_b_in ) ,
    __vlow_p ( __vlow_p_in ) ,
    __vhigh_p ( __vhigh_p_in ) ,
    __constf_p ( __constf_p_in ) ,
    __ampmax_p ( __ampmax_p_in ) ,
    __pos ( __pos_in ) ,
    __vel ( __vel_in ) ,
    __tt ( __tt_in ) ,
    __v ( __v_in ) ,
    __dv ( __dv_in ) ,
    __rnotch ( __rnotch_in ) ,
    __dnch ( __dnch_in ) ,
    __rnotch_for_capper ( __rnotch_for_capper_in ) ,
    __a ( __a_in ) ,
    __a_wo_capper ( __a_wo_capper_in ) ,
    __a_main_circuit ( __a_main_circuit_in ) ,
    __di ( __di_in ) ,
    __noshibo ( __noshibo_in ) ,
    __sw_regendead ( __sw_regendead_in ) ,
    __is_limiting_regen ( __is_limiting_regen_in ) ,
    __sw_torque_shibori ( __sw_torque_shibori_in ) ,
    __sw_shibori_parallel ( __sw_shibori_parallel_in ) ,
    __sw_regenoffantei ( __sw_regenoffantei_in ) ,
    __max_tractive_effort ( 0 ) ,
    __max_braking_effort ( 0 ) ,
    __nxx ( __nxx_in )
{
  trn_ess = trn_ess_in -> getMyClone () ;
}


train_ParamFunc :: train_ParamFunc
( train_ParamFunc const & x )
  : __carno ( x . __carno ) ,
    __bd ( x . __bd ) ,
    __pd ( x . __pd ) ,
    __vlow_b ( x . __vlow_b ) ,
    __vhigh_b ( x . __vhigh_b ) ,
    __constf_b ( x . __constf_b ) ,
    __ampmax_b ( x . __ampmax_b ) ,
    __ampmotor_b ( x . __ampmotor_b ) ,
    __vlow_p ( x . __vlow_p ) ,
    __vhigh_p ( x . __vhigh_p ) ,
    __constf_p ( x . __constf_p ) ,
    __ampmax_p ( x . __ampmax_p ) ,
    __pos ( x . __pos ) ,
    __vel ( x . __vel ) ,
    __tt ( x . __tt ) ,
    __v ( x . __v ) ,
    __dv ( x . __dv ) ,
    __rnotch ( x . __rnotch ) ,
    __dnch ( x . __dnch ) ,
    __rnotch_for_capper ( x . __rnotch_for_capper ) ,
    __a ( x . __a ) ,
    __a_wo_capper ( x . __a_wo_capper ) ,
    __a_main_circuit ( x . __a_main_circuit ) ,
    __di ( x . __di ) ,
    __noshibo ( x . __noshibo ) ,
    __sw_regendead ( x . __sw_regendead ) ,
    __is_limiting_regen ( x . __is_limiting_regen ) ,
    __sw_torque_shibori ( x . __sw_torque_shibori ) ,
    __sw_shibori_parallel ( x . __sw_shibori_parallel ) ,
    __sw_regenoffantei ( x . __sw_regenoffantei ) ,
    __max_tractive_effort ( x . __max_tractive_effort ) ,
    __max_braking_effort ( x . __max_braking_effort ) ,
    __nxx ( x . __nxx )
{
  trn_ess = x . trn_ess -> getMyClone () ;
}



// -----
// Renew the electrical state variables.
// 電気的状態変数を更新。
// -----
void
train :: renewElectricalStates
()
{
  // ----
  // Because it seems train_ParamFunc pointer is actually not necessary...
  // どうも train_ParamFunc ポインタは実際には必要ないみたいなので……
  // ----
  trn_ess -> renewElectricalStates ( 0 ) ;
}



// -----
// Calculate voltage and current of the ESS.
// -----
void
train :: calculateESDVoltageAndCurrent
()
{
  // ----
  // Because it seems train_ParamFunc pointer is actually not necessary...
  // どうも train_ParamFunc ポインタは実際には必要ないみたいなので……
  // ----
  trn_ess -> calculateESDVoltageAndCurrent ( 0 ) ;
}
