diff --git a/Project.toml b/Project.toml index 3122b10..942c8ea 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "TrainRun" uuid = "e4541106-d44c-4e00-b50b-ecdf479fcf92" authors = ["Max Kannenberg"] -version = "0.2.0" +version = "0.5.0" [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" diff --git a/README.md b/README.md index ee52059..35bb997 100644 --- a/README.md +++ b/README.md @@ -23,18 +23,28 @@ See folder examples. # History +## Version 0.5 + +Refactor modules for diminishing run and tractive effort velocity pairs + +- Add the seperate moving phase "diminishing run" for steep ascents where a train runs with maximum tractive effort while the driving resistances are even higher +- Refactor tractiveEffortArray to tractiveEffortVelocityPairs +- Rename file path and folder path to directory + + ## Version 0.4.1 Rename waypoints - rename "waypoints" to "dataPoints" and "Waypoint" to "DataPoint" + ## Version 0.4 Refactor and fix modules EnergySaving, OperationModes and MovingPhases -- add the general used level of accuracy from v0.3 to EnergySaving and OperationModes. -- fix OperationModes and MovingPhases for steep ascents where a train runs with maximum tractive effort while the driving resistances are even higher. +- add the general used level of accuracy from v0.3 to EnergySaving and OperationModes +- fix OperationModes and MovingPhases for steep ascents where a train runs with maximum tractive effort while the driving resistances are even higher ## Version 0.3 @@ -42,7 +52,7 @@ Refactor and fix modules EnergySaving, OperationModes and MovingPhases Refactor module MovingPhases - extract repeatedly occuring code lines and create smaller functions (e.g. the function moveAStep) -- integrate a new approach for calculating the waypoints near intersections (e.g. including an editable level of accuracy). +- integrate a new approach for calculating the waypoints near intersections (e.g. including an editable level of accuracy) ## Version 0.2 diff --git a/src/EnergySaving.jl b/src/EnergySaving.jl index fd38d6b..7bfc6bc 100644 --- a/src/EnergySaving.jl +++ b/src/EnergySaving.jl @@ -90,6 +90,214 @@ function calculateRecoveryTime(s_MS::AbstractFloat, t_MS::AbstractFloat, train:: end #function calculateRecoveryTime function increaseCoastingSection(csOriginal::CharacteristicSection, drivingCourse::Vector{DataPoint}, settings::Settings, train::Train, allCSs::Vector{CharacteristicSection}, t_recoveryAvailable::AbstractFloat) + if (haskey(csOriginal.behaviorSections, "cruising") || haskey(csOriginal.behaviorSections, "diminishing")) && haskey(csOriginal.behaviorSections, "braking") + # check if cruising or diminishing should be reduced for coasting + if haskey(csOriginal.behaviorSections, "cruising") && haskey(csOriginal.behaviorSections, "diminishing") + if get(csOriginal.behaviorSections, "cruising", BehaviorSection()).dataPoints[1] > get(csOriginal.behaviorSections, "diminishing", BehaviorSection()).dataPoints[1] + reduceCruising=true + reduceDiminishing=false + else + reduceDiminishing=true + reduceCruising=false + end + elseif haskey(csOriginal.behaviorSections, "cruising") + reduceCruising=true + reduceDiminishing=false + elseif haskey(csOriginal.behaviorSections, "diminishing") + reduceDiminishing=true + reduceCruising=false + end + + + + if reduceCruising + cruisingReduction=settings.stepSize + while cruisingReduction>=settings.stepSize/10^approximationLevel + #while cruisingReduction>=settings.stepSize/100 + while cruisingReduction>=settings.stepSize/10^approximationLevel # will be done once and then depending on approximationLevel repeated with smaller cruisingReduction unless !(drivingCourseModified[end].v<=csModified.v_exit && drivingCourseModified[end].s see below at the end of the while loop + + # create a copy for the characteristic sections drivingCourse + energySavingStartId=get(csOriginal.behaviorSections, "cruising", BehaviorSection()).dataPoints[1] + if energySavingStartId==0 + error("ERROR at creating a new driving course for energy saving with coasting !") + end + + # copy the driving course till the beginning of energy saving + drivingCourseModified=Vector{DataPoint}() + for i in 1:energySavingStartId + push!(drivingCourseModified, DataPoint(drivingCourse[i])) # List of data points till the start of energy saving + # TODO: tried to insert copy on 15.07.2021 push!(drivingCourseModified, copy(drivingCourse[i])) # List of data points till the start of energy saving + end + + # calculating the new length of the cruising section + if settings.stepVariable=="s in m" # distance step method + s_cruising=get(csOriginal.behaviorSections, "cruising", BehaviorSection()).s_total-cruisingReduction + elseif settings.stepVariable=="t in s" # time step method + # 09/20 old: doesn't work for non constant cruising + # t_cruising=get(csOriginal.behaviorSections, "cruising", BehaviorSection()).t_total-cruisingReduction + # s_cruising=t_cruising*drivingCourseModified[end].v + wayReduction=drivingCourse(get(csOriginal.behaviorSections, "cruising", BehaviorSection()).dataPoints[end]).v*cruisingReduction + s_cruising=get(csOriginal.behaviorSections, "cruising", BehaviorSection()).s_total-wayReduction + + elseif settings.stepVariable=="v in m/s" # velocity step method + s_cruising=get(csOriginal.behaviorSections, "cruising", BehaviorSection()).s_total-cruisingReduction*10 # TODO: or better: *100 ? + end #if + s_cruising=max(0.0, s_cruising) + + # copy csOriginal to csModified + csModified=CharacteristicSection(csOriginal.id, csOriginal.s_total, csOriginal.s_start, csOriginal.s_end, 0.0, 0.0, csOriginal.v_limit, csOriginal.v_reach, csOriginal.v_entry, csOriginal.v_exit, csOriginal.f_Rp, Dict{String, BehaviorSection}()) + if haskey(csOriginal.behaviorSections, "starting") + startingSection=BehaviorSection(get(csOriginal.behaviorSections, "starting", BehaviorSection())) + merge!(csModified.behaviorSections, Dict("starting"=>startingSection)) + csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "starting", BehaviorSection()).E_total + csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "starting", BehaviorSection()).t_total + end + if haskey(csOriginal.behaviorSections, "cruisingBeforeAcceleration") # this section is needed before acceleration if the mass strip model is used and if the train wants to accelerate to a velocity higher than the limit in the other CS where parts of the union are still located + cruisingBeforeAccelerationSection=BehaviorSection(get(csOriginal.behaviorSections, "cruisingBeforeAcceleration", BehaviorSection())) + merge!(csModified.behaviorSections, Dict("cruisingBeforeAcceleration"=>cruisingBeforeAccelerationSection)) + csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "cruisingBeforeAcceleration", BehaviorSection()).E_total + csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "cruisingBeforeAcceleration", BehaviorSection()).t_total + end + if haskey(csOriginal.behaviorSections, "acceleration") + accelerationSection=BehaviorSection(get(csOriginal.behaviorSections, "acceleration", BehaviorSection())) + merge!(csModified.behaviorSections, Dict("acceleration"=>accelerationSection)) + csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "acceleration", BehaviorSection()).E_total + csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "acceleration", BehaviorSection()).t_total + end + + if haskey(csOriginal.behaviorSections, "diminishing") + diminishingSection=BehaviorSection(get(csOriginal.behaviorSections, "diminishing", BehaviorSection())) + merge!(csModified.behaviorSections, Dict("diminishing"=>diminishingSection)) + csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "diminishing", BehaviorSection()).E_total + csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "diminishing", BehaviorSection()).t_total + end + + + # calculate the new and now shorter cruising section + if s_cruising>0.0 + (csModified, drivingCourseModified)=addCruisingPhase!(csModified, drivingCourseModified, s_cruising, settings, train, allCSs, "cruising") + end + + # calculate the coasting phase until the point the train needs to brake + (csModified, drivingCourseModified)=addCoastingPhaseUntilBraking!(csModified, drivingCourseModified, settings, train, allCSs) + + if drivingCourseModified[end].v < csModified.v_exit || drivingCourseModified[end].s > csModified.s_end + # the train reaches v_exit before reaching s_end. The cruising and coasting sections have to be calculated again with a larger cruising section (so with a smaller reduction of the cruising section) + cruisingReduction=cruisingReduction/10 + else + break + end + end # while cruisingReduction + + # calculate the moving phase between coasting and the end of the CS + if drivingCourseModified[end].v > csModified.v_exit + #(csModified, drivingCourseModified)=addBrakingPhase!(csModified, drivingCourseModified, settings.massModel, train, allCSs) + (csModified, drivingCourseModified)=addBrakingPhase!(csModified, drivingCourseModified, settings, train, allCSs) + elseif drivingCourseModified[end].v == csModified.v_exit && drivingCourseModified[end].s < csModified.s_end + # v_exit is already reached. Now cruise till the end of the CS + s_cruisingAfterCoasting=csModified.s_end-drivingCourseModified[end].s + (csModified, drivingCourseModified)=addCruisingPhase!(csModified, drivingCourseModified, s_cruisingAfterCoasting, settings, train, allCSs, "cruisingAfterCoasting") + end + + if t_recoveryAvailable < csModified.t_total-csOriginal.t_total || drivingCourseModified[end].v != csModified.v_exit || drivingCourseModified[end].s != csModified.s_end # time loss is to high and the CS has to be calculated again with larger cruising section (so with a smaller reduction of the cruising section) or v_exit or s_end are not reached excatly + cruisingReduction=cruisingReduction/10 + else + return (csModified, drivingCourseModified, true) + end + end #while + + + elseif reduceDiminishing + # TODO: At the moment diminishing is reduced like the acceleration in decreaseMaximumVelocity. To reduce code, the methods for reducing cruising phase an reducing the diminishing pahse can be combined in some parts. + + # copy csOriginal to csModified + csModified=CharacteristicSection(csOriginal.id, csOriginal.s_total, csOriginal.s_start, csOriginal.s_end, 0.0, 0.0, csOriginal.v_limit, csOriginal.v_reach, csOriginal.v_entry, csOriginal.v_exit, csOriginal.f_Rp, Dict{String, BehaviorSection}()) + + if haskey(csOriginal.behaviorSections, "starting") + startingSection=BehaviorSection(get(csOriginal.behaviorSections, "starting", BehaviorSection())) + merge!(csModified.behaviorSections, Dict("starting"=>startingSection)) + csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "starting", BehaviorSection()).E_total + csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "starting", BehaviorSection()).t_total + end + + if haskey(csOriginal.behaviorSections, "cruisingBeforeAcceleration") # this section is needed before acceleration if the mass strip model is used and if the train wants to accelerate to a velocity higher than the limit in the other CS where parts of the union are still located + cruisingBeforeAccelerationSection=BehaviorSection(get(csOriginal.behaviorSections, "cruisingBeforeAcceleration", BehaviorSection())) + merge!(csModified.behaviorSections, Dict("cruisingBeforeAcceleration"=>cruisingBeforeAccelerationSection)) + csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "cruisingBeforeAcceleration", BehaviorSection()).E_total + csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "cruisingBeforeAcceleration", BehaviorSection()).t_total + end + if haskey(csOriginal.behaviorSections, "acceleration") + accelerationSection=BehaviorSection(get(csOriginal.behaviorSections, "acceleration", BehaviorSection())) + merge!(csModified.behaviorSections, Dict("acceleration"=>accelerationSection)) + csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "acceleration", BehaviorSection()).E_total + csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "acceleration", BehaviorSection()).t_total + end + + if haskey(csOriginal.behaviorSections, "cruising") + cruisingSection=BehaviorSection(get(csOriginal.behaviorSections, "cruising", BehaviorSection())) + merge!(csModified.behaviorSections, Dict("cruising"=>cruisingSection)) + csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "cruising", BehaviorSection()).E_total + csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "cruising", BehaviorSection()).t_total + end + + diminishingSection=BehaviorSection(get(csOriginal.behaviorSections, "diminishing", BehaviorSection())) + if length(diminishingSection.dataPoints) > 2 + # remove the last diminishing waypoint + pop!(diminishingSection.dataPoints) + + diminishingSection.v_exit=drivingCourse[diminishingSection.dataPoints[end]].v # exit speed (in m/s) + diminishingSection.s_end=drivingCourse[diminishingSection.dataPoints[end]].s # last position (in m) + diminishingSection.s_total=diminishingSection.s_end-diminishingSection.s_start # total length (in m) + diminishingSection.t_total=drivingCourse[diminishingSection.dataPoints[end]].t-drivingCourse[diminishingSection.dataPoints[1]].t # total running time (in s) + diminishingSection.E_total=drivingCourse[diminishingSection.dataPoints[end]].E-drivingCourse[diminishingSection.dataPoints[1]].E # total energy consumption (in Ws) + + merge!(csModified.behaviorSections, Dict("diminishing"=>diminishingSection)) + csModified.E_total=csModified.E_total+get(csModified.behaviorSections, "diminishing", BehaviorSection()).E_total + csModified.t_total=csModified.t_total+get(csModified.behaviorSections, "diminishing", BehaviorSection()).t_total + + energySavingStartId=diminishingSection.dataPoints[end] + else + # The diminishing section is only one step. This step is removed and if there is a cruisingBeforeAcceleration section it will be combined with the new cruising section. + energySavingStartId=get(csOriginal.behaviorSections, "cruisingBeforeAcceleration", get(csOriginal.behaviorSections, "diminishing", BehaviorSection())).dataPoints[1] + end + + # copy the driving course till the beginning of energy saving + drivingCourseModified=Vector{DataPoint}() + for i in 1:energySavingStartId + push!(drivingCourseModified, DataPoint(drivingCourse[i])) # List of data points till the start of energy saving + end + + # calculate the coasting phase until the point the train needs to brake + (csModified, drivingCourseModified)=addCoastingPhaseUntilBraking!(csModified, drivingCourseModified, settings, train, allCSs) + + # calculate the moving phase between coasting and the end of the CS + if drivingCourseModified[end].v > csModified.v_exit + (csModified, drivingCourseModified)=addBrakingPhase!(csModified, drivingCourseModified, settings, train, allCSs) + elseif drivingCourseModified[end].v == csModified.v_exit && drivingCourseModified[end].s < csModified.s_end + # v_exit is already reached. Now cruise till the end of the CS + s_cruisingAfterCoasting=csModified.s_end-drivingCourseModified[end].s + (csModified, drivingCourseModified)=addCruisingPhase!(csModified, drivingCourseModified, s_cruisingAfterCoasting, settings, train, allCSs, "cruisingAfterCoasting") + end + + + if t_recoveryAvailable>=(csModified.t_total-csOriginal.t_total) + return (csModified, drivingCourseModified, true) + else # time loss is to high. so there is no energy saving modification for this CS with the available recovery time + # TODO: just return false or take smaller steps? + + return (CharacteristicSection(), [], false) + end + end + + # there is no energy saving modification for this CS with the available recovery time + return (CharacteristicSection(), [], false) + else + # there is no energy saving modification for this CS because a cruising section AND a braking section are needed to be transformed into a coasting section + return (CharacteristicSection(), [], false) + end +end # function increaseCoastingSection + +#= 12/03 old without diminishing: function increaseCoastingSection(csOriginal::CharacteristicSection, drivingCourse::Vector{DataPoint}, settings::Settings, train::Train, allCSs::Vector{CharacteristicSection}, t_recoveryAvailable::AbstractFloat) if haskey(csOriginal.behaviorSections, "cruising") && haskey(csOriginal.behaviorSections, "braking") cruisingReduction=settings.stepSize while cruisingReduction>=settings.stepSize/10^approximationLevel @@ -101,11 +309,13 @@ function increaseCoastingSection(csOriginal::CharacteristicSection, drivingCours if energySavingStartId==0 error("ERROR at creating a new driving course for energy saving with coasting !") end - # TODO: tried to insert copy on 15.07.2021 drivingCourseModified=[copy(drivingCourse[1])] + drivingCourseModified=[DataPoint(drivingCourse[1])] + # TODO: tried to insert copy on 15.07.2021 drivingCourseModified=[copy(drivingCourse[1])] for i in 2:energySavingStartId - # TODO: tried to insert copy on 15.07.2021 push!(drivingCourseModified, copy(drivingCourse[i])) # List of data points till the start of energy saving push!(drivingCourseModified, DataPoint(drivingCourse[i])) # List of data points till the start of energy saving + # TODO: tried to insert copy on 15.07.2021 push!(drivingCourseModified, copy(drivingCourse[i])) # List of data points till the start of energy saving + end # calculating the new length of the cruising section @@ -182,6 +392,7 @@ function increaseCoastingSection(csOriginal::CharacteristicSection, drivingCours end end # function increaseCoastingSection +=# # method 2 with shortening the acceleration by stepsize function decreaseMaximumVelocity(csOriginal::CharacteristicSection, drivingCourse, settings::Settings, train::Train, allCSs::Vector{CharacteristicSection}, t_recoveryAvailable::AbstractFloat) @@ -228,7 +439,7 @@ function decreaseMaximumVelocity(csOriginal::CharacteristicSection, drivingCours energySavingStartId=accelerationSection.dataPoints[end] else - # The acceleration section is only one step. This step is removed and if ther ist a cruisingBeforeAcceleration section it will be combined with the new cruising section. + # The acceleration section is only one step. This step is removed and if there is a cruisingBeforeAcceleration section it will be combined with the new cruising section. energySavingStartId=get(csOriginal.behaviorSections, "cruisingBeforeAcceleration", get(csOriginal.behaviorSections, "acceleration", BehaviorSection())).dataPoints[1] end diff --git a/src/Input.jl b/src/Input.jl index 95c14fe..2b9e41e 100644 --- a/src/Input.jl +++ b/src/Input.jl @@ -8,10 +8,10 @@ export readInput """ Read the input information from YAML files for train, path and settings, save it in different objects and return them. """ -function readInput(trainFilePath::String, pathFilePath::String, settingsFilePath::String) - train=inputTrain(trainFilePath) - path=inputPath(pathFilePath) - settings=inputSettings(settingsFilePath) +function readInput(trainDirectory::String, pathDirectory::String, settingsDirectory::String) + train=inputTrain(trainDirectory) + path=inputPath(pathDirectory) + settings=inputSettings(settingsDirectory) return (train, path, settings) end #function readInput @@ -19,8 +19,8 @@ function readInput(trainFilePath::String, pathFilePath::String, settingsFilePath """ Read the train information from a YAML file, save it in a Train object and return it. """ -function inputTrain(trainFilePath::String) - data = YAML.load(open(trainFilePath)) +function inputTrain(trainDirectory::String) + data = YAML.load(open(trainDirectory)) collect(keys(data)) collect(values(data)) @@ -56,8 +56,6 @@ function inputTrain(trainFilePath::String) end - - # speed limit: # trains speed limit (in m/s) v_limit_temp=0.0 v_limit_kmh_temp=0.0 @@ -189,11 +187,13 @@ function inputTrain(trainFilePath::String) delete!(data["train"], "rotationMassFactor_w") - # input for function tractiveEffort(v) - # TODO: Should the arrays check and the arrays copy be in the same "for" loop? + # pairs of velocity and tractive effort if haskey(data["train"],"F_T_pairs") && data["train"]["F_T_pairs"]!=nothing F_T_pairs=data["train"]["F_T_pairs"] + train.tractiveEffortVelocityPairs=checkAndDefineTractiveEffortInput(F_T_pairs, 1.0) + + #= old 2021-11-04: now it is pairs and no scope # check if the elements of the array have the correct type errorDetected=false for row in 1:length(F_T_pairs) @@ -207,17 +207,33 @@ function inputTrain(trainFilePath::String) errorDetected=true println("ERROR at reading the train yaml file: The tractive effort value of F_T_pairs in row ", row ," is no real floating point number >=0.0.") end + + if row>=2 && F_T_pairs[row][1] <= F_T_pairs[row-1][1] + errorDetected=true + println("ERROR at reading the train yaml file: The speed value of F_T_pairs in row ", row ," (v=",F_T_pairs[row][1]," m/s) is not higher than the speed value in the previous row (v=",F_T_pairs[row-1][1]," m/s).") + end end # for if errorDetected - error("ERROR at reading the train yaml file: Only real floating point number >=0.0 are allowed for speed and tractive effort.") + error("ERROR at reading the train yaml file: Only real floating point number >=0.0 are allowed for speed and tractive effort. The speed values have to be listed from low to high.") end + # create tractiveEffortVelocityPairs + if F_T_pairs[1][1]>0.0 # if there is no F_T for v=0.0, the first known value is used + push!(train.tractiveEffortVelocityPairs, [0.0, F_T_pairs[1][2]]) + println("WARNING at reading the train yaml file: The tractive effort for v=0 m/s is missing. Therefore the first given value F_T(v=",F_T_pairs[1][1]," m/s)=",F_T_pairs[1][2]," N will be used." ) + end + + for row in 1:length(F_T_pairs) + push!(train.tractiveEffortVelocityPairs, [F_T_pairs[row][1]], F_T_pairs[row][2]]) + end # for + + # create tractiveEffortArray train.tractiveEffortArray=[] if F_T_pairs[1][1]==0.0 push!(train.tractiveEffortArray, [F_T_pairs[1][1], F_T_pairs[1][1], F_T_pairs[1][2]]) elseif F_T_pairs[1][1]>0.0 # if there is no F_T for v=0.0, the first value is used - push!(train.tractiveEffortArray, [0.0, F_T_pairs[1][1]/3.6, F_T_pairs[1][2]]) + push!(train.tractiveEffortArray, [0.0, F_T_pairs[1][1], F_T_pairs[1][2]]) println("WARNING at reading the train yaml file: The tractive effort for v=0 m/s is missing. Therefore the first given value F_T(v=",F_T_pairs[1][1]," m/s)=",F_T_pairs[1][2]," N will be used." ) else error("ERROR at reading the train yaml file: There is a negative speed value in the list. Only positive values for speed and tractive effort are allowed in F_T_pairs.") @@ -234,9 +250,11 @@ function inputTrain(trainFilePath::String) error("ERROR at reading the train yaml file: The F_T_pairs are not in the correct order. They have to be arranged by speed values from low to high.") end end # for + if length(F_T_pairs[1])>2 println("INFO according the train yaml file: Only the first two columns of F_T_pairs are used in this tool.") end + =# if haskey(data["train"],"F_T_pairs_kmh") && data["train"]["F_T_pairs_kmh"]!=nothing println("WARNING at reading the train yaml file: There are values for F_T_pairs and F_T_pairs_kmh. The values for F_T_pairs are used." ) @@ -245,6 +263,9 @@ function inputTrain(trainFilePath::String) elseif haskey(data["train"],"F_T_pairs_kmh") && data["train"]["F_T_pairs_kmh"]!=nothing F_T_pairs_kmh=data["train"]["F_T_pairs_kmh"] + train.tractiveEffortVelocityPairs=checkAndDefineTractiveEffortInput(F_T_pairs_kmh, 1000/3600) + + #= old 2021-11-04: now it is pairs and no scope # check if the elements of the array have the correct type errorDetected=false for row in 1:length(F_T_pairs_kmh) @@ -285,6 +306,7 @@ function inputTrain(trainFilePath::String) if length(F_T_pairs_kmh[1])>2 println("INFO at reading the train yaml file: Only the first two columns of F_T_pairs_kmh are used in this tool.") end + =# else error("ERROR at reading the train yaml file: There has to be one of the keywords F_T_pairs or F_T_pairs_kmh filled with a list of pairs of velocity and tractive effort.") end # if @@ -398,10 +420,53 @@ function inputTrain(trainFilePath::String) return train end #function inputTrain +function checkAndDefineTractiveEffortInput(F_T_pairs, velocityMultiplier::AbstractFloat) + # TODO: check if its numbers are real ? function checkAndDefineTractiveEffortInput(F_T_pairs::Array{Array{Real,1},1}, velocityMultiplier::AbstractFloat) + # check if the elements of the array have the correct type + errorDetected=false + for row in 1:length(F_T_pairs) + if typeof(F_T_pairs[row][1]) <: Real && F_T_pairs[row][1]>=0.0 + else + errorDetected=true + println("ERROR at reading the train yaml file: The speed value of F_T_pairs in row ", row ," is no real floating point number >=0.0.") + end + if typeof(F_T_pairs[row][2]) <: Real && F_T_pairs[row][2]>=0.0 + else + errorDetected=true + println("ERROR at reading the train yaml file: The tractive effort value of F_T_pairs in row ", row ," is no real floating point number >=0.0.") + end -function inputPath(pathFilePath::String) + if row>=2 && F_T_pairs[row][1] <= F_T_pairs[row-1][1] + errorDetected=true + println("ERROR at reading the train yaml file: The speed value of F_T_pairs in row ", row ," (v=",F_T_pairs[row][1]," m/s) is not higher than the speed value in the previous row (v=",F_T_pairs[row-1][1]," m/s).") + end + end # for + if errorDetected + error("ERROR at reading the train yaml file: Only real floating point number >=0.0 are allowed for speed and tractive effort. The speed values have to be listed from low to high.") + end + + # create tractiveEffortVelocityPairs + tractiveEffortVelocityPairs=[] + if F_T_pairs[1][1]>0.0 # if there is no F_T for v=0.0, the first known value is used + push!(tractiveEffortVelocityPairs, [0.0, F_T_pairs[1][2]]) + println("WARNING at reading the train yaml file: The tractive effort for v=0 m/s is missing. Therefore the first given value F_T(v=",F_T_pairs[1][1]," m/s)=",F_T_pairs[1][2]," N will be used." ) + end + + for row in 1:length(F_T_pairs) + push!(tractiveEffortVelocityPairs, [F_T_pairs[row][1]*velocityMultiplier, F_T_pairs[row][2]]) + end # for + + + if length(F_T_pairs[1])>2 + println("INFO according the train yaml file: Only the first two columns of F_T_pairs are used in this tool.") + end + return tractiveEffortVelocityPairs +end #function checkAndDefineTractiveEffortInput + + +function inputPath(pathDirectory::String) # this function reads path information from a YAML file, saves it in a Path object and returns it - data = YAML.load(open(pathFilePath)) + data = YAML.load(open(pathDirectory)) collect(keys(data)) collect(values(data)) @@ -504,9 +569,9 @@ end # function inputPath -function inputSettings(settingsFilePath::String) +function inputSettings(settingsDirectory::String) # this function reads setting information from a YAML file, saves it in a Setting object and returns it - data = YAML.load(open(settingsFilePath)) + data = YAML.load(open(settingsDirectory)) collect(keys(data)) collect(values(data)) @@ -594,16 +659,16 @@ function inputSettings(settingsFilePath::String) # TODO: it could be checked if the path is existing on the pc if settings.typeOfOutput=="CSV" - if haskey(data["settings"],"csvFolderPath") - if typeof(data["settings"]["csvFolderPath"])==String - settings.csvFolderPath=data["settings"]["csvFolderPath"] + if haskey(data["settings"],"csvDirectory") + if typeof(data["settings"]["csvDirectory"])==String + settings.csvDirectory=data["settings"]["csvDirectory"] else - error("ERROR at reading the settings yaml file: The value of csvFolderPath is wrong. It has to be of type String.") + error("ERROR at reading the settings yaml file: The value of csvDirectory is wrong. It has to be of type String.") end else - error("ERROR at reading the settings yaml file: The keyword csvFolderPath is missing. It has to be added.") + error("ERROR at reading the settings yaml file: The keyword csvDirectory is missing. It has to be added.") end - delete!(data["settings"], "csvFolderPath") + delete!(data["settings"], "csvDirectory") end # if diff --git a/src/MovingPhases.jl b/src/MovingPhases.jl index a42376e..96e4867 100644 --- a/src/MovingPhases.jl +++ b/src/MovingPhases.jl @@ -11,16 +11,15 @@ approximationLevel = 6 # value for approximation to intersections TODO further # TODO: define it in TrainRun and give it to each function? ## functions for calculating tractive effort and resisting forces - #TODO: change tractiveEffortArray to tractiveEffortVelocityPairs ?? Currently the example doesn't fit to the function """ - calculateTractiveEffort(v, tractiveEffortArray) + calculateTractiveEffort(v, tractiveEffortVelocityPairs) -Calculate the trains tractive effort from the `tractiveEffortArray` dependend on the velocity `v`. +Calculate the trains tractive effort with the `tractiveEffortVelocityPairs` dependend on the velocity `v`. ... # Arguments - `v::AbstractFloat`: the current velocity in m/s. -- `tractiveEffortArray::Array{Array{AbstractFloat,1},1}`: the trains pairs for velocity in m/s and tractive effort in N as one array containing an array for each pair. +- `tractiveEffortVelocityPairs::Array{Array{AbstractFloat,1},1}`: the trains pairs for velocity in m/s and tractive effort in N as one array containing an array for each pair. ... # Examples @@ -32,25 +31,42 @@ julia> calculateTractiveEffort(30.0, [[0.0, 180000], [20.0, 100000], [40.0, 6000 80000 ``` """ -function calculateTractiveEffort(v::AbstractFloat, tractiveEffortArray) - for row in 1:length(tractiveEffortArray) - if tractiveEffortArray[row][1]<=v && v<=tractiveEffortArray[row][2] - return tractiveEffortArray[row][3] - elseif tractiveEffortArray[row][1]>v - if row>1 - # interpolate for a straight line between the two surrounding points with the formula: F=(v-v_(row-1))*(F_row-_(row-1))/(v_row-v_(row-1))+F_(row-1) - F_T_interpolation=(v-tractiveEffortArray[row-1][2])*(tractiveEffortArray[row][3]-tractiveEffortArray[row-1][3])/(tractiveEffortArray[row][1]-tractiveEffortArray[row-1][2])+tractiveEffortArray[row-1][3] - - return F_T_interpolation - else - return tractiveEffortArray[1][3] - end #if +function calculateTractiveEffort(v::AbstractFloat, tractiveEffortVelocityPairs) + for row in 1:length(tractiveEffortVelocityPairs) + if tractiveEffortVelocityPairs[row][1]==v + return tractiveEffortVelocityPairs[row][2] + elseif tractiveEffortVelocityPairs[row][1]>v + # interpolate for a straight line between the two surrounding points with the formula: F=(v-v_(row-1))*(F_row-F_(row-1))/(v_row-v_(row-1))+F_(row-1) + F_T_interpolation=(v-tractiveEffortVelocityPairs[row-1][1])*(tractiveEffortVelocityPairs[row][2]-tractiveEffortVelocityPairs[row-1][2])/(tractiveEffortVelocityPairs[row][1]-tractiveEffortVelocityPairs[row-1][1])+tractiveEffortVelocityPairs[row-1][2] + return F_T_interpolation end #if end #for - # if v gets higher than the velocities in tractiveEffortArray the last tractive effort will be used + # if v gets higher than the velocities in tractiveEffortVelocityPairs the last tractive effort will be used # TODO: also an extrapolation could be used - return tractiveEffortArray[end][3] + return tractiveEffortVelocityPairs[end][2] end #function calculateTractiveEffort + #= old 2021-11-04: now with easier tractiveEffortVelocityPairs than previous tractiveEffortArray + function calculateTractiveEffort(v::AbstractFloat, tractiveEffortArray) + for row in 1:length(tractiveEffortArray) + if tractiveEffortArray[row][1]<=v && v<=tractiveEffortArray[row][2] + return tractiveEffortArray[row][3] + elseif tractiveEffortArray[row][1]>v + if row>1 + # interpolate for a straight line between the two surrounding points with the formula: F=(v-v_(row-1))*(F_row-_(row-1))/(v_row-v_(row-1))+F_(row-1) + F_T_interpolation=(v-tractiveEffortArray[row-1][2])*(tractiveEffortArray[row][3]-tractiveEffortArray[row-1][3])/(tractiveEffortArray[row][1]-tractiveEffortArray[row-1][2])+tractiveEffortArray[row-1][3] + + return F_T_interpolation + else + return tractiveEffortArray[1][3] + end #if + end #if + end #for + # if v gets higher than the velocities in tractiveEffortArray the last tractive effort will be used + # TODO: also an extrapolation could be used + return tractiveEffortArray[end][3] + end #function calculateTractiveEffort + =# + #TODO: choose an explanation and replace the ? ? ? """ @@ -125,12 +141,14 @@ function calculateForces!(dataPoint::DataPoint, train::Train, massModel::String, dataPoint.F_Rp=calculatePathResistance(dataPoint.s, massModel, train, allCs) dataPoint.F_R=dataPoint.F_Runion+dataPoint.F_Rp - #calculate tractive effort - if bsType == "acceleration" - dataPoint.F_T = calculateTractiveEffort(dataPoint.v, train.tractiveEffortArray) + # calculate tractive effort + if bsType == "acceleration" || bsType == "diminishing" + # 12/03 test: if bsType == "acceleration" || bsType == "diminishing" || bsType == "maximumTraction" + # 11/21 old without diminishing: if bsType == "acceleration" + dataPoint.F_T = calculateTractiveEffort(dataPoint.v, train.tractiveEffortVelocityPairs) + # println(" F_T:",dataPoint.F_T ) elseif bsType == "cruising" - # 09/22 println("s=",dataPoint.s, " v=",dataPoint.v, " F_R=",dataPoint.F_R, " F_T=",calculateTractiveEffort(dataPoint.v, train.tractiveEffortArray)) - dataPoint.F_T = min(max(0.0, dataPoint.F_R), calculateTractiveEffort(dataPoint.v, train.tractiveEffortArray)) + dataPoint.F_T = min(max(0.0, dataPoint.F_R), calculateTractiveEffort(dataPoint.v, train.tractiveEffortVelocityPairs)) else dataPoint.F_T = 0.0 end @@ -144,6 +162,7 @@ TODO function moveAStep(previousPoint::DataPoint, stepVariable::String, stepSize::AbstractFloat, csId::Integer) # stepSize is the currentStepSize depending on the accessing function # TODO: csId is only for error messages. Should it be removed? + #= 08/31 TODO: How to check if the train stopps during this step? I should throw an error myself that I catch in higher hierarchies. =# # creating the next data point newPoint=DataPoint() @@ -156,14 +175,15 @@ function moveAStep(previousPoint::DataPoint, stepVariable::String, stepSize::Abs newPoint.Δv=0.0 # step size (in m/s) elseif stepVariable=="s in m" # distance step method newPoint.Δs=stepSize # step size (in m) - # TODO: is this if correct and necessary? - #if ((previousPoint.v/previousPoint.a)^2+2*newPoint.Δs/previousPoint.a)<0.0 || (previousPoint.v^2+2*newPoint.Δs*previousPoint.a)<0.0 # checking if the parts of the following square roots will be <0.0 - # error("ERROR: The train stops during the acceleration phase in CS",csId," because the tractive effort is lower than the resistant forces.", - # " Before the stop the last point has the values s=",previousPoint.s," m, v=",previousPoint.v," m/s, a=",previousPoint.a," m/s^2,", - # " F_T=",previousPoint.F_T," N, F_Rt=",previousPoint.F_Rt," N, F_Rw=",previousPoint.F_Rw," N, F_Rp=",previousPoint.F_Rp," N.") - #end - #= 08/31 TODO: How to check if the train stopps during this step? I should throw an error myself that I catch in higher hierarchies. - =# + # 11/21 |-> + if previousPoint.a<0.0 + if ((previousPoint.v/previousPoint.a)^2+2*newPoint.Δs/previousPoint.a)<0.0 || (previousPoint.v^2+2*newPoint.Δs*previousPoint.a)<0.0 # checking if the parts of the following square roots will be <0.0 + error("ERROR: The train stops during the acceleration phase in CS",csId," because the tractive effort is lower than the resistant forces.", + " Before the stop the last point has the values s=",previousPoint.s," m, v=",previousPoint.v," m/s, a=",previousPoint.a," m/s^2,", + " F_T=",previousPoint.F_T," N, F_Rt=",previousPoint.F_Rt," N, F_Rw=",previousPoint.F_Rw," N, F_Rp=",previousPoint.F_Rp," N.") + end + end + # 11/21 ->| newPoint.Δt=sign(previousPoint.a)*sqrt((previousPoint.v/previousPoint.a)^2+2*newPoint.Δs/previousPoint.a)-previousPoint.v/previousPoint.a # step size (in s) newPoint.Δv=sqrt(previousPoint.v^2+2*newPoint.Δs*previousPoint.a)-previousPoint.v # step size (in m/s) elseif stepVariable=="t in s" # time step method @@ -179,17 +199,12 @@ function moveAStep(previousPoint::DataPoint, stepVariable::String, stepSize::Abs newPoint.s=previousPoint.s+newPoint.Δs # position (in m) newPoint.t=previousPoint.t+newPoint.Δt # point in time (in s) newPoint.v=previousPoint.v+newPoint.Δv # velocity (in m/s) - # 08/23 the following will be checked later - #if newPoint.v<=0.0 - # error("ERROR: The train stops during the acceleration phase in CS",csId," m because the tractive effort is lower than the resistant forces.", - # " Before the stop the last point has the values s=",previousPoint.s," v=",previousPoint.v," m/s a=",previousPoint.a," m/s^2", - # " F_T=",previousPoint.F_T," N F_Rt=",previousPoint.F_Rt," N F_Rw=",previousPoint.F_Rw," N F_Rp=",previousPoint.F_Rp," N.") - #end newPoint.ΔW_T=previousPoint.F_T*newPoint.Δs # mechanical work in this step (in Ws) newPoint.W_T=previousPoint.W_T+newPoint.ΔW_T # mechanical work (in Ws) newPoint.ΔE=newPoint.ΔW_T # energy consumption in this step (in Ws) newPoint.E=previousPoint.E+newPoint.ΔE # energy consumption (in Ws) + return newPoint end #function moveAStep @@ -343,11 +358,23 @@ function addAccelerationPhase!(characteristicSection::CharacteristicSection, dri (characteristicSection, drivingCourse)=addStartingPhase!(characteristicSection, drivingCourse, settings, train, allCs) end #if + calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "acceleration") + if drivingCourse[end].F_T < drivingCourse[end].F_R + (characteristicSection, drivingCourse)=addDiminishingPhase!(characteristicSection, drivingCourse, settings, train, allCs) + drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "acceleration")) + end + # if the tail of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept formerSpeedLimits = detectFormerSpeedLimits(allCs, characteristicSection.id, drivingCourse[end], train.l_union) - if drivingCourse[end].v < characteristicSection.v_reach && drivingCourse[end].s 0.000001 && drivingCourse[end].s0.0 - - while drivingCourse[end].v0.0 - - # 09/09 new (for steep gradients "<=" is necessary but only in accelertion until braking due to Operation modes) TODO + while drivingCourse[end].v drivingCourse[end].F_R + # 12/03 old with v>0.0: while drivingCourse[end].v0.0 && drivingCourse[end].F_T > drivingCourse[end].F_R # traction effort and resisting forces (in N) - drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type)) + # 11/22 drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type)) # acceleration (in m/s^2): drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train.m_union/train.ξ_union - # if drivingCourse[end].a==0.0 - # error("ERROR: a=0 m/s^2 in the acceleration phase ! with F_T=",drivingCourse[end].F_T," F_Rt=",drivingCourse[end].F_Rt," F_Rw=",drivingCourse[end].F_Rw," F_Rp=",drivingCourse[end].F_Rp) - # end # create the next data point push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, characteristicSection.id)) push!(accelerationSection.dataPoints, drivingCourse[end].i) + # drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type)) + if length(formerSpeedLimits) > 0 # If the tail of the train is located in a former characteristic section with lower speed limit check if is is possible to accelerate as normal (characteristicSection, drivingCourse, formerSpeedLimits, accelerationSection, endOfCsReached) = considerFormerSpeedLimits!(characteristicSection, drivingCourse, settings, train, allCs, formerSpeedLimits, accelerationSection) @@ -385,6 +404,7 @@ function addAccelerationPhase!(characteristicSection::CharacteristicSection, dri end #if currentStepSize=settings.stepSize # initializing the step size that can be reduced near intersections end #if + drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type)) end #while # check which limit was reached and adjust the currentStepSize for the next cycle @@ -411,6 +431,8 @@ function addAccelerationPhase!(characteristicSection::CharacteristicSection, dri elseif drivingCourse[end].v==characteristicSection.v_reach break + elseif drivingCourse[end].F_T <= drivingCourse[end].F_R + currentStepSize = settings.stepSize / 10.0^cycle else error("ERROR at acceleration phase: With the step variable ",settings.stepVariable," the while loop will be left although vcharacteristicSection.s_end drivingCourse[end].s=characteristicSection.s_end # rounding s down to s_end + elseif drivingCourse[end].F_T <= drivingCourse[end].F_R + (characteristicSection, drivingCourse)=addDiminishingPhase!(characteristicSection, drivingCourse, settings, train, allCs) + drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type)) + else end end end #for - # if length(accelerationSection.dataPoints) > 1 # 09/09 new: it is possible that the acceleration starts at v_reach, accelerates a step, is to high and drops the last point. then there is only one data point which is not a section. | It should only be used in addAccelerationUntilBreaking! due to Operation Modes TODO + if length(accelerationSection.dataPoints) > 1 # 11/21 new: it is possible that the acceleration starts at v_reach, accelerates a step, is to high and drops the last point. then there is only one data point which is not a section. + # calculate the accumulated acceleration section information + accelerationSection.v_exit=drivingCourse[end].v # exit speed (in m/s) + accelerationSection.s_end=drivingCourse[end].s # last position (in m) + accelerationSection.s_total=accelerationSection.s_end-accelerationSection.s_start # total length (in m) + accelerationSection.t_total=drivingCourse[end].t-drivingCourse[accelerationSection.dataPoints[1]].t # total running time (in s) + accelerationSection.E_total=drivingCourse[end].E-drivingCourse[accelerationSection.dataPoints[1]].E # total energy consumption (in Ws) + characteristicSection.t_total=characteristicSection.t_total+accelerationSection.t_total # total running time (in s) + characteristicSection.E_total=characteristicSection.E_total+accelerationSection.E_total # total energy consumption (in Ws) - # calculation the accumulated acceleration section information - accelerationSection.v_exit=drivingCourse[end].v # exit speed (in m/s) - accelerationSection.s_end=drivingCourse[end].s # last position (in m) - accelerationSection.s_total=accelerationSection.s_end-accelerationSection.s_start # total length (in m) - accelerationSection.t_total=drivingCourse[end].t-drivingCourse[accelerationSection.dataPoints[1]].t # total running time (in s) - accelerationSection.E_total=drivingCourse[end].E-drivingCourse[accelerationSection.dataPoints[1]].E # total energy consumption (in Ws) - characteristicSection.t_total=characteristicSection.t_total+accelerationSection.t_total # total running time (in s) - characteristicSection.E_total=characteristicSection.E_total+accelerationSection.E_total # total energy consumption (in Ws) + # TODO: this warning schould not be needed. just for testing + if characteristicSection.v_reach < drivingCourse[end].v + println("WARNING, v is getting to high at the end of the acceleration phase. v=",drivingCourse[end].v ," > v_reach=",characteristicSection.v_reach) + end - # TODO: this warning schould not be needed. just for testing - if characteristicSection.v_reach v_reach=",characteristicSection.v_reach) + merge!(characteristicSection.behaviorSections, Dict("acceleration"=>accelerationSection)) end - - merge!(characteristicSection.behaviorSections, Dict("acceleration"=>accelerationSection)) - # end end # else: just return the given data point number without changes due to the acceleration phase return (characteristicSection, drivingCourse) @@ -468,48 +493,18 @@ function addAccelerationPhaseUntilBraking!(characteristicSection::Characteristic (characteristicSection, drivingCourse)=addStartingPhase!(characteristicSection, drivingCourse, settings, train, allCs) end #if + calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "acceleration") + if drivingCourse[end].F_T < drivingCourse[end].F_R + (characteristicSection, drivingCourse)=addDiminishingPhase!(characteristicSection, drivingCourse, settings, train, allCs) + drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "acceleration")) + end + # if the tail of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept formerSpeedLimits = detectFormerSpeedLimits(allCs, characteristicSection.id, drivingCourse[end], train.l_union) - #(formerSpeedLimits, s_cruisingBeforeAcceleration) = detectFormerSpeedLimits(allCs, characteristicSection.id, drivingCourse[end], train.l_union) - #if s_cruisingBeforeAcceleration > 0.0 - # (characteristicSection, drivingCourse)=addCruisingPhase!(characteristicSection, drivingCourse, s_cruisingBeforeAcceleration, settings, train, allCs, "cruisingBeforeAcceleration") - #else - # error("ERROR: cruisingBeforeAcceleration <=0.0 although it has to be >0.0 in CS ",csWithTrainHeadId) - #end - #= 07/30 *** TODO - # if the tail of the train is still in a former characteristic section it has to be checked if its speed limit can be kept - formerSpeedLimits=[] - if characteristicSection.id>1 && drivingCourse[end].s-train.l_union0.0 - (characteristicSection, drivingCourse)=addCruisingPhase!(characteristicSection, drivingCourse, s_cruisingBeforeAcceleration, settings, train, allCs, "cruisingBeforeAcceleration") - else - error("ERROR: cruisingBeforeAcceleration <=0.0 although it has to be >0.0 in CS ",characteristicSection.id) - end - else # detecting the lower speed limits of former sections - csId=characteristicSection.id-1 - while csId>0 && drivingCourse[end].s-train.l_unionF_R: if drivingCourse[end].v < characteristicSection.v_reach && drivingCourse[end].s drivingCourse[end].F_R accelerationSection=BehaviorSection() accelerationSection.type="acceleration" # type of behavior section accelerationSection.s_start=drivingCourse[end].s # first position (in m) @@ -517,24 +512,23 @@ function addAccelerationPhaseUntilBraking!(characteristicSection::Characteristic push!(accelerationSection.dataPoints, drivingCourse[end].i) currentStepSize=settings.stepSize # initializing the step size that can be reduced near intersections - # 08/23 : old for cycle in 1:5 # first cycle with normal step size, second cycle with reduced step size, third cycle with more reduced step size. fourth and fith are needed in case the velocity approaches 0.0 or v_reach for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation s_braking=max(0.0, ceil((characteristicSection.v_exit^2-drivingCourse[end].v^2)/2/train.a_braking, digits=approximationLevel)) - while drivingCourse[end].v <= characteristicSection.v_reach && drivingCourse[end].s+s_braking0.0 # as long as s_i + s_braking < s_CSend - # 09/09 old (for steep gradients <= is necessary): while drivingCourse[end].v0.0 # as long as s_i + s_braking < s_CSend + while drivingCourse[end].v < characteristicSection.v_reach && drivingCourse[end].s+s_braking drivingCourse[end].F_R # as long as s_i + s_braking < s_CSend + # 12/03 old with v>0 while drivingCourse[end].v < characteristicSection.v_reach && drivingCourse[end].s+s_braking0.0 && drivingCourse[end].F_T > drivingCourse[end].F_R # as long as s_i + s_braking < s_CSend - - drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type)) + #11/22 drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type)) # acceleration (in m/s^2): drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train.m_union/train.ξ_union - if drivingCourse[end].a==0.0 - error("ERROR: a=0 m/s^2 in the acceleration phase ! with F_T=",drivingCourse[end].F_T," F_Rt=",drivingCourse[end].F_Rt," F_Rw=",drivingCourse[end].F_Rw," F_Rp=",drivingCourse[end].F_Rp) - end + # if drivingCourse[end].a==0.0 + # error("ERROR: a=0 m/s^2 in the acceleration phase ! with F_T=",drivingCourse[end].F_T," F_Rt=",drivingCourse[end].F_Rt," F_Rw=",drivingCourse[end].F_Rw," F_Rp=",drivingCourse[end].F_Rp) + # end # create the next data point push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, characteristicSection.id)) push!(accelerationSection.dataPoints, drivingCourse[end].i) + # 12/03: was moved behind considerFormerSpeedLimits: drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type)) if length(formerSpeedLimits) > 0 # If the tail of the train is located in a former characteristic section with lower speed limit check if is is possible to accelerate as normal (characteristicSection, drivingCourse, formerSpeedLimits, accelerationSection, endOfCsReached) = considerFormerSpeedLimits!(characteristicSection, drivingCourse, settings, train, allCs, formerSpeedLimits, accelerationSection) @@ -542,7 +536,7 @@ function addAccelerationPhaseUntilBraking!(characteristicSection::Characteristic return (characteristicSection, drivingCourse) end end - + drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type)) s_braking=max(0.0, ceil((characteristicSection.v_exit^2-drivingCourse[end].v^2)/2/train.a_braking, digits=approximationLevel)) end #while @@ -567,6 +561,9 @@ function addAccelerationPhaseUntilBraking!(characteristicSection::Characteristic elseif drivingCourse[end].v==characteristicSection.v_reach break + elseif drivingCourse[end].F_T <= drivingCourse[end].F_R + currentStepSize = settings.stepSize / 10.0^cycle + else error("ERROR at acceleration until braking phase: With the step variable ",settings.stepVariable," the while loop will be left although v characteristicSection.s_end pop!(drivingCourse) pop!(accelerationSection.dataPoints) + + elseif drivingCourse[end].F_T <= drivingCourse[end].F_R + (characteristicSection, drivingCourse)=addDiminishingPhase!(characteristicSection, drivingCourse, settings, train, allCs) + drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, accelerationSection.type)) + else end @@ -594,7 +596,7 @@ function addAccelerationPhaseUntilBraking!(characteristicSection::Characteristic end #for if length(accelerationSection.dataPoints) > 1 # 09/09 new: it is possible that the acceleration starts at v_reach, accelerates a step, is to high and drops the last point. then there is only one data point which is not a section. - # calculation the accumulated acceleration section information + # calculate the accumulated acceleration section information accelerationSection.v_exit=drivingCourse[end].v # exit speed (in m/s) accelerationSection.s_end=drivingCourse[end].s # last position (in m) accelerationSection.s_total=accelerationSection.s_end-accelerationSection.s_start # total length (in m) @@ -615,11 +617,20 @@ end #function addAccelerationPhaseUntilBraking! ## This function calculates the data points of the cruising phase. # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for cruising if needed. function addCruisingPhase!(characteristicSection::CharacteristicSection, drivingCourse::Vector{DataPoint}, s_cruising::AbstractFloat, settings::Settings, train::Train, allCs::Vector{CharacteristicSection}, cruisingType::String) - if drivingCourse[end].v>0.0 && drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s0.0 && drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s= drivingCourse[end].F_R + # 11/22 old: if drivingCourse[end].v>0.0 && drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s 1 && drivingCourse[end].s < allCs[characteristicSection.id].s_start + train.l_union)) && drivingCourse[end].v>0.0 #&& drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s 1 + currentStepSize=settings.stepSize + for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation + while drivingCourse[end].s < characteristicSection.s_start + train.l_union && drivingCourse[end].s=drivingCourse[end].F_R #&& drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s=drivingCourse[end].F_R #&& drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s= drivingCourse[end].F_R # acceleration (in m/s^2): drivingCourse[end].a=0.0 # create the next data point - push!(drivingCourse, moveAStep(drivingCourse[end], "s_cruising in m", train.l_union/(10.0^cycle), characteristicSection.id)) # TODO welche Schrittweite nehm ich hier? - push!(cruisingSection.dataPoints, drivingCourse[end].i) - else - # acceleration (in m/s^2): - drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train.m_union/train.ξ_union - - # create the next data point - push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, characteristicSection.id)) - push!(cruisingSection.dataPoints, drivingCourse[end].i) - end - - - - # traction effort and resisting forces (in N) - drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "cruising")) - end #while - - # check which limit was reached and adjust the currentStepSize for the next cycle - if cycle < approximationLevel+1 - if drivingCourse[end].v<=0.0 - currentStepSize = settings.stepSize / 10.0^cycle - - elseif drivingCourse[end].s>cruisingSection.s_start+s_cruising # TODO also the following? drivingCourse[end].s > allCs[characteristicSection.id].s_start + train.l_union)) - if settings.stepVariable == "s in m" - currentStepSize=cruisingSection.s_start+s_cruising-drivingCourse[end-1].s + if settings.stepVariable=="s in m" + push!(drivingCourse, moveAStep(drivingCourse[end], "s_cruising in m", currentStepSize, characteristicSection.id)) else - currentStepSize = settings.stepSize / 10.0^cycle + push!(drivingCourse, moveAStep(drivingCourse[end], "s_cruising in m", train.l_union/(10.0^cycle), characteristicSection.id)) # TODO which step size should be used? end - - #elseif drivingCourse[end].s>characteristicSection.s_end #TODO: is this necesaary if s_cruising is known? # now s_cruising will be limited to the end of CS at the beginning of this function - # if settings.stepVariable == "s in m" - # currentStepSize=characteristicSection.s_end-drivingCourse[end-1].s - # else - # currentStepSize = settings.stepSize / 10.0^cycle - # end - - #elseif drivingCourse[end].v>characteristicSection.v_reach # copied from addAccelerationPhase. TODO is it necessary for homogeneous strip? #TODO: now, the train can't get faster in the cruising section. so v_reach can not be exceeded - # if settings.stepVariable=="v in m/s" - # currentStepSize=characteristicSection.v_reach-drivingCourse[end-1].v - # else - # currentStepSize = settings.stepSize / 10.0^cycle - # end - - elseif drivingCourse[end].s==cruisingSection.s_start+s_cruising # || drivingCourse[end].s==characteristicSection.s_end - break - - #elseif drivingCourse[end].v==characteristicSection.v_reach # copied from addAccelerationPhase. TODO 08/24 should it be used otherwise for homogeneous strip? - # break - - elseif drivingCourse[end].F_T>=drivingCourse[end].F_R # TODO should not be necessary: && (settings.massModel=="mass point" || characteristicSection.id == 1 || drivingCourse[end].s >= allCs[characteristicSection.id].s_start+train.l_union) - drivingCourse[end].a=0.0 # acceleration (in m/s^2) - - # calculate the remaining cruising way - s_cruisingRemaining=cruisingSection.s_start+s_cruising-drivingCourse[end].s - - # create the next data point - push!(drivingCourse, moveAStep(drivingCourse[end], "s_cruising in m", s_cruisingRemaining, characteristicSection.id)) push!(cruisingSection.dataPoints, drivingCourse[end].i) - break - - else # TODO copied from addAccelerationPhase -> probably not needed here !? - error("ERROR at cruising phase: With the step variable ",settings.stepVariable," the while loop will be left although the if cases don't apply in CS",characteristicSection.id," with s=" ,drivingCourse[end].s," m and v=",drivingCourse[end].v," m/s") - end - # delete last data point for recalculating the last step with reduced step size - pop!(drivingCourse) - pop!(cruisingSection.dataPoints) - - else # if the level of approximation is reached - if drivingCourse[end].v<=0.0 # copied from addAccelerationPhase TODO: change error message? - error("ERROR: The train stops during the cruising phase in CS",characteristicSection.id," because the tractive effort is lower than the resistant forces.", - " Before the stop the last point has the values s=",drivingCourse[end-1].s," m v=",drivingCourse[end-1].v," m/s a=",drivingCourse[end-1].a," m/s^2", - " F_T=",drivingCourse[end-1].F_T," N F_Rt=",drivingCourse[end-1].F_Rt," N F_Rw=",drivingCourse[end-1].F_Rw," N F_Rp=",drivingCourse[end-1].F_Rp," N.") - #elseif drivingCourse[end].v > characteristicSection.v_reach # copied from addAccelerationPhase. TODO is it necessary for homogeneous strip? - # pop!(drivingCourse) - # pop!(cruisingSection.dataPoints) - #elseif drivingCourse[end].s>characteristicSection.s_end - # drivingCourse[end].s=characteristicSection.s_end # round s down to s_end - - elseif drivingCourse[end].s>cruisingSection.s_start+s_cruising - - if cruisingSection.type == "cruisingBeforeAcceleration" - else - pop!(drivingCourse) - pop!(cruisingSection.dataPoints) + # for testing + if drivingCourse[end].F_T > drivingCourse[end].F_R && drivingCourse[end].F_R > 0.0 + error("In the cruising phase of CS",cruisingSection.id,": F_T=",drivingCourse[end].F_T," != F_R=",drivingCourse[end].F_R) end - - elseif drivingCourse[end].F_T>=drivingCourse[end].F_R # TODO should not be necessary: && (settings.massModel=="mass point" || characteristicSection.id == 1 || drivingCourse[end].s >= allCs[characteristicSection.id].s_start + train.l_union) - # it is calculated the same as for the other cycles - drivingCourse[end].a=0.0 # acceleration (in m/s^2) - - # calculate the remaining cruising way - s_cruisingRemaining=cruisingSection.s_start+s_cruising-drivingCourse[end].s - - # create the next data point - push!(drivingCourse, moveAStep(drivingCourse[end], "s_cruising in m", s_cruisingRemaining, characteristicSection.id)) - push!(cruisingSection.dataPoints, drivingCourse[end].i) - break - else - - end - end - end #for - - #= 09/21 old. homogenous strip has to be added - if drivingCourse[end].F_T>=drivingCourse[end].F_R - drivingCourse[end].a=0.0 # acceleration (in m/s^2) - - push!(drivingCourse, DataPoint()) - drivingCourse[end].i=drivingCourse[end-1].i+1 # incrementing the number of the data point - push!(cruisingSection.dataPoints, drivingCourse[end].i) - - # calculate s, t, v, E - drivingCourse[end].Δs=min(s_cruising, characteristicSection.s_end-drivingCourse[end-1].s) # step size (in m) - drivingCourse[end].Δt=drivingCourse[end].Δs/drivingCourse[end-1].v # step size (in s) - drivingCourse[end].Δv=0.0 # step size (in m/s) - # TODO moveAStep can not be used at the moment because of 1/a in the formulars. It has to be changed and then used with stepVariable="s in m", stepSize=min(s_cruising, characteristicSection.s_end-drivingCourse[end-1].s) -> see the three lines above - - drivingCourse[end].s=drivingCourse[end-1].s+drivingCourse[end].Δs # position (in m) - drivingCourse[end].t=drivingCourse[end-1].t+drivingCourse[end].Δt # point in time (in s) - drivingCourse[end].v=drivingCourse[end-1].v # velocity (in m/s) - - drivingCourse[end].ΔW_T=drivingCourse[end-1].F_T*drivingCourse[end].Δs # mechanical work in this step (in Ws) - drivingCourse[end].W_T=drivingCourse[end-1].W_T+drivingCourse[end].ΔW_T # mechanical work (in Ws) - drivingCourse[end].ΔE=drivingCourse[end].ΔW_T # energy consumption in this step (in Ws) - drivingCourse[end].E=drivingCourse[end-1].E+drivingCourse[end].ΔE # energy consumption (in Ws) - - - else # the tractive effort is lower than the resisiting forces and the train has use the highest possible effort to try to stay at v_reach - currentStepSize=settings.stepSize - - for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation - while drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s0.0 # TODO: <= v_reach was inserted -> probably needed for homogeneous strip - # traction effort and resisting forces (in N) - drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "cruising")) - - # acceleration (in m/s^2): - drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train.m_union/train.ξ_union - if drivingCourse[end].a==0.0 - # TODO: this part is important for mass strip - end - - # create the next data point - push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, characteristicSection.id)) - push!(cruisingSection.dataPoints, drivingCourse[end].i) - - #= TODO: the following has probably to be considered with homogeneous strip: - if length(formerSpeedLimits) > 0 # If the tail of the train is located in a former characteristic section with lower speed limit check if is is possible to accelerate as normal - (characteristicSection, drivingCourse, formerSpeedLimits, cruisingSection, endOfCsReached) = considerFormerSpeedLimits!(characteristicSection, drivingCourse, settings, train, allCs, formerSpeedLimits, accelerationSection) - - if endOfCsReached - return (characteristicSection, drivingCourse) - end #if - end #if - =# + calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "cruising") end #while # check which limit was reached and adjust the currentStepSize for the next cycle if cycle < approximationLevel+1 - if drivingCourse[end].v<=0.0 - currentStepSize = settings.stepSize / 10.0^cycle - - elseif drivingCourse[end].s>characteristicSection.s_end + if drivingCourse[end].s>cruisingSection.s_start+s_cruising # TODO also the following? drivingCourse[end].s > allCs[characteristicSection.id].s_start + train.l_union)) if settings.stepVariable == "s in m" - currentStepSize=characteristicSection.s_end-drivingCourse[end-1].s + currentStepSize=cruisingSection.s_start+s_cruising-drivingCourse[end-1].s else currentStepSize = settings.stepSize / 10.0^cycle end - - elseif drivingCourse[end].v>characteristicSection.v_reach # copied from addAccelerationPhase. TODO is it necessary for homogeneous strip? - if settings.stepVariable=="v in m/s" - currentStepSize=characteristicSection.v_reach-drivingCourse[end-1].v - else - currentStepSize = settings.stepSize / 10.0^cycle - end - - elseif drivingCourse[end].s==characteristicSection.s_end + elseif drivingCourse[end].s==cruisingSection.s_start+s_cruising # || drivingCourse[end].s==characteristicSection.s_end + break + elseif drivingCourse[end].F_T < drivingCourse[end].F_R + # if settings.stepVariable == "s in m" + # currentStepSize=cruisingSection.s_start+s_cruising-drivingCourse[end-1].s + # else + currentStepSize = settings.stepSize / 10.0^cycle + # end + elseif drivingCourse[end].s >= characteristicSection.s_start + train.l_union + # TODO: whithout allCs should work as well, no? elseif drivingCourse[end].s >= allCs[characteristicSection.id].s_start + train.l_union break - - #elseif drivingCourse[end].v==characteristicSection.v_reach # copied from addAccelerationPhase. TODO should it be used otherwise for homogeneous strip? - # break - else # TODO copied from addAccelerationPhase -> probably not needed here !? - error("ERROR at cruising phase: With the step variable ",settings.stepVariable," the while loop will be left although v characteristicSection.v_reach # copied from addAccelerationPhase. TODO is it necessary for homogeneous strip? - pop!(drivingCourse) - pop!(cruisingSection.dataPoints) - elseif drivingCourse[end].s>characteristicSection.s_end - drivingCourse[end].s=characteristicSection.s_end # round s down to s_end + if drivingCourse[end].s>cruisingSection.s_start+s_cruising + if cruisingSection.type == "cruisingBeforeAcceleration" + else + pop!(drivingCourse) + pop!(cruisingSection.dataPoints) + end + # 11/21 |-> + elseif drivingCourse[end].s==cruisingSection.s_start+s_cruising + break + # 11/21 ->| + elseif drivingCourse[end].F_T < drivingCourse[end].F_R + + (characteristicSection, drivingCourse)=addDiminishingPhase!(characteristicSection, drivingCourse, settings, train, allCs) + drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "cruising")) + + # s_cruising=max(0.0, s_cruising-get(characteristicSection.behaviorSections, "diminishing", BehaviorSection()).s_total) + else end end end #for - end - =# + end #if + + # TODO oder soll das lieber nach oben in den else des letzten Durchlaufs. Noch mal genauer ansehen, ob hier was doppelt gemoppelt ist + # if drivingCourse[end].s= drivingCourse[end].F_R + drivingCourse[end].a=0.0 # acceleration (in m/s^2) + + # calculate the remaining cruising way + s_cruisingRemaining=cruisingSection.s_start+s_cruising-drivingCourse[end].s + + # create the next data point + push!(drivingCourse, moveAStep(drivingCourse[end], "s_cruising in m", s_cruisingRemaining, characteristicSection.id)) + push!(cruisingSection.dataPoints, drivingCourse[end].i) + end - # 08/24 old push!(cruisingSection.dataPoints, drivingCourse[end].i) ## new 09/06 TODO: if no acceleration is following the cruising it could be called cruising #if cruisingSection.type == "cruisingBeforeAcceleration" && drivingCourse[end].s == characteristicSection.s_end # cruisingSection.type = "cruising" #end - # calculation the accumulated cruising section information - cruisingSection.v_exit=drivingCourse[end].v # exit speed (in m/s) - cruisingSection.s_total=cruisingSection.s_end-cruisingSection.s_start # total length (in m) + # calculate the accumulated cruising section information + cruisingSection.v_exit=drivingCourse[end].v # exit speed (in m/s) + cruisingSection.s_end=drivingCourse[end].s # last position (in m) + cruisingSection.s_total=cruisingSection.s_end-cruisingSection.s_start # total length (in m) cruisingSection.t_total=drivingCourse[end].t-drivingCourse[cruisingSection.dataPoints[1]].t # total running time (in s) cruisingSection.E_total=drivingCourse[end].E-drivingCourse[cruisingSection.dataPoints[1]].E # total energy consumption (in Ws) @@ -976,7 +859,7 @@ function addCoastingPhaseUntilBraking!(characteristicSection::CharacteristicSect end end #for - # calculation the accumulated coasting section information + # calculate the accumulated coasting section information coastingSection.v_exit=drivingCourse[end].v # exit speed (in m/s) coastingSection.s_end=drivingCourse[end].s # last position (in m) coastingSection.s_total=coastingSection.s_end-coastingSection.s_start # total length (in m) @@ -1062,9 +945,7 @@ function addBrakingPhaseStepwise!(characteristicSection::CharacteristicSection, currentStepSize=settings.stepSize # initializing the step size that can be reduced near intersections velocityIsPositive=true - # println("Bremsphase") while drivingCourse[end].v>characteristicSection.v_exit && drivingCourse[end].s < characteristicSection.s_end && velocityIsPositive - # println(" while-Durchlauf mit v=",drivingCourse[end].v," und v_exit=",characteristicSection.v_exit) # traction effort and resisting forces (in N): drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, brakingSection.type)) @@ -1096,7 +977,7 @@ function addBrakingPhaseStepwise!(characteristicSection::CharacteristicSection, #drivingCourse[end-1].a=round((drivingCourse[end].v^2-drivingCourse[end-1].v^2)/2/drivingCourse[end].Δs, digits=approximationLevel) # acceleration (in m/s^2) (rounding because it should not be less than a_braking) drivingCourse[end-1].a=(drivingCourse[end].v^2-drivingCourse[end-1].v^2)/2/drivingCourse[end].Δs # acceleration (in m/s^2) - println("a_braking_last=",drivingCourse[end-1].a," m/s^2 und a_braking_standard=" , train.a_braking) + # println("a_braking_last=",drivingCourse[end-1].a," m/s^2 und a_braking_standard=" , train.a_braking) # if drivingCourse[end-1].a=0.0 # println("Warning: a_braking gets to high in CS ",characteristicSection.id, " with a=",drivingCourse[end-1].a ," > ",train.a_braking) @@ -1114,7 +995,7 @@ function addBrakingPhaseStepwise!(characteristicSection::CharacteristicSection, end - # calculation the accumulated coasting section information + # calculate the accumulated coasting section information brakingSection.v_exit=drivingCourse[end].v # exit speed (in m/s) brakingSection.s_end=drivingCourse[end].s # last position (in m) brakingSection.s_total=brakingSection.s_end-brakingSection.s_start # total length (in m) @@ -1130,4 +1011,99 @@ function addBrakingPhaseStepwise!(characteristicSection::CharacteristicSection, end #function addBrakingPhaseStepwise! +## This function calculates the data points for diminishing run when using maximum tractive effort and still getting slower +function addDiminishingPhase!(characteristicSection::CharacteristicSection, drivingCourse::Vector{DataPoint}, settings::Settings, train::Train, allCs::Vector{CharacteristicSection}) + drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, "diminishing")) + + if drivingCourse[end].F_T <= drivingCourse[end].F_R && drivingCourse[end].v > 0.0 && drivingCourse[end].s0.0 && drivingCourse[end].v<=characteristicSection.v_reach && drivingCourse[end].s0.0 # as long as s_i + s_braking < s_CSend + # 11/22 old without F_T<=F_R while drivingCourse[end].s+s_braking0.0 # as long as s_i + s_braking < s_CSend + + #11/22 drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, diminishingSection.type)) + + # acceleration (in m/s^2): + drivingCourse[end].a=(drivingCourse[end].F_T-drivingCourse[end].F_R)/train.m_union/train.ξ_union + # 11/21: old, only for cruising: + #if drivingCourse[end].a==0.0 + # error("ERROR: a=0 m/s^2 in the diminishing phase ! with F_T=",drivingCourse[end].F_T," F_Rt=",drivingCourse[end].F_Rt," F_Rw=",drivingCourse[end].F_Rw," F_Rp=",drivingCourse[end].F_Rp) + #end + + # create the next data point + push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, characteristicSection.id)) + push!(diminishingSection.dataPoints, drivingCourse[end].i) + + s_braking=max(0.0, ceil((characteristicSection.v_exit^2-drivingCourse[end].v^2)/2/train.a_braking, digits=approximationLevel)) + drivingCourse[end]=DataPoint(calculateForces!(drivingCourse[end], train, settings.massModel, allCs, diminishingSection.type)) + end #while + + # check which limit was reached and adjust the currentStepSize for the next cycle + if cycle < approximationLevel+1 + if drivingCourse[end].v<=0.0 + currentStepSize = settings.stepSize / 10.0^cycle + + elseif drivingCourse[end].s + s_braking > characteristicSection.s_end + currentStepSize = settings.stepSize / 10.0^cycle + + elseif drivingCourse[end].s + s_braking==characteristicSection.s_end + # 11/21 old without s_braking: elseif drivingCourse[end].s==characteristicSection.s_end + break + + elseif drivingCourse[end].F_T > drivingCourse[end].F_R + currentStepSize = settings.stepSize / 10.0^cycle + + else + error("ERROR during diminishing run: With the step variable ",settings.stepVariable," the while loop will be left although s+s_braking0.0 in CS",characteristicSection.id," with s=" ,drivingCourse[end].s," m and v=",drivingCourse[end].v," m/s") + end + # delete last data point for recalculating the last step with reduced step size + pop!(drivingCourse) + pop!(diminishingSection.dataPoints) + + else # if the level of approximation is reached + if drivingCourse[end].v<=0.0 + # push!(diminishingSection.dataPoints, drivingCourse[end].i) + error("ERROR: The train stops during diminishing run in CS",characteristicSection.id," because the maximum tractive effort is lower than the resistant forces.", + " Before the stop the last point has the values s=",drivingCourse[end-1].s," m v=",drivingCourse[end-1].v," m/s a=",drivingCourse[end-1].a," m/s^2", + " F_T=",drivingCourse[end-1].F_T," N F_Rt=",drivingCourse[end-1].F_Rt," N F_Rw=",drivingCourse[end-1].F_Rw," N F_Rp=",drivingCourse[end-1].F_Rp," N.") + + elseif drivingCourse[end].s + s_braking > characteristicSection.s_end + pop!(drivingCourse) + pop!(diminishingSection.dataPoints) + + elseif drivingCourse[end].F_T > drivingCourse[end].F_R + break + + else + + end + end + end #for + + if length(diminishingSection.dataPoints) > 1 # TODO: necessary? May it be possible that there is no diminishing because braking has to start + # calculate the accumulated diminishing section information + diminishingSection.v_exit=drivingCourse[end].v # exit speed (in m/s) + diminishingSection.s_end=drivingCourse[end].s # last position (in m) + diminishingSection.s_total=diminishingSection.s_end-diminishingSection.s_start # total length (in m) + diminishingSection.t_total=drivingCourse[end].t-drivingCourse[diminishingSection.dataPoints[1]].t # total running time (in s) + diminishingSection.E_total=drivingCourse[end].E-drivingCourse[diminishingSection.dataPoints[1]].E # total energy consumption (in Ws) + characteristicSection.t_total=characteristicSection.t_total+diminishingSection.t_total # total running time (in s) + characteristicSection.E_total=characteristicSection.E_total+diminishingSection.E_total # total energy consumption (in Ws) + + merge!(characteristicSection.behaviorSections, Dict("diminishing"=>diminishingSection)) + end + end + + return (characteristicSection, drivingCourse) +end #function addDiminishingPhase! + end #module MovingPhases diff --git a/src/OperationModes.jl b/src/OperationModes.jl index 0bf9202..565218f 100644 --- a/src/OperationModes.jl +++ b/src/OperationModes.jl @@ -11,13 +11,15 @@ export simulateMinimumRunningTime!, simulateMinimumEnergyConsumption approximationLevel = 6 # TODO: define it in TrainRun and give it to each function? + # simulate a train run focussing on using the minimum possible running time function simulateMinimumRunningTime!(movingSection::MovingSection, settings::Settings, train::Train) - # simulate a train run focussing on using the minimum possible running time +# CSs=movingSection.characteristicSections startingPoint=DataPoint() startingPoint.i=1 startingPoint.s=movingSection.characteristicSections[1].s_start drivingCourse=[startingPoint] # List of data points + # for CS in CSs for csId in 1:length(movingSection.characteristicSections) # println("CS",csId) # check if the CS has a cruising section @@ -33,6 +35,7 @@ function simulateMinimumRunningTime!(movingSection::MovingSection, settings::Set delete!(movingSection.characteristicSections[csId].behaviorSections, "starting") delete!(movingSection.characteristicSections[csId].behaviorSections, "cruisingBeforeAcceleration") delete!(movingSection.characteristicSections[csId].behaviorSections, "acceleration") + delete!(movingSection.characteristicSections[csId].behaviorSections, "diminishing") # 11/22 added new delete!(movingSection.characteristicSections[csId].behaviorSections, "cruising") movingSection.characteristicSections[csId].E_total=0.0 movingSection.characteristicSections[csId].t_total=0.0 @@ -98,7 +101,7 @@ end #function simulateMinimumRunningTime function simulateMinimumEnergyConsumption(movingSectionMinimumRunningTime::MovingSection, drivingCourseMinimumRunningTime::Vector{DataPoint}, settings::Settings, train::Train) -# simulate a train run focussing on using the minimum possible energy consumption + # simulate a train run focussing on using the minimum possible energy consumption # booleans for choosing which methods are used for saving energy doMethod1=true #doMethod1=false diff --git a/src/Output.jl b/src/Output.jl index 389c2b1..aa1f473 100644 --- a/src/Output.jl +++ b/src/Output.jl @@ -112,13 +112,13 @@ function createOutputCsv(settings::Settings, pathName::String, trainName::String outputArray="outputArrayMinimumEnergyConsumption" date = Dates.now() dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS") - csvFilePath=settings.csvFolderPath*"\\"*dateString*"_MinimumEnergyConsumption.csv" + csvFilePath=settings.csvDirectory*"\\"*dateString*"_MinimumEnergyConsumption.csv" else operationMode="minimum running time" outputArray="outputArrayMinimumRunningTime" date = Dates.now() dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS") - csvFilePath=settings.csvFolderPath*"\\"*dateString*"_MinimumRunningTime.csv" + csvFilePath=settings.csvDirectory*"\\"*dateString*"_MinimumRunningTime.csv" end # creating information block @@ -144,7 +144,7 @@ function createOutputCsv(settings::Settings, pathName::String, trainName::String end # for - # combining the columns in a data frame and saving it as a CSV-file at csvFolderPath + # combining the columns in a data frame and saving it as a CSV-file at csvDirectory if settings.detailOfOutput=="reduced" df=DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3]) elseif settings.detailOfOutput=="driving course" @@ -187,7 +187,7 @@ function createOutputCsv(settings::Settings, pathName::String, trainName::String push!(allColumns, infoColumns[column]) end # for - #combining the columns in a data frame and saving it as a CSV-file at csvFolderPath + #combining the columns in a data frame and saving it as a CSV-file at csvDirectory if settings.detailOfOutput=="reduced" df=DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3]) elseif settings.detailOfOutput=="driving course" @@ -195,7 +195,7 @@ function createOutputCsv(settings::Settings, pathName::String, trainName::String end date = Dates.now() dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS") - csvFilePath=settings.csvFolderPath*"\\"*dateString*"_dataMinimumRunningTime.csv" + csvFilePath=settings.csvDirectory*"\\"*dateString*"_dataMinimumRunningTime.csv" CSV.write(csvFilePath, df, header=false) println("The output CSV file has been created for minimum running time at ",csvFilePath) end #if settings.operationModeMinimumRunningTime @@ -232,10 +232,10 @@ function createOutputCsv(settings::Settings, pathName::String, trainName::String df=DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11], c12=allColumns[12], c13=allColumns[13], c14=allColumns[14], c15=allColumns[15], c16=allColumns[16], c17=allColumns[17], c18=allColumns[18]) end - # creating a CSV-file at csvFolderPath + # creating a CSV-file at csvDirectory date = Dates.now() dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS") - csvFilePath=settings.csvFolderPath*"\\"*dateString*"_dataMinimumEnergyConsumption.csv" + csvFilePath=settings.csvDirectory*"\\"*dateString*"_dataMinimumEnergyConsumption.csv" CSV.write(csvFilePath, df, header=false) println("The output CSV file has been created for minimum energy consumption at ",csvFilePath) end # if settings.operationModeMinimumEnergyConsumption @@ -255,7 +255,7 @@ end #function printImportantValues function printSectionInformation(movingSection::MovingSection) println("MS mit s_total=", movingSection.s_total," mit t_total=", movingSection.t_total) - allBs=["starting", "cruisingBeforeAcceleration","acceleration", "cruising", "coasting","cruisingAfterCoasting", "braking"] + allBs=["starting", "cruisingBeforeAcceleration","acceleration", "cruising", "diminishing", "coasting","cruisingAfterCoasting", "braking"] for csId in 1:length(movingSection.characteristicSections) println("CS ",csId," mit s_total=", movingSection.characteristicSections[csId].s_total," mit t_total=", movingSection.characteristicSections[csId].t_total) for bs in 1: length(allBs) diff --git a/src/TrainRun.jl b/src/TrainRun.jl index ff8fd27..40265ff 100644 --- a/src/TrainRun.jl +++ b/src/TrainRun.jl @@ -19,9 +19,9 @@ export calculateDrivingDynamics # TODO: define it here and give it to each function? (MovingPhases, EnergySaving) """ - calculateDrivingDynamics(trainFilePath::String, pathFilePath::String, settingsFilePath::String) + calculateDrivingDynamics(trainDirectory::String, pathDirectory::String, settingsDirectory::String) -Calculate the driving dynamics of a train run on a path with special settings with information from the corresponding YAML files with the file paths `trainFilePath`, `pathFilePath`, `settingsFilePath`. +Calculate the driving dynamics of a train run on a path with special settings with information from the corresponding YAML files with the file paths `trainDirectory`, `pathDirectory`, `settingsDirectory`. # Examples ```julia-repl @@ -29,11 +29,11 @@ julia> calculateDrivingDynamics(C:\\folder\\train.yaml, C:\\folder\\path.yaml, C todo !!! ``` """ -function calculateDrivingDynamics(trainFilePath::String, pathFilePath::String, settingsFilePath::String) +function calculateDrivingDynamics(trainDirectory::String, pathDirectory::String, settingsDirectory::String) print("\n\n\n") # input - (train, path, settings)=readInput(trainFilePath, pathFilePath, settingsFilePath) + (train, path, settings)=readInput(trainDirectory, pathDirectory, settingsDirectory) println("The input has been saved.") @@ -53,7 +53,7 @@ function calculateDrivingDynamics(trainFilePath::String, pathFilePath::String, s if settings.operationModeMinimumEnergyConsumption==true (movingSectionMinimumEnergyConsumption, drivingCourseMinimumEnergyConsumption)=simulateMinimumEnergyConsumption(movingSectionMinimumRunningTime, drivingCourseMinimumRunningTime, settings, train) # printSectionInformation(movingSectionMinimumEnergyConsumption) - println("The driving course for lowest the energy consumption has been calculated.") + println("The driving course for the lowest energy consumption has been calculated.") end #if #output diff --git a/src/types.jl b/src/types.jl index adea213..b7fef80 100644 --- a/src/types.jl +++ b/src/types.jl @@ -11,7 +11,7 @@ mutable struct Settings operationModeMinimumEnergyConsumption::Bool # operation mode "minimum energy consumption" # output: typeOfOutput::String # output as "julia dictionary" or as "CSV" - csvFolderPath::String # path of the folder in which the CSV fiiles willl be saved + csvDirectory::String # directory in which the CSV files will be saved detailOfOutput::String # detail of output "reduced" or "everything" end # mutable struct Settings Settings()=Settings("", "", 0.0, false, false, "", "", "") @@ -26,8 +26,10 @@ mutable struct Train v_limit::AbstractFloat # trains speed limit (in m/s) a_braking::AbstractFloat # braking acceleration (in m/s^2) m_union::AbstractFloat # total mass (in kg) + # m_train ξ_union::AbstractFloat # rotation mass factor of the whole train union (without unit) # if not available use ξ_t and ξ_w + # ξ_train # traction unit m_t::AbstractFloat # mass of the traction unit (in kg) @@ -35,7 +37,7 @@ mutable struct Train m_tc::AbstractFloat # mass on the traction units carrying axles (in kg) ξ_t::AbstractFloat # rotation mass factor of the traction unit (without unit) # in case ξ_union is not available - tractiveEffortArray # list values for tractive effort (in [m/s , N]) + tractiveEffortVelocityPairs # list of velocities and their corresponding tractive effort (in [m/s , N]) f_Rtd0::AbstractFloat # coefficient for basic resistance due to the traction units driving axles (in ‰) f_Rtc0::AbstractFloat # coefficient for basic resistance due to the traction units carring axles (in ‰) @@ -89,15 +91,21 @@ mutable struct DataPoint Δv::AbstractFloat # step size (in m/s) a::AbstractFloat # acceleration (in m/s^2) W_T::AbstractFloat # mechanical work (in Ws) + # W ΔW_T::AbstractFloat # mechanical work in this step (in Ws) + # ΔW E::AbstractFloat # energy consumption (in Ws) ΔE::AbstractFloat # energy consumption in this step (in Ws) F_T::AbstractFloat # tractive effort (in N) F_R::AbstractFloat # resisting force (in N) - F_Rp::AbstractFloat # line resistanc (in N) - F_Runion::AbstractFloat # vehicle resistance (in N) + F_Rp::AbstractFloat # path resistance (in N) + # R_path + F_Runion::AbstractFloat # train resistance (in N) + # R_train F_Rt::AbstractFloat # traction unit resistance (in N) + # R_traction F_Rw::AbstractFloat # set of wagons resistance (in N) + # R_consist end # mutable struct DataPoint DataPoint()=DataPoint(0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) # tried to insert copy on 15.07.2021 copy(original::DataPoint)=DataPoint(original.i, original.s, original.Δs, original.t, original.Δt, original.v, original.Δv, original.a, original.W_T, original.ΔW_T, original.E, original.ΔE, original.F_T, original.F_R, original.F_Rp, original.F_Runion, original.F_Rt, original.F_Rw) @@ -109,6 +117,7 @@ DataPoint(original::DataPoint)=DataPoint(original.i, original.s, original.Δs, o ## smallest section of the path is the behavior section. It relates to the containing data points via their identifier. mutable struct BehaviorSection type::String # type of behavior section: "starting", "cruisingBeforeAcceleration", "acceleration", "cruising", "coasting", "cruisingAfterCoasting" or "braking" + # enum-type. breakFree, clearing, diminishing, standStill, "acceleration", "cruising", "coasting", "braking" s_total::AbstractFloat # total length (in m) s_start::AbstractFloat # first position (in m) s_end::AbstractFloat # last position (in m) @@ -131,15 +140,21 @@ end mutable struct CharacteristicSection id::Integer # identifier s_total::AbstractFloat # total length (in m) + # length::AbstractFloat # total length (in m) s_start::AbstractFloat # first position (in m) + # s_entry s_end::AbstractFloat # last position (in m) + # s_exit t_total::AbstractFloat # total running time (in s) + # t E_total::AbstractFloat # total energy consumption (in Ws) + # E v_limit::AbstractFloat # speed limit (in m/s) v_reach::AbstractFloat # maximum reachable speed (in m/s) + # v_target v_entry::AbstractFloat # maximum entry speed (in m/s) v_exit::AbstractFloat # maximum exit speed (in m/s) - f_Rp::AbstractFloat # spedific line resistance (in ‰) + f_Rp::AbstractFloat # spedific path resistance (in ‰) behaviorSections::AbstractDict{String, BehaviorSection} # list of containing behavior sections end # mutable struct CharacteristicSection CharacteristicSection()=CharacteristicSection(0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Dict{String, BehaviorSection}())