Objets, lecture et interrogation de modèles
Que sont les objets ?
FMT est fabriqué avec une structure particulière appelée Programmation orientée objet (POO). Si vous n’en avez jamais entendu parler, en voici un résumé très rapide pour mieux comprendre comment utiliser FMT.
Dans l’approche POO ou Object oriented programming en anglais (OOP), le programme utilise différents “objets” qui ont une certaine “classe” et qui peuvent avoir différentes “fonctions”.
Vous connaissez et utilisez peut-être déjà des fonctions dans des logiciels tels que “R”. Par exemple, dans R, plot()
est une fonction.
Vous pourriez également être habitué.e à certains objets et classes dans le logiciel que vous utilisez. Par exemple, dans R
, data<-read.csv (données.csv)
met le contenu des données.fichier csv
dans l’objet data
, qui a la classe data frame
.
Maintenant, imaginez que chaque fonction que vous utilisez est associée à un objet d’une classe particulière. Par exemple, une classe chien
aurait la fonction aboyer_sur()
. Si nous avons une classe nommée chat
, nous pourrions alors :
- Créer un nouvel objet
chien
de la classechien
:pluto = chien(nom = Pluto, age = 8)
- Créer un nouvel objet
chat
à partir de la classechat
:felix = chat(nom = Felix, age = 2)
- Faire aboyer le chien sur le chat:
pluto.aboyer_sur(felix)
À son tour, l’objet peut avoir des “propriétés”, qui sont exactement ce à quoi cela ressemble. Par exemple, disons que notre classe chat
a trois propriétés : nom
(qui peut être une chaîne de caractères), age
(qui peut être un nombre) et effrayé
(qui est un booléen, true
ou false
).
Dans notre exemple précédent, avant d’utiliser pluto.aboyer_sur(felix)
, la propriété felix.peur
pouvait être false
. Mais maintenant que nous avons utilisé pluto.aboyer_sur(felix)
, felix.peur
s’est surement changé en true
.
Enfin, une classe parent en programmation orientée objet signifie que la classe enfant héritera automatiquement de toutes les fonctions et propriétés de la fonction parent.
Par exemple, supposons que nous ayons une classe parent animal
dont dérivent les classes chien
et chat
. Si la classe animal
a une fonction respiration
(animal.respiration()
), alors les classes chien
et chat
étant ses classes enfant, elles auront automatiquement cette fonction (chien.respiration()
) et chat.respiration()
).
La programmation orientée objet est une façon particulière de programmer, intégrée dans le langage de programmation que vous utilisez, qui présente de multiples avantages. L’un d’eux est de rendre les choses plus faciles à représenter.
En bref : FMT utilise la programmation orientée objet, ce qui fait de tout un objet avec des fonctions particulières. Les fonctions et propriétés d’un objet sont définies par sa classe.
Pour apprendre à utiliser FMT, vous apprendrez quelles sont ses classes principales, afin que vous puissiez créer les objets dont vous avez besoin et les faire interagir pour faire les choses que vous voulez faire. En effet, que ce soit en Python, R ou C ++, utiliser FMT signifie utiliser ses différents objets.
Les namespaces de FMT
Les différentes classes d’objets dans FMT sont regroupées en espaces de noms (namespaces), qui sont simplement les différentes sections de ses fichiers.
Dans FMT, les différents espaces de noms sont :
Parser
: Contient des classes utilisées pour lire ou éditer les fichiers des modèles au format WoodstockModels
: Contient des classes utilisées pour manipuler et résoudre les modèlesSpatial
: Contient des classes utilisées pour travailler sur des données spatialement explicitesHeuristics
: Contient les heuristiques utilisées pour agréger spatialement les blocs de coupes et les planifier dans le tempsVersion
: Contient des informations sur la version actuelle de FMT, et les fonctions qu’elle contient (ce qui dépend de la façon dont il a été compilée)
Classes importantes de l’espace de noms Parser
L’espace de noms Parser
contient deux classes importantes pour la lecture des modèles :
FMTareaparser
: Permet la lecture et l’écriture des fichiers raster et vectoriels utilisés dans les opérations spatiales de FMT- Certaines de ses fonctions vous permettent de transformer des données entre le format vectoriel et le format raster.
FMTmodelparser
: Permet de lire les fichiers d’un modèle Woodstock avec la fonctionread project()
, ou de l’enregistrer avec la fonctionwrite()
après l’avoir modifié.- La classe utilise également d’autres classes faites pour lire les fichiers Woodstock.
La classe FMTmodel
La classe FMTmodel
est la base de FMT.
Elle contient des informations provenant des fichiers des modèles au format Woodstock. Cela peut être vu en regardant les propriétés du FMTmodel
:
Cependant, ces attributs sont “protégés” afin qu’ils ne soient pas modifiés de manière incorrecte. Si vous souhaitez les lire lors de l’utilisation de FMT, vous devrez utiliser les fonctions getter qui les obtiendront pour vous :
De plus, vous pouvez les modifier de la bonne manière en utilisant les fonctions setter. Cela vous permet d’éditer différentes parties du modèle.
En fin de compte, le FMTModel
est ce que nous appelons une classe parent pour toutes les différentes classes de modèles utilisées par FMT, telles que FMTlpmodel
(modèle de programmation linéaire) et FMTsesmodel
(modèle spatialement explicite) selon le diagramme suivant :
classDiagram
FMTobject <|-- FMTmodel
FMTmodel <|-- FMTsemodel
FMTsemodel <|-- FMTsamodel
FMTsemodel <|-- FMTsesmodel
FMTmodel <|-- FMTsrmodel
FMTsrmodel <|-- FMTlpmodel
FMTsrmodel <|-- FMTnssmodel
Observez que toutes ces classes héritent finalement de la classe FMTobject
. C’est le cas pour chaque objet de FMT, car FMTobject
contient des fonctions et des propriétés utiles pour déboguer FMT.
Les modèles FMTnssmodel
et FMTlpmodel
sont des modèles référencés spatialement FMTsrmodel
. Le FMTlpmodel
est utilisé pour l’optimisation, tandis que FMTnssmodel
est utilisé pour la simulation.
En contraste, les modèles FMTsesmodel
et FMTsamodel
sont des modèles spatialement explicites FMTsemodel
. De la même manière, FMTsamodel
est utilisé pour l’optimisation, tandis que FMTsesmodel
est utilisé pour la simulation.
Nous examinerons de plus près les différents types de modèles plus tard. Pour l’instant, nous n’utiliserons que le modèle le plus simple qui correspond le plus à une structure de modèle de Woodstock, le FMTlpmodel
.
Lire un simple FMTlpmodel
Voici un exemple qui permet de lire un modèle de programmation linéaire (au format Woodstock) avec FMT.
En R, le code pour correspondant serait :
library(FMT) # Charge FMT dans R
if (new(FMTversion)$hasfeature("OSI")) # Vérifie si FMT a été compilé avec OSI en créant un nouvel objet FMTversion, et en utilisant la fonction hasfeature().
{
# Créer un objet parser pour lire les fichiers du modèle
newmodelparser <- new(FMTmodelparser)
# Lit le projet avec le parser en spécifiant que l'on veut lire le scénario "LP" (il peut y avoir différents scénarios dans un seul modèle)
modelslist <- newmodelparser$readproject("Models/TWD_land/TWD_land.pri", c("LP"), TRUE, TRUE, TRUE)
model_scenario_lp <- modelslist[[1]]
# On récupère le nom du modèle
print(model_scen_lp$getname())
} else { # Si le modèle n'as pas été compilé avec OSI, on affiche une erreur
print("FMT needs to be compiled with OSI")
}
Dans Python, le même code aurait la forme suivante :
import sys
from FMT import Models
from FMT import Parser
from FMT import Version
if __name__ == "__main__":
if Version.FMTversion().hasfeature("OSI"): # Vérifie si FMT a été compilé avec OSI en utilisant la fonction hasfeature() de la classe FMTversion.
# Créer un objet parser pour lire les fichiers du modèle
newmodelparser= Parser.FMTmodelparser()
path = "Models/TWD_Land/TWD_Land.pri"
scenarios = ["LP"]
# Lit le projet avec le parser en spécifiant que l'on veut lire le scénario "LP" (il peut y avoir différents scénarios dans un seul modèle)
modelslist = newmodelparser.readproject(path, scenarios)
model_scen_lp = modelslist[0]
# On récupère le nom du modèle
print(model_scen_lp.getname())
else:
# Si le modèle n'as pas été compilé avec OSI, on affiche une erreur
print("FMT needs to be compiled with OSI")
Que ce soit dans le terminal de R ou de Python, les codes précédents devraient affichier la même chose :
Reading Models/TWD_land/TWD_land.pri
FMT 0.9.1, build: Sep 30 2021 12:07:49
Tue Oct 05 10:59:57 2021
Reading Scenario Lp
FMTexc(39)Undefined _death action: _DEATH FMTsection(4)Action
FMTexc(40)Undefined _death transition: _DEATH FMTsection(5)Transition
Done reading Tue Oct 05 10:59:57 2021
[1] "LP"
Comme on peut le voir, FMT indique qu’il a lu le scénario “LP”, et il affiche son nom.
L’espace de noms Core
.
L’espace de nom Core
contient les éléments utilisés par FMT “sous le capot” pour faire fonctionner l’objet FMTModel
.
Par exemple, il contient les objets :
FMTaction
: Classe qui définit l’opérabilité de plusieurs strates pour une perturbation donnée.FMTtransition
: Classe qui définit les transitions de strates multiples pour une perturbation donnée.FMTyields
: Classe qui définit les valeurs de croissance et de rendement pour chaque strate.FMToutputs
: Classe qui définit les sorties dans le modèle (inventaire ou action), mais pas les sorties du modèle (par exemple, les fichiers de sortie ou autres).FMTconstraints
: Classe qui définit les contraintes globales et l’objectif du modèle (par exemple, la variable à optimiser).
Ces différents objets peuvent être appelés depuis un objet FMTmodel
avec les différentes fonctions getter.
Par exemple, pour voir la liste des objets FMTaction
associés à un FMTmodel
particulier, vous pouvez utiliser la fonction FMTModel.getactions()
(ou FMTModel$getactions()
en R), et utiliser une boucle for
pour afficher toutes les actions dans le modèle. Les actions affichées de cette manière correspondront aux actions présentes dans le fichier .act
des fichiers Woodstock pour le modèle.
Voici un exemple qui affiche les actions et les transitions d’un FMTmodel
en code R :
library(FMT) # Charge FMT dans R
if (new(FMTversion)$hasfeature("OSI")) # Vérifier si FMT a été compilé avec OSI en créant un nouvel objet FMTversion, et en utilisant la fonction hasfeature().
{
# Créer un objet parser pour lire les fichiers du modèle
newmodelparser <- new(FMTmodelparser)
# Lit le projet avec le parser en spécifiant que l'on veut lire le scénario "LP" (il peut y avoir différents scénarios dans un seul modèle)
modelslist <- newmodelparser$readproject("Models/TWD_land/TWD_land.pri", c("LP"), TRUE, TRUE, TRUE)
model <- modelslist[[1]]
# Récupère le actions du modèle et les affiche
print("***** Here is the name of the actions")
for (action in model$getactions())
{
print(action$getname())
}
# On fait de même pour les transitions
print("***** Here is the name of the transitions")
for (transition in model$gettransitions())
{
# On concatène l'entrée pour la transition afin de la rendre plus lisible dans le terminal
cat(transition$str())
}
} else { # Si le modèle n'as pas été compilé avec OSI, on affiche une erreur
print("FMT needs to be compiled with OSI")
}
Ce code en R affichera le texte suivant dans le terminal :
Reading Models/TWD_land/TWD_land.pri
FMT 0.9.1, build: Sep 30 2021 12:07:49
Tue Oct 05 10:59:57 2021
Reading Scenario Lp
FMTexc(39)Undefined _death action: _DEATH FMTsection(4)Action
FMTexc(40)Undefined _death transition: _DEATH FMTsection(5)Transition
Done reading Tue Oct 05 10:59:57 2021
[1] "***** Here is the name of the actions"
[1] "CLEARCUT"
[1] "ACARIBOU"
[1] "PLANTATION"
[1] "AFIRE"
[1] "ARECUP"
[1] "_DEATH"
[1] "***** Here is the name of the transitions"
*CASE CLEARCUT
*SOURCE ? ? ?
*TARGET ? ? ? 100.000000
*CASE ACARIBOU
*SOURCE ? ? ?
*TARGET ? ? ? 100.000000 _LOCK 1
*CASE PLANTATION
*SOURCE ? ? ?
*TARGET ? STAND1 ? 100.000000
*CASE AFIRE
*SOURCE ? ? ?
*TARGET ? FIRE ? 100.000000
*CASE ARECUP
*SOURCE ? FIRE ?
*TARGET ? STAND1 ? 100.000000
*CASE _DEATH
*SOURCE ? ? ?
*TARGET ? ? ? 100.000000
L’équivalent en Python serait :
import sys
from FMT import Models
from FMT import Parser
from FMT import Version
if __name__ == "__main__":
if Version.FMTversion().hasfeature("OSI"):
# Créer un objet parser pour lire les fichiers du modèle
newmodelparser= Parser.FMTmodelparser()
path = "Models/TWD_Land/TWD_Land.pri"
scenarios = ["LP"]
# Lit le projet avec le parser en spécifiant que l'on veut lire le scénario "LP" (il peut y avoir différents scénarios dans un seul modèle)
modelslist = newmodelparser.readproject(path, scenarios)
model = modelslist[0]
# Récupère le actions du modèle et les affiche
print("***** Here is the name of the actions")
for action in model.getactions():
print(action)
# On fait de même pour les transitions
print("***** Here is the name of the transitions")
for transition in model.gettransitions():
print(transition.getname())
else:
print("FMT needs to be compiled with OSI")
Ce qui donnera le texte suivant dans le terminal Python. Notez que si les sorties entre R et Python devraient généralement être les mêmes, il existe parfois de petites différences. Ici, la version Python affichera plus d’informations sur les actions, et juste le nom des transitions par rapport à R ; ceci est dû aux particularités des deux langages.
Reading Models/TWD_land/TWD_land.pri
FMT 0.9.1, build: Sep 30 2021 12:07:49
Tue Oct 05 10:59:57 2021
Reading Scenario Lp
FMTexc(39)Undefined _death action: _DEATH FMTsection(4)Action
FMTexc(40)Undefined _death transition: _DEATH FMTsection(5)Transition
Done reading Tue Oct 05 10:59:57 2021
***** Here is the name of the actions
*ACTION CLEARCUT Y
*OPERABLE COUPETOTALE
? ? ? TOTALVOLUME >= 100.000000
*ACTION ACARIBOU N
*OPERABLE ACARIBOU
UC ? ? _AGE >= 8
*ACTION PLANTATION Y _LOCKEXEMPT
*OPERABLE PLANTATION
? ? ? _AGE >= 1 AND _AGE <= 3
*ACTION ARECUP Y
*OPERABLE AFIRE
? PROD ? _AGE >= 1
*ACTION ARECUP Y
*OPERABLE ARECUP
? FEU ? _AGE = 0
*ACTION _DEATH Y _LOCKEXEMPT
*OPERABLE _DEATH
? ? ? _AGE >= 80
***** Here is the name of the transitions
CLEARCUT
ACARIBOU
PLANTATION
AFIRE
ARECUP
_DEATH
Comparer des éléments dans FMT
Une opération courante à faire dans vos scripts sera de comparer des éléments : par exemple, comparer le nom d’un objet FMTaction
avec le nom de l’action que vous voulez sélectionner, etc.
Dans de tels cas, rappelez-vous que toutes les chaînes de caractères lues par FMT sont automatiquement mises en majuscules. Par conséquent, si vous voulez comparer le nom des éléments dans FMT, assurez-vous que les lettres sont en majuscules.
Par exemple, si vous avez une action nommée Clearcut
ou clearcut
que vous voulez sélectionner, vous devrez comparer le nom des FMTactions
des modèles avec le mot CLEARCUT
, tout en majuscules.
Conversion des erreurs en avertissements
Toutes les classes FMT héritent de la classe FMTobject
, et partagent donc les mêmes objets FMTexceptionhandler
et FMTlogger
.
Si l’utilisateur veut ignorer certaines erreurs, il peut utiliser la fonction seterrorstowarnings
de n’importe quelle classe FMT et passer un vecteur d’erreurs que le gestionnaire d’erreurs doit considérer comme des avertissements. Cette fonction est hazardeuse et peux mener a des erreurs. Il est recommandé d’investiguer les messages d’erreur de FMT et de corriger les modèles conséquement.
Maintenant que vous savez tout sur la structure de FMT et ses éléments de base, nous allons voir comment faire de l’optimisation à référence spatiale avec elle, qui est l’une des principales fonctions de FMT.