LCOV - code coverage report
Current view: top level - src/microsim/cfmodels - MSCFModel_Rail.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 87.9 % 149 131
Test Date: 2024-12-21 15:45:41 Functions: 88.2 % 17 15

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2012-2024 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    MSCFModel_Rail.cpp
      15              : /// @author  Gregor Laemmel
      16              : /// @author  Leander Flamm
      17              : /// @date    Tue, 08 Feb 2017
      18              : ///
      19              : // <description missing>
      20              : /****************************************************************************/
      21              : #include <config.h>
      22              : 
      23              : #include <iostream>
      24              : #include <utils/common/MsgHandler.h>
      25              : #include <utils/common/StringUtils.h>
      26              : #include <utils/common/StringTokenizer.h>
      27              : #include <utils/geom/GeomHelper.h>
      28              : #include <microsim/MSVehicle.h>
      29              : #include <microsim/lcmodels/MSAbstractLaneChangeModel.h>
      30              : #include "MSCFModel_Rail.h"
      31              : 
      32              : // ===========================================================================
      33              : // trainParams method definitions
      34              : // ===========================================================================
      35              : 
      36              : double
      37      2313348 : MSCFModel_Rail::TrainParams::getResistance(double speed) const {
      38      2313348 :     if (resCoef_constant != INVALID_DOUBLE) {
      39        20704 :         return (resCoef_quadratic * speed * speed + resCoef_linear * speed + resCoef_constant); // kN
      40              :     } else {
      41      2292644 :         return LinearApproxHelpers::getInterpolatedValue(resistance, speed); // kN
      42              :     }
      43              : }
      44              : 
      45              : 
      46              : double
      47      1489710 : MSCFModel_Rail::TrainParams::getTraction(double speed) const {
      48      1489710 :     if (maxPower != INVALID_DOUBLE) {
      49         6596 :         return MIN2(maxPower / speed, maxTraction); // kN
      50              :     } else {
      51      1483114 :         return LinearApproxHelpers::getInterpolatedValue(traction, speed); // kN
      52              :     }
      53              : }
      54              : 
      55              : // ===========================================================================
      56              : // method definitions
      57              : // ===========================================================================
      58              : 
      59              : 
      60          338 : MSCFModel_Rail::MSCFModel_Rail(const MSVehicleType* vtype) :
      61          338 :     MSCFModel(vtype) {
      62          338 :     const std::string trainType = vtype->getParameter().getCFParamString(SUMO_ATTR_TRAIN_TYPE, "NGT400");
      63          338 :     if (trainType.compare("RB425") == 0) {
      64           38 :         myTrainParams = initRB425Params();
      65          300 :     } else if (trainType.compare("RB628") == 0) {
      66           19 :         myTrainParams = initRB628Params();
      67          281 :     } else if (trainType.compare("NGT400") == 0) {
      68          116 :         myTrainParams = initNGT400Params();
      69          165 :     } else if (trainType.compare("NGT400_16") == 0) {
      70            4 :         myTrainParams = initNGT400_16Params();
      71          161 :     } else if (trainType.compare("ICE1") == 0) {
      72            9 :         myTrainParams = initICE1Params();
      73          152 :     } else if (trainType.compare("REDosto7") == 0) {
      74           89 :         myTrainParams = initREDosto7Params();
      75           63 :     } else if (trainType.compare("Freight") == 0) {
      76           38 :         myTrainParams = initFreightParams();
      77           25 :     } else if (trainType.compare("ICE3") == 0) {
      78            5 :         myTrainParams = initICE3Params();
      79           20 :     } else if (trainType.compare("MireoPlusB") == 0) {
      80            4 :         myTrainParams = initMireoPlusB2TParams();
      81           16 :     } else if (trainType.compare("MireoPlusH") == 0) {
      82            4 :         myTrainParams = initMireoPlusH2TParams();
      83           12 :     } else if (trainType.compare("custom") == 0) {
      84           12 :         myTrainParams = initCustomParams();
      85              :     } else {
      86            4 :         WRITE_ERRORF(TL("Unknown train type: %. Exiting!"), trainType);
      87            0 :         throw ProcessError();
      88              :     }
      89              :     // override with user values
      90          338 :     if (vtype->wasSet(VTYPEPARS_MAXSPEED_SET)) {
      91           28 :         myTrainParams.vmax = vtype->getMaxSpeed();
      92              :     }
      93          338 :     if (vtype->wasSet(VTYPEPARS_LENGTH_SET)) {
      94           47 :         myTrainParams.length = vtype->getLength();
      95              :     }
      96          338 :     if (vtype->wasSet(VTYPEPARS_MASS_SET)) {
      97              :         // kg to tons
      98            4 :         myTrainParams.weight = vtype->getMass() / 1000;
      99              :     }
     100          338 :     myTrainParams.mf = vtype->getParameter().getCFParam(SUMO_ATTR_MASSFACTOR, myTrainParams.mf);
     101          338 :     myTrainParams.decl = vtype->getParameter().getCFParam(SUMO_ATTR_DECEL, myTrainParams.decl);
     102              :     setMaxDecel(myTrainParams.decl);
     103          338 :     setEmergencyDecel(vtype->getParameter().getCFParam(SUMO_ATTR_EMERGENCYDECEL, myTrainParams.decl + 0.3));
     104              :     // update type parameters so they are shown correctly in the gui (if defaults from trainType are used)
     105          338 :     const_cast<MSVehicleType*>(vtype)->setMaxSpeed(myTrainParams.vmax);
     106          338 :     const_cast<MSVehicleType*>(vtype)->setLength(myTrainParams.length);
     107              : 
     108              :     // init tabular curves
     109          338 :     std::vector<double> speedTable = getValueTable(vtype, SUMO_ATTR_SPEED_TABLE);
     110          338 :     std::vector<double> tractionTable = getValueTable(vtype, SUMO_ATTR_TRACTION_TABLE);
     111          338 :     std::vector<double> resistanceTable = getValueTable(vtype, SUMO_ATTR_RESISTANCE_TABLE);
     112          338 :     if (speedTable.size() > 0 || tractionTable.size() > 0 || resistanceTable.size() > 0) {
     113            8 :         if (speedTable.size() == 1) {
     114            0 :             throw ProcessError(TLF("Invalid size of speedTable for vType '%' (at least 2 values are required).", vtype->getID()));
     115            8 :         } else if (speedTable.size() != tractionTable.size()) {
     116            0 :             throw ProcessError(TLF("Mismatching size of speedTable and tractionTable for vType '%'.", vtype->getID()));
     117            8 :         } else if (speedTable.size() != resistanceTable.size()) {
     118            0 :             throw ProcessError(TLF("Mismatching size of speedTable and resistanceTable for vType '%'.", vtype->getID()));
     119              :         }
     120              :         myTrainParams.traction.clear();
     121              :         myTrainParams.resistance.clear();
     122          112 :         for (int i = 0; i < (int)speedTable.size(); i++) {
     123          104 :             myTrainParams.traction[speedTable[i]] = tractionTable[i];
     124          104 :             myTrainParams.resistance[speedTable[i]] = resistanceTable[i];
     125              :         }
     126              :     }
     127              : 
     128              :     // init parametric curves
     129          338 :     myTrainParams.maxPower = vtype->getParameter().getCFParam(SUMO_ATTR_MAXPOWER, INVALID_DOUBLE);
     130          338 :     myTrainParams.maxTraction = vtype->getParameter().getCFParam(SUMO_ATTR_MAXTRACTION, INVALID_DOUBLE);
     131          338 :     myTrainParams.resCoef_constant = vtype->getParameter().getCFParam(SUMO_ATTR_RESISTANCE_COEFFICIENT_CONSTANT, INVALID_DOUBLE);
     132          338 :     myTrainParams.resCoef_linear = vtype->getParameter().getCFParam(SUMO_ATTR_RESISTANCE_COEFFICIENT_LINEAR, INVALID_DOUBLE);
     133          338 :     myTrainParams.resCoef_quadratic = vtype->getParameter().getCFParam(SUMO_ATTR_RESISTANCE_COEFFICIENT_QUADRATIC, INVALID_DOUBLE);
     134              : 
     135          338 :     if (myTrainParams.maxPower != INVALID_DOUBLE && myTrainParams.maxTraction == INVALID_DOUBLE) {
     136            0 :         throw ProcessError(TLF("Undefined maxPower for vType '%'.", vtype->getID()));
     137          338 :     } else if (myTrainParams.maxPower == INVALID_DOUBLE && myTrainParams.maxTraction != INVALID_DOUBLE) {
     138            0 :         throw ProcessError(TLF("Undefined maxTraction for vType '%'.", vtype->getID()));
     139              :     }
     140          338 :     if (myTrainParams.maxPower != INVALID_DOUBLE && tractionTable.size() > 0) {
     141            0 :         WRITE_WARNING(TLF("Ignoring tractionTable because maxPower and maxTraction are set for vType '%'.", vtype->getID()));
     142              :     }
     143          338 :     const bool hasSomeResCoef = (myTrainParams.resCoef_constant != INVALID_DOUBLE
     144          334 :                                  || myTrainParams.resCoef_linear != INVALID_DOUBLE
     145          672 :                                  || myTrainParams.resCoef_quadratic != INVALID_DOUBLE);
     146              :     const bool hasAllResCoef = (myTrainParams.resCoef_constant != INVALID_DOUBLE
     147            4 :                                 && myTrainParams.resCoef_linear != INVALID_DOUBLE
     148          342 :                                 && myTrainParams.resCoef_quadratic != INVALID_DOUBLE);
     149          338 :     if (hasSomeResCoef && !hasAllResCoef) {
     150            0 :         throw ProcessError(TLF("Some undefined resistance coefficients for vType '%' (requires resCoef_constant, resCoef_linear and resCoef_quadratic)", vtype->getID()));
     151              :     }
     152          338 :     if (myTrainParams.resCoef_constant != INVALID_DOUBLE && resistanceTable.size() > 0) {
     153            0 :         WRITE_WARNING(TLF("Ignoring resistanceTable because resistance coefficients are set for vType '%'.", vtype->getID()));
     154              :     }
     155              : 
     156          338 :     if (myTrainParams.traction.empty() && myTrainParams.maxPower == INVALID_DOUBLE) {
     157           12 :         throw ProcessError(TLF("Either tractionTable or maxPower must be defined for vType '%' with Rail model type '%'.", vtype->getID(), trainType));
     158              :     }
     159          334 :     if (myTrainParams.resistance.empty() && myTrainParams.resCoef_constant == INVALID_DOUBLE) {
     160            0 :         throw ProcessError(TLF("Either resistanceTable or resCoef_constant must be defined for vType '%' with Rail model type '%'.", vtype->getID(), trainType));
     161              :     }
     162          688 : }
     163              : 
     164              : 
     165          666 : MSCFModel_Rail::~MSCFModel_Rail() { }
     166              : 
     167              : 
     168              : std::vector<double>
     169         1014 : MSCFModel_Rail::getValueTable(const MSVehicleType* vtype, SumoXMLAttr attr) {
     170              :     std::vector<double> result;
     171         2028 :     const std::string values = vtype->getParameter().getCFParamString(attr, "");
     172         1014 :     if (!values.empty()) {
     173          360 :         for (std::string value : StringTokenizer(values).getVector()) {
     174          312 :             result.push_back(StringUtils::toDouble(value));
     175           24 :         }
     176              :     }
     177         1014 :     return result;
     178            0 : }
     179              : 
     180              : 
     181        84126 : double MSCFModel_Rail::followSpeed(const MSVehicle* const veh, double speed, double gap,
     182              :                                    double /* predSpeed */, double /* predMaxDecel*/, const MSVehicle* const /*pred*/, const CalcReason /*usage*/) const {
     183              : 
     184              :     // followSpeed module is used for the simulation of moving block operations. The safety gap is chosen similar to the existing german
     185              :     // system CIR-ELKE (based on LZB). Other implementations of moving block systems may differ, but for now no appropriate parameter
     186              :     // can be set (would be per lane, not per train) -> hard-coded
     187              : 
     188              :     // @note: default train minGap of 5 is already subtracted from gap
     189        84126 :     if (speed >= 30 / 3.6) {
     190              :         // safety distance for higher speeds (>= 30 km/h)
     191        52872 :         gap = MAX2(0.0, gap + veh->getVehicleType().getMinGap() - 50);
     192              :     }
     193              : 
     194        84126 :     const double vsafe = maximumSafeStopSpeed(gap, myDecel, speed, false, TS, false); // absolute breaking distance
     195        84126 :     const double vmin = minNextSpeed(speed, veh);
     196        84126 :     const double vmax = maxNextSpeed(speed, veh);
     197              : 
     198        84126 :     if (MSGlobals::gSemiImplicitEulerUpdate) {
     199              :         return MIN2(vsafe, vmax);
     200              :     } else {
     201              :         // ballistic
     202              :         // XXX: the euler variant can break as strong as it wishes immediately! The ballistic cannot, refs. #2575.
     203              :         return MAX2(MIN2(vsafe, vmax), vmin);
     204              :     }
     205              : }
     206              : 
     207              : 
     208              : int
     209            0 : MSCFModel_Rail::getModelID() const {
     210            0 :     return SUMO_TAG_CF_RAIL;
     211              : }
     212              : 
     213              : 
     214              : MSCFModel*
     215            3 : MSCFModel_Rail::duplicate(const MSVehicleType* vtype) const {
     216            3 :     return new MSCFModel_Rail(vtype);
     217              : }
     218              : 
     219              : 
     220      1624357 : double MSCFModel_Rail::maxNextSpeed(double speed, const MSVehicle* const veh) const {
     221              : 
     222      1624357 :     if (speed >= myTrainParams.vmax) {
     223              :         return myTrainParams.vmax;
     224              :     }
     225              : 
     226              :     double targetSpeed = myTrainParams.vmax;
     227              : 
     228      1489710 :     double res = myTrainParams.getResistance(speed); // kN
     229              : 
     230      1489710 :     double slope = veh->getSlope();
     231      1489710 :     double gr = myTrainParams.weight * GRAVITY * sin(DEG2RAD(slope)); //kN
     232              : 
     233      1489710 :     double totalRes = res + gr; //kN
     234              : 
     235      1489710 :     double trac = myTrainParams.getTraction(speed); // kN
     236              : 
     237              :     double a;
     238      1489710 :     if (speed < targetSpeed) {
     239      1489710 :         a = (trac - totalRes) / myTrainParams.getRotWeight(); //kN/t == N/kg
     240              :     } else {
     241              :         a = 0.;
     242            0 :         if (totalRes > trac) {
     243            0 :             a = (trac - totalRes) / myTrainParams.getRotWeight(); //kN/t == N/kg
     244              :         }
     245              :     }
     246      1489710 :     double maxNextSpeed = speed + ACCEL2SPEED(a);
     247              : 
     248              : //    std::cout << veh->getID() << " speed: " << (speed*3.6) << std::endl;
     249              : 
     250      1489710 :     return maxNextSpeed;
     251              : }
     252              : 
     253              : 
     254       823638 : double MSCFModel_Rail::minNextSpeed(double speed, const MSVehicle* const veh) const {
     255              : 
     256       823638 :     const double slope = veh->getSlope();
     257       823638 :     const double gr = myTrainParams.weight * GRAVITY * sin(DEG2RAD(slope)); //kN
     258       823638 :     const double res = myTrainParams.getResistance(speed); // kN
     259       823638 :     const double totalRes = res + gr; //kN
     260       823638 :     const double a = myTrainParams.decl + totalRes / myTrainParams.getRotWeight();
     261       823638 :     const double vMin = speed - ACCEL2SPEED(a);
     262       823638 :     if (MSGlobals::gSemiImplicitEulerUpdate) {
     263              :         return MAX2(vMin, 0.);
     264              :     } else {
     265              :         // NOTE: ballistic update allows for negative speeds to indicate a stop within the next timestep
     266              :         return vMin;
     267              :     }
     268              : 
     269              : }
     270              : 
     271              : 
     272              : double
     273       244880 : MSCFModel_Rail::minNextSpeedEmergency(double speed, const MSVehicle* const veh) const {
     274       244880 :     return minNextSpeed(speed, veh);
     275              : }
     276              : 
     277              : 
     278              : //void
     279              : //MSCFModel_Rail::initVehicleVariables(const MSVehicle *const veh, MSCFModel_Rail::VehicleVariables *pVariables) const {
     280              : //
     281              : //    pVariables->setInitialized();
     282              : //
     283              : //}
     284              : 
     285              : 
     286            0 : double MSCFModel_Rail::getSpeedAfterMaxDecel(double /* speed */) const {
     287              : 
     288              : //    //TODO: slope not known here
     289              : //    double gr = 0; //trainParams.weight * GRAVITY * edge.grade
     290              : //
     291              : //    double a = 0;//trainParams.decl - gr/trainParams.rotWeight;
     292              : //
     293              : //    return speed + a * DELTA_T / 1000.;
     294            0 :     WRITE_ERROR("function call not allowed for rail model. Exiting!");
     295            0 :     throw ProcessError();
     296              : }
     297              : 
     298              : 
     299          378 : MSCFModel::VehicleVariables* MSCFModel_Rail::createVehicleVariables() const {
     300          378 :     VehicleVariables* ret = new VehicleVariables();
     301          378 :     return ret;
     302              : }
     303              : 
     304              : 
     305       244880 : double MSCFModel_Rail::finalizeSpeed(MSVehicle* const veh, double vPos) const {
     306       244880 :     return MSCFModel::finalizeSpeed(veh, vPos);
     307              : }
     308              : 
     309              : 
     310       927705 : double MSCFModel_Rail::freeSpeed(const MSVehicle* const /* veh */, double /* speed */, double dist, double targetSpeed,
     311              :                                  const bool onInsertion, const CalcReason /*usage*/) const {
     312              : 
     313              : //    MSCFModel_Rail::VehicleVariables *vars = (MSCFModel_Rail::VehicleVariables *) veh->getCarFollowVariables();
     314              : //    if (vars->isNotYetInitialized()) {
     315              : //        initVehicleVariables(veh, vars);
     316              : //    }
     317              : 
     318              :     //TODO: signals, coasting, ...
     319              : 
     320       927705 :     if (MSGlobals::gSemiImplicitEulerUpdate) {
     321              :         // adapt speed to succeeding lane, no reaction time is involved
     322              :         // when breaking for y steps the following distance g is covered
     323              :         // (drive with v in the final step)
     324              :         // g = (y^2 + y) * 0.5 * b + y * v
     325              :         // y = ((((sqrt((b + 2.0*v)*(b + 2.0*v) + 8.0*b*g)) - b)*0.5 - v)/b)
     326       927704 :         const double v = SPEED2DIST(targetSpeed);
     327       927704 :         if (dist < v) {
     328              :             return targetSpeed;
     329              :         }
     330       834551 :         const double b = ACCEL2DIST(myDecel);
     331       834551 :         const double y = MAX2(0.0, ((sqrt((b + 2.0 * v) * (b + 2.0 * v) + 8.0 * b * dist) - b) * 0.5 - v) / b);
     332       834551 :         const double yFull = floor(y);
     333       834551 :         const double exactGap = (yFull * yFull + yFull) * 0.5 * b + yFull * v + (y > yFull ? v : 0.0);
     334       834551 :         const double fullSpeedGain = (yFull + (onInsertion ? 1. : 0.)) * ACCEL2SPEED(myTrainParams.decl);
     335      1113654 :         return DIST2SPEED(MAX2(0.0, dist - exactGap) / (yFull + 1)) + fullSpeedGain + targetSpeed;
     336              :     } else {
     337            1 :         WRITE_ERROR(TL("Anything else than semi implicit euler update is not yet implemented. Exiting!"));
     338            1 :         throw ProcessError();
     339              :     }
     340              : }
     341              : 
     342              : 
     343       996357 : double MSCFModel_Rail::stopSpeed(const MSVehicle* const veh, const double speed, double gap, double decel, const CalcReason /*usage*/) const {
     344       996357 :     return MIN2(maximumSafeStopSpeed(gap, decel, speed, false, TS, false), maxNextSpeed(speed, veh));
     345              : }
        

Generated by: LCOV version 2.0-1