Exercise 2
In this exercise, you will try to use FMT to answer different questions about a strategic model and a tactical model through a re-planning process.
Thus, this exercise will teach you to:
- Create a re-planning script
- Re-plan with multiple models, and varying special FMT keywords
- Analyze re-planning results to answer different questions
To do this exercise, you must have FMT installed on your computer, along with the example files from the FMT GitHub repository.
You must also have Python installed on your computer. If this is not done, refer to this page.
Part 1: Creating a re-planning script
Replanner.py
script which is in the “Examples” folder you downloaded, in the /Python/replanning
folder.
The re-planning process often involves running many models, many times (to make iterations).
It is therefore very useful to create a Python script that can be called through a console, a terminal, or a command prompt.
Even better : it is possible to create a Python script that will read arguments given to it when it is called with the command prompt. This will allow to re-use this script for different re-planning scenarios or purposes.
Try to create the following script in Python language:
- Importing
Models
,Parser
,Core
,Version
andParallel
fromFMT
. - Read the following arguments (it is recommended to use the
argparse
module)-pri
which specifies the location of the primary file of the models that will be used-str
which indicates the name of the strategic scenario-tac
which indicates the name of the tactical scenario-sto
which indicates the name of the stochastic scenario-out
indicates a comma-separated list of output values of interest to be extracted from the model results-fol
which indicates the folder where the output files of the script will be put-rep
which indicates the number of iterations/replicas to do-len
which indicates the number of periods of the strategic model-rel
which indicates the number of periods over which the re-planning will be done-thr
which indicates the number of CPU cores to use for parallelization
Next, the script will need to:
- Read the model via the primary file
- Read the different scenarios
- Create the strategic/global model using the scenario name provided by
-str
.- Make the global model run for the duration provided by
-len
. - Make the global model use the number of threads given by
-thr
for parallel resolution
- Make the global model run for the duration provided by
- Create the stochastic model using the scenario name provided by
-sto
.- Make the stochastic model run for one period
- Create the tactical model using the scenario name provided by
-tac
.- Make the tactical model run for one period
- Make the global model use the number of threads specified by
-thr
for parallel resolution
- Add the outputs selected by the
-out
argument in a list from the model outputs - Prepare the re-planning task through the
Parallel.FMTreplanningtask()
function by providing to the function :- The strategic model
- The stochastic model
- The tactical model
- The list of desired outputs
- The folder where the outputs will be put
- The format of the outputs (here,
.csv
) - All other arguments needed for the function
- Run the rescheduling task through the
Parallel.FMTtaskhandler()
function
When you are done, or if you are stuck, you can view the correction of this exercise for Python code by clicking on the “Reveal correction” button below.
Reveal correction
from FMT import Models
from FMT import Parser
from FMT import Core
from FMT import Version
from FMT import Parallel
import os,argparse
if __name__ == "__main__":
ap = argparse.ArgumentParser()
ap.add_argument("-pri", "--primary", required=True,help="Fichier primaire")
ap.add_argument("-str", "--strategic", required=True,help="Nom du scenario strategique")
ap.add_argument("-tac", "--tactic", required=True,help="Nom du scenario tactique")
ap.add_argument("-sto", "--stochastic", required=True,help="Nom du scenario stochastique")
ap.add_argument("-out", "--outputs", required=True,help="Liste d'outputs separe d'une virgule")
ap.add_argument("-fol", "--folder", required=True,help="Dossier de sortie")
ap.add_argument("-rep", "--replicates", required=True,help="Nombre de replicas")
ap.add_argument("-len", "--strategiclength", required=True,help="Nombre de periode du strategique")
ap.add_argument("-rel", "--replanninglength", required=True,help="Nombre de periode de re-plannification")
ap.add_argument("-thr", "--threads", required=True,help="Nombre de threads")
ap.add_argument("-com","--compresstime", nargs="+",help="Compress time sous la forme 20,5 40,8")
args = vars(ap.parse_args())
if Version.FMTversion().hasfeature("OSI"):
modelparser = Parser.FMTmodelparser()
path = args["primary"]
scenarios = [args["strategic"],args["stochastic"],args["tactic"]]
models = modelparser.readproject(path, scenarios)
globalmodel = Models.FMTlpmodel(models[0], Models.FMTsolverinterface.CLP)
globalmodel.setparameter(Models.FMTintmodelparameters.LENGTH,int(args["strategiclength"]))
globalmodel.setparameter(Models.FMTintmodelparameters.NUMBER_OF_THREADS,1)
if "com" in args:
for firstperiod,value in [tuple(int(cmpt.split(",")[0]),float(cmpt.split(",")[1])) for cmpt in args["com"]]:
globalmodel.setcompresstime(firstperiod,int(args["strategiclength"]),value)
stochastic = Models.FMTnssmodel(models[1],0)
stochastic.setparameter(Models.FMTintmodelparameters.LENGTH, 1)
localmodel = Models.FMTlpmodel(models[2], Models.FMTsolverinterface.CLP)
localmodel.setparameter(Models.FMTintmodelparameters.LENGTH, 1)
localmodel.setparameter(Models.FMTintmodelparameters.NUMBER_OF_THREADS,1)
selectedoutputs=[]
for output in globalmodel.getoutputs():
if output.getname() in args["outputs"].split(","):
selectedoutputs.append(output)
outputlocation = args["folder"]
layersoptions=["SEPARATOR=SEMICOLON"]
replanningtask=Parallel.FMTreplanningtask(globalmodel,stochastic, localmodel, selectedoutputs, outputlocation, "CSV", layersoptions,int(args["replicates"]),int(args["replanninglength"]),0.5, Core.FMToutputlevel.totalonly)
handler = Parallel.FMTtaskhandler(replanningtask,int(args["threads"]))
handler.setquietlogger()
handler.conccurentrun()
else:
print("FMT needs to be compiled with OSI")
Part 2: Creation of scenarios for re-planning
Preparation
After downloading the FMT example files (see above), open the folder Models/TWD_land/Scenarios/Globalex1
.
This Globalex1
scenario is a scenario that we will use as strategic model or global model.
Take time to look at the contents of its files; in particular, look at its actions, objectives and constraints.
Do the same with the Localex1
model, which we will use as the tactical model or local model
Question 1
Open a windows command prompt, or a powershell. Use the command cd
to go to the Examples/Python/replanning
folder. Then use the following command to start re-planning:
python Replanner.py -pri ../../Models/TWD_land/TWD_land.pri -str Globalex1 -tac Localex1 -sto Globalnofire -out OVOLREC,OSUPREC,OSUPPL,VOLINVENT -fol replanning_EX1 -rep 10 -len 20 -rel 20 -thr 2
This command tells the script created in the first part that we want to :
- Use the model found at
../../Models/TWD_land/TWD_land.pri
- Use the scenario
Globalx1
as a strategic model - Use the
Localex1
scenario as a tactical model - Use the
Globalnofire
scenario as a stocastic model - Create output tables for the
OVOLREC
,OSUPREC
,OSUPPL
, andVOLINVENT
outputs - Put these tables in the
replanning_EX1
folder - Make 10 iterations
- Solve the strategic model for 20 periods
- Do the re-plannification on 20 periods
- Use 2 CPU cores to make iterations in parallel
Once the command has run, look at the output in the Examples/Python/replanning/replanning_EX1
folder.
With a stock-out tolerance of 5%, what is the probability of holding OVOLREC
until period 10 in the tactical model?
Reveal correction
To look at the probability of keeping OVOLREC
above a 5% value drop, we just have to look at the outputsdrift.csv
file. This file shows us the probability that the different outputs selected in the tactical model remain above or below a certain distance (drift) from the strategic model.
We can open the file, and go to the lines that concern OVOLREC
and a drift of 0.05
(5%), namely lines 462-481.
Looking at these rows, we can see that from period 7 onwards, OVOLREC
has a probability of 0
of not falling by more than 5% compared to the strategic model (third column LowerProbability
); this probability remains at 0 for all subsequent periods. Thus, it appears that the probability of keeping OVOLREC
above a 5% decline until period 10 is 0.
These values can be represented with a graph via the data in outputsdrift.csv
:
Question 2
Now duplicate the Globalex1
folder and rename it Globalex2
(delete the existing folder if it already exists).
Then modify the TWD_land.opt
file of Globalex2
to force the Globalex2
scenario not to exceed 20,000 m³ for the OVOLREC
output.
Reveal correction
The content of TWD_land.opt
of the Globalex2
scenario should then be :
*OBJECTIVE
_MAXMIN oVolRec 1.._LENGTH
*EXCLUDE
aCaribou 1.._LENGTH
afire 1.._LENGTH
arecup 1.._LENGTH
*CONSTRAINTS
oVolRec<= 20000 1.._LENGTH
_NDY(oVolRec) 1.._LENGTH
*FORMAT MOSEK
Then run a re-planning with the strategic model Globalex2
and the tactical model Localex1
, with the following command:
python Replanner.py -pri ../../Models/TWD_land/TWD_land.pri -str Globalex2 -tac Localex1 -sto Globalnofire -out OVOLREC,OSUPREC,OSUPPL,VOLINVENT -fol replanning_EX2 -rep 10 -len 20 -rel 20 -thr 2
Once the command has run, look at the output in the Examples/Python/replanning/replanning_EX2
folder.
With a stock-out tolerance of 5%, what is the probability of holding OVOLREC
until period 10 in the tactical model?
Is there a gain from question 1?
Reveal correction
Looking at the results of outputsdrift.csv
, we can see that OVOLREC
keeps a probability of 1
of not decreasing more than 5% throughout the 20 periods. Thus, there is a maximum probability that OVOLREC
will stay above a 5% decline in the tactical model Localex1
, when using the strategic model Globalex2
.
We have a clear gain on question 1, for which OVOLREC
could not stay above a 5% decline from the 7th period. This is probably due to the fact that Globalex2
was forced not to harvest too much, which made it easier to maintain this level in Localex1
.
Question 3
Now duplicate the Localex1
folder and rename it Localex3
(delete the existing folder if it already exists).
Then modify the TWD_land.opt
file of Localex3
to force this tactical model to follow the solution of the strategic model with a weight of 1000, using the keyword _SETGLOBALSCHEDULE(weight)
.
Reveal correction
The content of TWD_land.opt
of the Localex3
scenario should then be :
*OBJECTIVE
_MAX ovolrec 1.._LENGTH _SETGLOBALSCHEDULE(100)
*EXCLUDE
aCaribou 1.._LENGTH
afire 1.._LENGTH
arecup 1.._LENGTH
*CONSTRAINTS
oVolRec<= 40272 1.._LENGTH _SETFROMGLOBAL(1)
*FORMAT MOSEK
Then run a re-planning with the strategic model Globalex1
and the tactical model Localex3
, with the following command:
python Replanner.py -pri ../../Models/TWD_land/TWD_land.pri -str Globalex1 -tac Localex3 -sto Globalnofire -out OVOLREC,OSUPREC,OSUPPL,VOLINVENT -fol replanning_EX3 -rep 10 -len 20 -rel 20 -thr 2
Once the command has run, look at the output in the Examples/Python/replanning/replanning_EX3
folder.
With a stock-out tolerance of 5%, what is the probability of holding OVOLREC
until period 10 in the tactical model?
Is there a gain from question 1?
Reveal correction
Looking at the results of outputsdrift.csv
in Examples/Python/replanning/replanning_EX3
, we can see that OVOLREC
has a probability of 1
of not falling more than 5% from the strategic model in period 8; but that this probability changes to 0
from period 9 onwards, and remains at 0
for all other periods. Thus, it is certain that OVOLREC
will not stay above a 5% decline until period 10.
However, we can still observe a slight gain from question 1; the probability that OVOLREC
will not decrease by more than 5% dropped to 0
as early as period 7 in these results. By pushing the tactical model to follow the solution of the strategic model with the keyword _SETGLOBALSCHEDULE(weight)
, we thus gained two more periods of stability!
Question 4
Now duplicate the TWD_land._opt
file from Localex1
to the Localex4
folder (delete the existing file if it already exists).
Then modify the TWD_land.opt
file in Localex4
to force the tactical model to follow the replica tables (PEUPLEMENT1.csv
and PEUPLEMENT2.csv
) for harvesting in the stands peuplement1 and peuplement2 (use _REPLICATE()
. In doing so, you must force the tactical model to do a certain level of harvesting in particular spatial features of the model (peuplement1 and peuplement2) based on files you provide to the model (PEUPLEMENT1.csv
and PEUPLEMENT2.csv
).
Reveal correction
The content of TWD_land.opt
of the Localex4
scenario should then be :
*OBJECTIVE
_MAX ovolrec - _Penalty(_All) 1.._LENGTH
*EXCLUDE
aCaribou 1.._LENGTH
afire 1.._LENGTH
arecup 1.._LENGTH
*CONSTRAINTS
oVolRec<= 40272 1.._LENGTH _SETFROMGLOBAL(1)
oVolRecPEUPLEMENT1 <= 0 1.._LENGTH _Goal(G1,9999) _REPLICATE(PEUPLEMENT1.csv)
oVolRecPEUPLEMENT1 >= 0 1.._LENGTH _Goal(G2,9999) _REPLICATE(PEUPLEMENT1.csv)
oVolRecPEUPLEMENT2 <= 0 1.._LENGTH _Goal(G3,9999) _REPLICATE(PEUPLEMENT2.csv)
oVolRecPEUPLEMENT2 >= 0 1.._LENGTH _Goal(G4,9999) _REPLICATE(PEUPLEMENT2.csv)
*FORMAT MOSEK
Then run a re-planning with the strategic model Globalex1
and the tactical model Localex4
, with the following command:
python Replanner.py -pri ../../Models/TWD_land/TWD_land.pri -str Globalex1 -tac Localex4 -sto Globalnofire -out OVOLREC,OSUPREC,OSUPPL,VOLINVENT,OVOLRECPEUPLEMENT1,OVOLRECPEUPLEMENT2 -fol replanning_EX4 -rep 10 -len 20 -rel 20 -thr 2
Once the command has run, go to the Localex4.csv
file in the EX4_Scheduling
folder, and look at the results of the OVOLRECPEUPLEMENT1
and OVOLRECPEUPLEMENT2
outputs. In particular, you can create a pivot table in a program such as Microsoft Excel to obtain a graph showing the evolution of these measures over time, with a curve for each iteration.
At the same time, open the files PEUPLEMENT1.csv
and PEUPLEMENT2.csv
, and observe their contents. Each column corresponds to values that the tactical model was supposed to use for a iteration, with each row containing a value for a given period.
When comparing the contents of Localex4.csv
and PEUPLEMENT1.csv
and PEUPLEMENT2.csv
, what do you observe?
Reveal correction
We can see that the tactical model has indeed followed the harvest levels defined in the PEUPLEMENT1.csv
and PEUPLEMENT2.csv
files for the output OVOLREC
in stands 1 and 2.
In particular, we can see that OVOLRECPEUPLEMENT1
drops to 0 for period 4 in all iterations, as expected in PEUPLEMENT1.csv
. We can also see that iteration 4 keeps a value of OVOLRECPEUPLEMENT1
at 10 most of the time, while the other iterations keep a value of 20.
We can observe a drop to 0 for OVOLRECPEUPLEMENT2
at period 9 in all iterations, as expected in PEUPLEMENT2.csv
.
Question 5
Now duplicate the Localex1
folder and rename it Localex5
(delete the existing folder if it already exists).
Then modify the TWD_land.opt
file of Localex5
to force this tactical model to ignore the 90-100ha planting constraint from period (or to follow it only in period 1) using the keyword _REIGNORE(period)
.
Reveal correction
The content of TWD_land.opt
of the Localex5
scenario should then be :
*OBJECTIVE
_MAX ovolrec - _Penalty(_All) 1.._LENGTH
*EXCLUDE
aCaribou 1.._LENGTH
afire 1.._LENGTH
arecup 1.._LENGTH
*CONSTRAINTS
oVolRec<= 40272 1.._LENGTH _SETFROMGLOBAL(1)
osuppl >= 90 1 _Goal(G1,9999) _REIGNORE(2)
osuppl <= 100 1 _Goal(G2,9999) _REIGNORE(2)
*FORMAT MOSEK
Then run a re-planning with the strategic model Globalex1
and the tactical model Localex5
, with the following command:
python Replanner.py -pri ../../Models/TWD_land/TWD_land.pri -str Globalex1 -tac Localex5 -sto Globalnofire -out OVOLREC,OSUPREC,OSUPPL,VOLINVENT -fol replanning_EX5 -rep 10 -len 20 -rel 20 -thr 2
Once the command has run, compare the evolution of the planting level output OSUPPL
in the tactical model Localex1
(in the planning_EX1
folder created in question 1) with the evolution of OSUPPL
in the tactical model Localex5
(in the planning_EX5
folder). As before, you can use a pivot table in a program like Microsoft Excel to obtain a graph showing the evolution of these measures over time, with a curve for each of the iterations.
What differences do you observe between Localex1
and Localex5
?
Reveal correction
We can see that the tactical model Localex1
manages to sustain the level of OSUPPL
for a long time in a stable way, as shown on this graph:
In comparison, in Localex5
, we can see that the level of OSUPPL
is much more variable and unstable. It quickly reaches values of 0, due to the fact that the model constraints on it are ignored after period 2, as shown on this graph:
Hence, it seems that the local model did ignore the constraints OSUPPL
.
Question 6
Now duplicate the Localex1
folder and rename it Localex6
(delete the existing folder if it already exists).
Then modify the TWD_land.opt
file of Localex6
to force this tactical model to achieve 100% of the harvest level (OVOLREC
) of the strategic model, with a 1% variability allowed for exceeding the value (so at least 100%, and at most 101%) with the keyword _SETFROMGLOBAL(weight)
.
Reveal correction
The content of TWD_land.opt
of the Localex6
scenario should then be :
*OBJECTIVE
_MAX ovolrec - _Penalty(_All) 1.._LENGTH
*EXCLUDE
aCaribou 1.._LENGTH
afire 1.._LENGTH
arecup 1.._LENGTH
*CONSTRAINTS
oVolRec<= 40272 1.._LENGTH _SETFROMGLOBAL(1)
osuprec <= 40272 1.._LENGTH _Goal(G1,9999) _SETFROMGLOBAL(1.0)
osuprec >= 40272 1.._LENGTH _Goal(G2,9999) _SETFROMGLOBAL(0.99)
*FORMAT MOSEK
Then run a re-plannibg with the strategic model Globalex1
and the tactical model Localex6
, with the following command:
python Replanner.py -pri ../../Models/TWD_land/TWD_land.pri -str Globalex1 -tac Localex6 -sto Globalnofire -out OVOLREC,OSUPREC,OSUPPL,VOLINVENT -fol replanning_EX6 -rep 10 -len 20 -rel 20 -thr 2
Once the command has run, look at the output in the Examples/Python/replanning/replanning_EX6
folder.
Now compare the probability of maintaining a similar harvest as in Exercise 1 (with Localex1
) by looking at the contents of outputsdrift.csv
in replanning_EX1
and replanning_EX6
.
What differences do you observe?
Reveal correction
We observe that the probability of maintaining OVOLREC
in the tactical model above a 5% decrease with respect to the strategic model is relatively similar between Localex1
and Localex6
; except that Localex6
has a lower value of this probability at period 7, when it drops towards 0.
Question 7
Now duplicate the Globalex1
folder and rename it Globalex7
(delete the existing folder if it already exists).
Then modify the TWD_land.opt
file of Globalex7
to force the Globalex7
scenario to achieve at least 99% of the OVOLREC
harvest level of the tactical model.
Reveal correction
The content of TWD_land.opt
of the Globalex7
scenario should then be :
*OBJECTIVE
_MAXMIN oVolRec - _Penalty(_All) 1.._LENGTH
*EXCLUDE
aCaribou 1.._LENGTH
afire 1.._LENGTH
arecup 1.._LENGTH
*CONSTRAINTS
osuprec <= 40272 1.._LENGTH _Goal(G1,9999) _SETFROMLOCAL(1.0)
osuprec >= 40272 1.._LENGTH _Goal(G2,9999) _SETFROMLOCAL(0.99)
_NDY(oVolRec) 1.._LENGTH
*FORMAT MOSEK
Then run a re-planning with the strategic model Globalex7
and the tactical model Localex1
, with the following command:
python Replanner.py -pri ../../Models/TWD_land/TWD_land.pri -str Globalex7 -tac Localex1 -sto Globalnofire -out OVOLREC,OSUPREC,OSUPPL,VOLINVENT -fol replanning_EX7 -rep 10 -len 20 -rel 20 -thr 2
Once the command has run, look at the output in the Examples/Python/replanning/replanning_EX7
folder.
Now observe how the planting levels (output OSSUPL
) compare between those of question 1, and those of this re-planning by looking at the outputsdrift.csv
files of replanning_EX1
and replanning_EX7
.
How does the maintenance of the level of OSSUPL
compare to question 1?
Reveal correction
It can be seen that for question 1 and this question, OSSUPL
keeps a very low probability of maintaining itself from a large decrease from the first periods when comparing the tactical and strategic model.
However, even for very high drift values (e.g. 50%), we can see that OSSUPL
tends to have a higher probability of greatly decreasing its value with Globalex7
than with Globalex1
.