DifferenceEquation/fr

Introduction
L'extension DifferenceEquation permet de développer des modèles qui calculent la valeur d'une ou plusieurs variables réelles en t est fonction d'elles-même à t-1, t-2, ... et fonction d'autres variables réelles en t, t-1, t-2, ... Nous avons appelé ça les équations aux différences mais cette extension est plus générale car seule la propriété ci-dessus est à respecter.

Il existe trois façons de manipuler les équations aux différences :
 * soit de manière individuelle : un modèle par équation ;
 * soit sous forme d'un système : un modèle pour un ensemble d'équations ;
 * soit de manière générique : le nombre de variables misent en jeu dans l'équation est indéterminé.

DifferenceEquation::Simple
La classe DifferenceEquation::Simple prend en charge la modélisation d'une équation par modèle.

La structure
Il faut définir trois types de port :
 * les ports pour la synchronisation lorsque l'on couple plusieurs équations aux différences : update ;
 * les ports pour la perturbation de l'équation aux différences : perturb ;
 * les ports pour l'interrogation par des événements instantanés de l'équation aux différences : request pour l'entrée et response pour la sortie.

Les ports update sont définis en entrée et en sortie si l'équation intégre des variables gérées par d'autres équations ou tout autre modèle gérant l'évolution d'une variable numérique (par exemple QSS). Pour ces autres modèles, il faut qu'il respecte un certain protocole.

Tous les ports sont optionnels :
 * si vous ne voulez pas autoriser les perturbations, pas de ports perturb;
 * si votre équation n'est pas intégrée dans un graphe de modèles numériques et donc ne dépend pas d'autres modèles ou ne rendre pas en jeu dans d'autres modèles numériques, pas de port update ;
 * si vous ne voulez pas que votre modèle soit interrogeable, pas de port request/response.

Si plusieurs équations (dans notre exemple m1 et m2) sont mutuellement dépendants, il faut connecter les ports update ensemble.

Naturellement, si seulement m2 a besoin de la variable gérée par m1 alors seule ma première connexion est nécessaire.

NB : la structure et le protocole sont identiques à celui de QSS, cela permet de construire des modèles à base d'équations différentielles et à base d'équations aux différences.

Les initialisations
Les initialisations se divisent en deux groupes :
 * les inits pour le modèle lui-même : les paramètres de l'équation, par exemple ;
 * les inits pour l'équation aux différences

DifferenceEquation nécessite la valeur du pas de temps élémentaire (time-step), de la valeur initiale de la variable (value), d'un historique (init) et d'un mode de nommage (mode). Cette liste se termine par le nom de la variable gérée (name). Seul le pas de temps est obligatoire.

Si name n'est pas défini alors le nom de la variable sera :
 * soit le nom du port de sortie (si ce n'est pas update)
 * soit le nom du modèle défini dans le vpz.

Si value n'est pas spécifié alors une méthode spécifique est appelée : initValue(const vle::devs::Time& time). Par défaut, cette méthode initialise la variable à 0. Il faut donc la surcharger si ce comportement n'est pas adéquat.

Si init n'est pas spécifié alors il n'est pas possible de faire appel à des valeurs dans le passé càd où t < 0. Par exemple, dans la méthode initValue qui ferait appel à la variable y, on ne pourra pas utiliser les valeurs en t-1, t-2, ...

Si mode est absent alors le mode par défaut est name, les noms des variables externes ne subissent aucun traitement. Un modèle qui gérerait la variable X et qui serait connecté à un modèle qui veut utiliser cette variable alors elle s'appellerait X. Si le mode est mapping alors on définit une règle de renommage des variables. La variable X pourrait être manipulée sous un autre nom dans le modèle. Dans ce cas, il faut définir une condition supplémentaire :

Il faut aussi supprimer le port update et le remplacer par autant de ports d'entrée qu'il y a de variables externes. Dans notre exemple, deux ports d'entrée p1 et p2 sont nécessaires. Ces deux ports seront connectés à deux modèles et recevront deux variables qui porteront comme nom X1 et X2.

Il existe un troisième mode, le mode "port". C'est une simplification du mode précédent, le nom des variables est celui des ports. Si on est en mode port, que le modèle possède deux ports d'entrée p1 et p2 et que deux modèles y sont connectés alors les variables se nommeront p1 et p2.

Comment écrire un modèle à base de DifferenceEquation::Simple ?
L'écriture d'un modèle passe par la construction d'une sous-classe de vle::extension::DifferenceEquation::Simple. Deux méthodes sont à définir en dehors du constructeur et du destructeur :
 * compute pour le calcul ;
 * initValue pour le calcul de la valeur initiale (facultatif).

Le constructeur, quand à lui, permet de récupérer les paramètres de l'équation via le deuxième paramètre events.

Les paramètres sont à définir dans le vpz sous la forme suivante :

Voici un exemple d'header :

Voici maintenant un exemple d'initialisation de l'extrait précédent de vpz. Attention, il ne faut pas oublier la récupération des paramètres dans le constructeur sinon les paramètres de DifferenceEquation ne seront pas définis.

La deuxième étape consiste à définir la variable gérée par l'équation et les variables externes. Pour cela, il faut déclarer, comme attribut de la classe, un attribut du type Var pour la variable gérée par l'équation et Sync ou Nosync pour les autres.

Par exemple, si l'équation M gère la variable X et dépend de deux variables Y et Z, il faut déterminer la nature de Y et Z. Sont-elles synchrones ou non ? Une variable Y, par exemple, est synchrone si dans l'expression de X, on a besoin de Y(t) ou non. Imaginons que Y est synchrone et Z non synchrone alors la déclaration est la suivante :

Ensuite, il faut faire le lien entre la variable C++ de manipulation de la variable et l'identifiant utilisé. Cela se déroule dans le constructeur.

La méthode de calcul peut faire intervenir la valeur de la variable gérée par le modèle, les paramètres s'ils existent et les valeurs des variables numériques gérées par d'autres modèles. Pour la variable gérée par le modèle et les variables gérées par d'autres modèles, on peut accéder à leur valeur en t mais aussi en t-1, t-2, ... L'opérateur est utilisé pour l'accès aux valeurs.

Dans l'exemple, a et b sont les paramètres de l'équation, X(-1) fait référence à X(t-1), Y à Y(t) et Z(-1) à Z(t-1). La méthode compute retourne la valeur de X(t).

DifferenceEquation attend la mise à jour des valeurs des variables externes avant de lancer le calcul sauf dans le cas de modèles connectés de manière cyclique.

DifferenceEquation::Multiple
La classe DifferenceEquation::Multiple prend en charge la modélisation de plusieurs équations par modèle.

La structure
La structure d'entrée et une partie de la structure de sortie est identique à celle de DifferenceEquation::Simple. Seul le port de sortie update n'existe pas. En effet, il y a un port de sortie par variable gérée par le système d'équations. Par exemple, si le modèle gère deux variables X et Y alors la structure complète est :

Les initialisations
Comme pour DifferenceEquation::Simple, time-step et mode sont à définir (de manière obligatoire pour time-step). En revanche, name, value et init se présentent sous une autre forme puisque DifferenceEquation::Multiple gèrent plusieurs variables.

Pour chaque variable gérée par le modèle, il faut définir une liste à 3 éléments maximum (le nom, la valeur d'initialisation et l'historique). Cette liste peut se réduire à un ou deux éléments.

Comment écrire un modèle à base de DifferenceEquation::Multiple ?
L'écriture d'un modèle passe par la construction d'une sous-classe de vle::extension::DifferenceEquation::Multiple. Deux méthodes sont à définir en dehors du constructeur et du destructeur :
 * compute pour le calcul ;
 * initValue pour le calcul de la valeur initiale (facultatif).

Le constructeur joue le même rôle que pour les modèles à une équation.

Voici un exemple d'header :

La deuxième étape consiste à définir les variables gérées par le modèle et les variables externes. Pour cela, il faut déclarer, comme attribut de la classe, des attributs du type Var pour les variables gérées par le modèle et Sync ou Nosync pour les autres.

Ensuite, il faut faire le lien entre la variable C++ de manipulation de la variable et l'identifiant utilisé. Cela se déroule dans le constructeur.

Comme pour DifferenceEquation::Simple, la manipulation des valeurs des variables internes ou externes se fait via l'opérateur.

La grosse différence par rapport à DifferenceEquation::Simple est que la méthode compute ne retourne rien et que les variables sont directement affectées.

Il y a deux précautions à prendre :
 * l'ordre est très important, X2(t) est fonction de X1(t) donc X1 doit être affectée avec X2 ;
 * une seule affectation par variable est autorisée.

Comment perturber un DifferenceEquation ?
Pour perturber un DifferenceEquation (simple ou multiple), il suffit de se connecter sur le port d'entrée perturb et d'envoyer un événement transportant trois valeurs :
 * name avec le nom de la variable à perturber qui doit être le nom de la variable gérée par le modèle ;
 * value avec la nouvelle valeur de la variable ;
 * type avec le type de perturbation.

Il existe 3 types de perturbations :
 * SET (mode par défaut si la valeur type n'est pas indiquée) : la valeur de la variable est remplacée par la nouvelle valeur ;
 * ADD : la valeur de la variable est augmentée de la valeur transportée par la perturbation ;
 * SCALE : la valeur de la variable est multipliée par la valeur transportée par la perturbation ;

Ces types sont définis dans l'énumération Perturbation_t du namespace DifferenceEquation.

Lors d'une perturbation, un modèle peut être amené à recalculer, pour une même date, la ou les valeurs des variables qu'il gère si la perturbation arrive après le calcul de ces derniers. S'il y a recalcul alors la nouvelle variable est propagée aux modèles dépendants d'une ou plusieurs variables recalculées. Si la dépendance est de type synchrone alors un recalcul peut aussi avoir lieu dans les modèles dépendants du modèle perturbé.

Comment interroger un DifferenceEquation ?
Si vous avez besoin de connaître la valeur courante d'un modèle, il suffit de se connecter sur le port "request" et vous pouvez envoyer un événement instantané qui vous donnera en retour la valeur de la variable.

Il faut envoyer un événement instantané ayant pour valeur le nom de la variable dans un attribut name. L'évenement de retour sera constitué du nom (attribut name) et de la valeur (attribut value).

Le port inst_m1 est connecté au port request du modèle m1 qui est un DifferenceEquation. Ce DifferenceEquation gère la variable x.

Couplage avec un modèle non DifferenceEquation
Deux types de couplage sont possibles :
 * un modèle non DifferenceEquation veut envoyer la valeur d'une variable réelle à une équation aux différences (ou à un système) et donc intervenir dans l'équation comme une variable externe ;
 * un modèle non DifferenceEquation veut recevoir la valeur d'une variable gérée par une équation aux différences (ou un système).

Dans le premier cas, il faut que le modèle envoie un événement transportant deux attributs : Cet événement doit être envoyé de manière synchrone (ou asynchrone) et sous la condition suivante : pendant un pas de temps de l'équation aux différences, le modèle reçoivent au moins une valeur.
 * name avec une chaîne de caractères contenant le nom de variable ;
 * value avec un réel contenant la valeur de la variable.

Dans le deuxième cas, il suffit de se connecter sur le port de sortie update (ou le port correspondant à la variable d'intérêt dans le cas d'un système) et le modèle va recevoir à chaque pas de temps un événement dont le format est identique à celui décrit ci-dessus.

Augmenter la taille de l'historique
Les variables Sync et Nosync ont par défaut un historique de 2 valeurs. Il est possible de changer la taille de cet historique en utilisant la fonction Base::size(const std::string& variable, int newsize) disponible dans les classes des équations aux différences simples et multiples. Par exemple, pour le modèle multiple M :