mise à jour :31-03-2010 cinet.chim

III.1.1  Réaction monomoléculaire

logo Sa

Exercice 1

(tutoriel Sa)


Sa - exercice 1

Réaction monomoléculaire
(tutoriel Sa)



Ce tout premier exercice avec Sa a pour but à la fois de vous permettre de "vivre" la partie correspondante du cours, comme ce sera le cas pour les exercices suivants, et de vous familiariser avec le logiciel (présentation de Sa). C'est donc aussi un tutoriel (pardon pour l'anglicisme), c'est pourquoi il peut sembler très long. Laissez-vous guider pas à pas afin de bien assimiler les éléments essentiels et la façon de travailler avec Sa, même si tout n'est pas immédiatement utile. Faute de perdre un peu de temps ici, vous risqueriez d'en perdre beaucoup plus, plus tard. Par la suite, lorsque vous serez familiarisé, nous irons plus directement au but.

Vous pouvez également utiliser le manuel de Sa, particulièrement le chapitre III : Prise en mains. Toutefois, ce manuel s'adresse plutôt aux personnes déjà un peu familiarisées avec le logiciel et nous vous recommandons plutôt, en un premier temps,  de suivre le présent tutoriel, conçu pour vous faire découvrir les éléments essentiels, sans vous noyer dans toutes les possibilités de Sa.

Si vous n'avez pas encore téléchargé Sa, c'est le moment de le faire : télécharger Sa3_0408.zip (6.5 Mo)

Une fois téléchargé, pour l'installer, suivre les indications de cette page : installer Sa

Contact : cinet.chim@orange.fr


En réalité, à ce stade, vous ne disposez pas encore de version exécutable de Sa, mais seulement de ses sources, c'est-à-dire l'ensemble de tous les fichiers décrivant, en langage C++, ce que le programme doit faire. Tous, sauf un : celui qui décrit votre modèle, votre application particulière, et que vous devez donc d'abord écrire. Une fois écrit, ce fichier que nous appellerons de façon générique MOD.cpp (MOD sera remplacé par le nom que vous donnerez) devra être compilé, ainsi que tous les autres fichiers constitutifs de Sa, c'est-à-dire traduit en langage machine. Cette opération créera pour chaque fichier source un fichier objet (avec l'extension .obj). Enfin, tous ces fichiers objet devront être liés pour obtenir un fichier Sa exécutable qui sera nommé MOD.exe, votre version de Sa capable de faire quelque chose.

Ceci peut vous paraître compliqué, mais vous verrez que l'assistant Nestor fait tout cela très simplement. Par la suite, vous écrirez d'autres fichiers MOD.cpp, correspondant à d'autres modèles. Il faudra refaire ces opérations pour obtenir de nouveaux exécutables. Le compilateur ne compilera alors que le nouveau fichier MOD.cpp et le liera aux autres.

En fait, il compilera aussi, automatiquement, tous ceux qui auraient été modifiés depuis la dernière compilation. C'est là tout l'avantage de travailler avec les sources complètes de Sa : si tel ou tel module ne répond pas à vos besoins, vous pouvez le modifier et votre modification sera intégrée à Sa. Toutefois... ne vous lancez pas dans dans une telle tâche sans de solides notions de programmation !

présentation de Nestor

Lancez l'assistant Nestor (Sa3Nestor.exe situé dans votre dossier principal d'installation, ou le raccourci que vous avez créé). Cela ouvre une fenêtre qui doit ressembler à celle-ci (écran 1) :

fenêtre Nestor

écran 1

Elle est constituée de quatre panneaux, de haut en bas :

  1. du panneau supérieur, nous ne retiendrons pour l'instant que l'accès à la totalité de l'aide.
  2. Edition
  3. Gestionnaire de fichiers
  4. Compilation / lancement de Sa


écriture du fichier MOD.cpp

1. Choisir ou créer un dossier de travail (WD)

La toute première chose à faire est de définir le dossier dans lequel vous allez travailler. C'est dans ce dossier que devra se trouver le modèle (MOD.cpp) et que sera créé l'exécutable (MOD.exe). Ensuite, tous les fichiers créés automatiquement par Sa le seront dans ce dossier. L'idée est de créer un tel dossier par modèle, ou du moins par thème.

Pour cela, cliquez sur le bouton change, marqué en rouge sur l'écran 1, et sélectionnez un dossier déjà existant ou créez en un nouveau en tapant son nom.

Supposons que vous avez choisi C:\Cinetique\Ordre1.

2. Ecrire MOD.cpp

Ouvrez l'éditeur en cliquant sur le bouton Edit. Il s'ouvre avec une page blanche :

fenêtre éditeur

écran 2

Le bouton   / /   marqué en bleu doit être enfoncé. Amenez le curseur de la souris au-dessus : une info-bulle apparaît, indiquant "C++ Program / Comment mode". C'est la description de son rôle : enfoncé, les commentaires dans les programmes C++ seront mis en bleu, ce qui est bien pratique (il faut quelquefois le libérer et l'enfoncer de nouveau pour mettre à jour).

Vous pouvez connaître le rôle de tous les boutons par ce même type d'info-bulles. La plupart de leurs fonctions sont accessibles également par les menus : File, Edit, etc. Donnez un coup d'œil pour voir de quels outils vous disposez. Notez en particulier l'outil  { }, marqué en vert,  qui permet de trouver le "com-paire" des signes {, (, [ et < ou inversement. C'est aussi très utile pour vérifier la syntaxe.

Notez également l'indication de la position du curseur d'édition, en bas à gauche de la fenêtre (line et col). Les numéros de lignes (marqué en violet) sont très utiles lorsqu'il y a une erreur de programme, le compilateur indiquant le numéro de la ligne où il a détecté l'erreur.

Ouvrez le menu Templates, puis sélectionnez Skeleton structure. Une fenêtre contenant du texte s'ouvre. Appuyez sur le bouton Insert all, ce texte est copié dans l'éditeur :

Skeleton structure

écran 3

(relâchez et enfoncez de nouveau le bouton  / /,  éventuellement, pour bien avoir les commentaires en bleu)

Tout ce qui apparaît en bleu est du simple commentaire, utile pour vous, mais complètement ignoré par le compilateur. Les commentaires peuvent être délimités de deux façons :

- dans une même ligne : tout ce qui suit le double slash, //

- sur une ou plusieurs lignes : tout ce qui est entre  /*  et  */

Vous avez maintenant sous les yeux la structure squelette de tous les fichiers MOD.cpp que vous aurez à écrire. La première ligne est juste une invitation à mettre le nom de ce fichier en commentaire d'entête. C'est sans importance mais pratique.

Suit la ligne :

#include global.h

Les lignes commençant par # sont des directives de compilation. Ici, cela indique au compilateur qu'il doit inclure le fichier global.h à cet endroit de votre fichier. C'est très important, le fichier global.h, qui fait partie de l'ensemble des fichiers que vous avez installé, contient les déclarations de toutes les variables globales du programme, c'est-à-dire celles que vous pouvez utiliser.

Vient ensuite le module, ou fonction, Identification, dont le corps est délimité par les deux signes  {  et  } . Ces deux signes sont indispensables pour délimiter un bloc. Identification sera exécuté au lancement de l'exécution du programme afin d'initialiser certaines variables.

Ne touchez pas les deux lignes suivant  // automatic identification.

Sous la rubrique  // personal identification,  remplacez si vous le désirez les caractères <???>, en conservant les guillemets " ", par votre nom et le nom du modèle. Cela n'est pas obligatoire, mais peut être utile pour s'y retrouver, par exemple lorsqu'on fait plusieurs versions pour un même problème.

Suivent quatre affectations de valeurs (surlignées en jaune dans l'écran 3) à des variables globales du programme, qui doivent impérativement être fournies. Mais nous y reviendrons après avoir écrit le reste du modèle. Quant à la dernière ligne, marquée d'un point rouge, nous n'en aurons pas besoin de si tôt : supprimez-la.

Puis une boîte vide  // -2- Global declarations. Nous n'avons rien à y mettre pour l'instant, mais c'est ici, en dehors de tout bloc délimité par { }, que nous devrions déclarer, le cas échéant, de nouvelles variables globales, c'est-à-dire utilisables dans toute la suite du fichier MOD.cpp. En effet, une variable déclarée à l'intérieur d'un bloc { } ne peut être utilisée que dans ce même bloc.

Il est temps de nous demander ce que nous voulons faire. En un premier temps, nous nous proposons simplement de simuler une réaction d'ordre 1, donnée par son expression algébrique. Il n'y a donc pas d'équation différentielle, et la fonction eqdiff doit rester vide, c'est-à-dire qu'il n'y a rien à mettre entre ses deux délimiteurs { }. Notez bien que, même vide, elle ne doit pas être supprimée, sinon vous aurez une erreur à la compilation.

Nous arrivons enfin au cœur de votre programme, la fonction fappel. C'est là que vous devez écrire la recette complète de votre cocktail calculatoire : Sa appellera cette fonction à chaque demande de simulation. La ligne

<???>; // instructions
indique simplement que vous devez écrire ces instructions, en remarquant que toute instruction doit se terminer par un point-virgule ; (son omission est une cause fréquente d'erreur de compilation).

Supprimez cette ligne et gardez le curseur d'édition à cet endroit. Revenez au menu Templates, sélectionnez Basic components puis for loop npt, puis appuyez sur Insert all. Cette opération va insérer dans votre fonction fappel les quatre lignes suivantes :

   for (int i = 0; i < npt; ++i)
   {
      ca[nn?][i] = <???>;
   }

Remettez éventuellement de l'ordre dans l'indentation, qui peut être perturbée par le processus d'insertion. L'indentation a pour but de montrer au lecteur, et à vous même, les différents niveaux d'imbrication des blocs et donc toute la logique de votre programme. Le compilateur l'ignore totalement, comme il ignore tous les signes de présentation (espaces, tab, retours à la ligne, sauf un espace séparant deux "mots"). Mais il est vivement recommandé d'en user, cela rend les programmes considérablement plus lisibles et plus faciles à réparer ou modifier.

Ce que vous avez inséré est une boucle for : dans la première ligne une variable entière, i, est déclarée et initialisée à la valeur 0  (int i = 0;). Puis il y a le test d'une condition  (i < npt;) : le corps de la boucle, c'est-à-dire ce qui est contenu entre { et }, sera exécuté tant que cette condition reste vraie. La variable npt (pour nombre de points) est une variable globale de Sa qui désigne le nombre de valeurs de la variable indépendante (le temps, pour nous) pour lesquelles il faut calculer les autres variables du modèle; sa valeur sera déterminée automatiquement par le programme lors de l'exécution. Enfin, ++i, forme abrégée de i = i + 1,indique qu'après chaque exécution du corps de la boucle i sera incrémenté de 1.

Veillez à ne pas confondre la lettre O (majuscule) et le chiffre 0 (zéro). Dans l'expression
p[0] = Omega;
par exemple, le chiffre 0 est l'indice de p, tandis que O est la première lettre du mot Omega.

Il ne reste plus qu'à préciser ce corps. La variable globale ca (pour calculé) désigne tout ce que Sa doit calculer lors d'une simulation. C'est une variable tableau à 2 dimensions et on accède donc à ses éléments à l'aide de 2 indices : ca[0][i]  par exemple. Le premier indice est le numéro de la variable, et le second est le numéro du "point", correspondant au temps, donc, dans notre cas. Affectant le numéro 0 à la concentration de A dans la réaction A → B, nous allons donc écrire :

   ca[0][i] = ca[0][0]*exp(-p[0]*ind[i]);

simple traduction de l'équation (3) du cours : A = A0 e−k t 
 ca[0][0] est A0, p[0], la constante de vitesse k, et ind[i] le temps t.

Les variables globales p et ind, représentant respectivement les paramètres du modèle et la variable indépendante (le temps ici) sont des variables tableau à 1 dimension, on accède donc à leurs éléments à l'aide d'un seul indice. Vous avez noté que ces indices doivent être entre crochets [ ], et qu'ils commencent à 0. Quant à  exp(...), c'est l'appel de la fonction exponentielle de l'argument entre parenthèses ( ).

C'est tout ce que nous avons à faire dans fappel pour l'instant !

Maintenant que nous avons écrit le corps du programme, nous pouvons revenir aux quatre variables surlignées dans Identification (écran 3), et leur affecter des valeurs :

n_diff = 0; (il n'y a pas d'équation différentielle)

first_var = 0; (il n'y a pas d'intégration numérique)

En fait, on pourrait affecter ici n'importe quelle valeur entière car elles ne seront pas utilisées, mais il faut affecter une valeur, sinon il y aura une erreur de compilation.

nv_mod = 1; (c'est le nombre total de variables du modèle)

nexp = 1; (nous expliquerons nexp plus tard, contentons-nous de le mettre à 1)

Le programme complet et nettoyé est donc le suivant :

//monomol_1.cpp // name of this file
//----------------------------------------------------------------------------
#include"global.h"
//----------------------------------------------------------------------------
void Identification(Modele& modele)
{
   modele.Fichier = String(__FILE__);
   modele.Version = String(__DATE__) + String(" ") + String(__TIME__);
   modele.Auteur = "Robinson";
   nom_syst = "monomol_1";
   n_diff = 0;    // number of differential equations
   first_var = 0; // number of the 1st variable to be integrated
   nv_mod = 1;    // number of variables of the model (v 3.3)
   nexp = 1;      // number of experiments (v 3.3)
}
//----------------------------------------------------------------------------
void eqdiff (Sa_data x, Sa_data* y, Sa_data* dy)
{
}
//----------------------------------------------------------------------------
void fappel()
{
   for (int i = 0; i < npt; ++i)
   {
      ca[0][i] = ca[0][0]*exp(-p[0]*ind[i]);
   }
}
//----------------------------------------------------------------------------

N'essayez pas de copier le texte de programme ci-dessus, vous auriez des surprises désagréables !

Essayez avant tout de faire vous-même votre programme. Si toutefois vous rencontrez des problèmes, vous pouvez télécharger le programme original : télécharger monomol_1.cpp

Il ne reste plus qu'à sauver ce fichier (menu File, Save as ou Save). Par défaut, il sera sauvé dans le dossier de travail que vous avez préalablement choisi. Appelons-le, par exemple monomol_1.cpp. Notez les caractères _ : surtout pas d'espaces dans les noms ! N'oubliez pas l'extension .cpp, elle n'est pas mise automatiquement, mais elle est obligatoire.

Les extensions de noms de fichiers (.cpp, .sac), bien qu'indispensables, ne sont jamais mises automatiquement par Sa. C'est à vous de les mettre correctement. Toutefois, les versions récentes de Windows peuvent vous proposer des extensions. Il vous revient alors de sélectionner celle qui convient.

Une fois sauvé, quittez l'éditeur. En principe, le nom complet de ce fichier doit apparaître dans le champ juste en dessous de File Manager. Si ce n'est pas le cas, cherchez-le à l'aide du bouton Search correspondant (le plus haut). Il ne reste plus qu'à dire à Nestor que c'est ce fichier que vous voulez considérer comme le modèle en cours : appuyez sur le bouton avec une flèche rouge mod copy, cela copie le fichier dont le nom est juste au dessus dans le dossier de travail, si ce n'est pas déjà le cas, et le désigne en même temps comme le modèle en cours (Attention : n'utilisez pas le bouton mod move si le fichier est déjà dans le dossier de travail... cela l'effacerait).

Le nom (sans le chemin complet) de votre fichier doit apparaître maintenant dans le champ Model.

3. Compiler

Allez maintenant dans le volet inférieur de Nestor. Choisissez dans quelle langue vous voulez compiler votre programme. En effet, Sa peut avoir une interface et une aide en ligne en français ou en anglais.

Appuyez sur Compile, et confirmez que vous voulez bien compiler le fichier affiché. Cela produit l'affichage de deux fenêtres : l'une noire, dont vous ne vous souciez pas, l'autre blanche, intitulée Compilation report, avec un message vous demandant de patienter.

Comme c'est votre première compilation, elle doit être relativement longue car c'est une compilation complète. Par la suite, ce sera beaucoup plus rapide puisque seul votre fichier MOD.cpp devra être compilé et lié aux autres.

Si vous n'avez pas fait d'erreur dans l'édition du fichier monomol_1.cpp, lorsque la compilation sera terminée, la fenêtre blanche se remplira de texte... plutôt obscur. Appuyez sur le bouton Continue qui apparaît maintenant, et regardez les deux dernières lignes du texte. Elles devraient commencer par The compilation is successfull... : il n'y a pas d'erreur et la compilation est terminée. Notez bien que par "pas d'erreur", il faut entendre uniquement "pas d'erreur qui empêche la compilation d'aller jusqu'au bout" : cela ne garantit pas que le programme ainsi compilé réalisera bien ce vous aviez l'intention de faire.

Pour illustrer ce qui se passe en cas d'erreur, supprimons volontairement le deuxième guillemet " dans la ligne 9 : modele.Auteur = "Robinson; // au lieu de "Robinson";
Pour cela, il suffit d'ouvrir de nouveau l'éditeur (il devrait s'ouvrir cette fois directement sur le fichier monomol_1.cpp), de faire la modification et de ne pas oublier de le sauver.

Cela provoque à la compilation d'abord l'ouverture d'une fenêtre ERROR avec le message
Impossible to compile. Unknown problem.
Fermez cette fenêtre en appuyant sur OK, puis appuyez sur le bouton Continue de la fenêtre Compilation report. Voici ce que cela donne :

ecran 4

écran 4  

Recherchez dans la liste des messages la première occurrence du mot Error. Elle vous indique le fichier responsable, suivi du numéro de ligne (entouré de rouge ci-dessus) et de la description (plus ou moins explicite suivant le cas !) de l'erreur. Dans le cas présent, le numéro de ligne (9) correspond bien à l'erreur réelle. Ce n'est pas toujours le cas car il se peut qu'une erreur dans une ligne du texte provoque une erreur de compilation plus loin, et la description de l'erreur peut devenir moins claire. Il faut alors penser à regarder dans les lignes précédentes.

La deuxième erreur signalée ici est en fait provoquée par la première et disparaîtra en corrigeant celle-ci. C'est le plus souvent le cas et, en règle générale, il faut toujours commencer par corriger la première erreur détectée.

Le dernier contenu de la fenêtre Compilation report est systématiquement sauvé dans le fichier comp_res.txt, situé dans le dossier principal d'installation, Sa3.

Revenez maintenant à la version correcte de monomol_1.cpp et recompilez.

4. Exécuter

Vous avez remarqué qu'après la compilation (réussie) le nom du fichier exécutable monomol_1.exe, créé dans votre dossier de travail, apparaît dans le champ Executable de Nestor. Vous pouvez garder Nestor sous la main et utiliser le bouton Run pour le lancer. C'est recommandé tant que tout n'est pas bien au point. Mais vous pouvez aussi quitter Nestor et lancer l'exécutable en cliquant deux fois dessus, dans l'explorateur de fichiers de Windows.

Au lancement, Sa ouvre deux fenêtres :
- la fenêtre principale, barre qui occupe la partie supérieure de l'écran, qui regroupe les commandes générales
- la fenêtre Infos, qui concerne plus spécifiquement votre application particulière.

ecran 5 écran 5    

Examinez la fenêtre principale en promenant le curseur de la souris sur les différents boutons. Par défaut, le mode simulation seule (Sim) est activé : laissez-le ainsi. Notez la présence de l'éditeur Sa Editor, souligné de deux traits rouges, avec en plus la possibilité de l'ouvrir directement sur les fichiers courants (dont nous parlerons le temps venu).

Appuyez sur le gros bouton coloré (info-bulle : Démarre le calcul). Vous avez un message d'erreur, peu aimable ! Cliquez sur OK pour le refermer. Les choses redeviennent normales (à part, peut-être, le curseur qui reste sous la forme "sablier", mais ce n'est pas grave). C'est ce qui se passera en général lorsqu'une erreur empêchera Sa de tourner normalement, les messages envoyés seront plus ou moins compréhensibles et utiles, suivant le cas . Toutefois, des erreurs plus graves peuvent être fatales, et vous obliger à fermer le programme depuis la barre des tâches de Windows.

Que s'est-il passé ? Tout simplement : aucun calcul n'est possible tant que nous n'avons pas donné des valeurs aux paramètre du modèle.

5. Fichier de paramètres (.sac)

Dans la fenêtre Infos (écran 5), c'est l'onglet Général qui est visible à l'ouverture. Dans le cadre Modèle, vous reconnaissez le nom de votre fichier monomol_1.cpp. En dessous, dans le champ Fichier de commande (.sac), il y a none puisque nous n'avons pas encore de tel fichier.

Allez dans l'onglet Paramètres puis cliquez sur le bouton + en vert pour créer un paramètre. Il aura le numéro 0, et sera donc affecté à la constante de vitesse p[0] de notre programme. Dans la colonne nom, tapez k, et dans la colonne valeur, tapez 1. Notez le mécanisme général de saisie : lorsque vous êtes en mode saisie, un gyro-phare vous en avertit en haut de la fenêtre et vous devez obligatoirement valider votre saisie par la touche Entrée. Vous devez obtenir ceci :

onglet paramètres

écran 6


Allez dans l'onglet Variables, qui ressemble beaucoup au précédent, et créez la variable n° 0, comme précédemment en cliquant sur le bouton +. Saisissez son nom, par exemple [A], et sa valeur (initiale), par exemple 1e-3 (pour 10-3). Cela sera affecté à la concentration initiale de A, ca[0][0] de notre programme.

Il ne reste plus qu'à préciser comment nous voulons faire varier la variable indépendante. Pour cela, revenez dans l'onglet Général, dans le cadre Variable indépendante. Saisissez :
- le nom : temps (vous pouvez désactiver la case "= var. d'intégration")
- la valeur Début : 0
- la valeur Fin : 10 par exemple (k = 1 s-1, τ = 1 s : on estime en général la cinétique terminée à 5 ou 6 τ )
- l'Incrément : 0.1 (cela fera donc 100 points de calcul, bien suffisants). Laissez-le en mode Normal.

Sa a maintenant tout ce qui est nécessaire pour effectuer une simulation. Mais avant de l'effectuer, vous devez enregistrer ces paramètres pour pouvoir vous en resservir. Dans le cadre Fichier de commande (.sac), cliquez sur Enregistrer, répondez non à la question Ecrasement du fichier de commande. Choisissez un dossier, de préférence votre dossier de travail, et un nom, par exemple monomol_1.sac. Attention : l'extension .sac  (pour Sa Commande) est indispensable, mais elle n'est pas mise automatiquement, vous devez la taper.

Vous pouvez voir à quoi ressemble le fichier .sac que vous venez de créer à l'aide de l'éditeur intégré. Dans la barre principale, cliquez sur la flèche à droite du bouton éditeur (souligné 2 fois en rouge sur l'écran 5) et sélectionnez Fichier paramètres (.sac). L'éditeur s'ouvre sur le fichier suivant :

ecran 7

écran 7

  

Ce fichier peut être édité directement, mais attention, il doit respecter très strictement ce format, c'est pourquoi nous avons adopté la méthode ci-dessus.

Les éléments marqués en rouge ont été automatiquement mis à jour par Sa. Les éléments surlignés en jaune sont ceux que vous avez saisis (x0 = Début, xf = Fin, hout = Incrément). Le reste ne nous est pas utile pour l'instant mais doit être laissé en l'état.

télécharger monomol_1.sac

6. Simuler

Maintenant, vous pouvez lancer une simulation (gros bouton coloré de la barre principale), après vous être assuré que le bouton SIM  est enfoncé. Vous ne devez plus obtenir de message désobligeant.

Dans la barre principale, le numéro de calcul s'affiche (n°1 pour l'instant, à la droite du bouton éditeur) et un d apparaît sur le bouton Fichier automatique des données. Cliquez dessus : vous avez les données que Sa vient de calculer. Ces données sont automatiquement enregistrées dans un fichier de même nom que votre fichier .sac mais avec l'extension .sad (pour Sa Données), donc pour l'instant monomol_1.sad. Le bouton Enregistrer sous... vous permet de l'enregistrer sous un autre nom si vous voulez le conserver, ce fichier étant automatiquement écrasé lors d'un nouveau calcul, par exemple avec des paramètres différents.

D'autre part, une nouvelle fenêtre nommée FGM (pour Feuille Graphique Multiple) s'ouvre. Il s'agit de la fenêtre graphique de Sa. Elle est conçue comme un outil de travail pour aider à la compréhension des calculs, et non comme un outil de présentation : pour cela, il faut utiliser les fichiers .sad et un logiciel spécialisé. Il n'en manque pas et tous sont capables d'ouvrir des fichiers texte de données en colonnes.

Aucun graphique n'est affiché pour l'instant, juste le nom de la variable de notre modèle, [A], et ses valeurs min et max prises au cours du calcul. Commencez par redimensionner, éventuellement suivant la configuration de votre écran, la fenêtre FGM de façon à faire disparaître les ascenseurs (vertical et horizontal), afin de la voir en entier.

Cliquez sur Page neuve. Cela crée un nouvel onglet intitulé 0-c1 : 0 est le numéro de l'onglet ou page, c1 le numéro du calcul. Ces numéros sont affichés également en bas à gauche de la fenêtre. Cliquez n'importe où sur la ligne de la variable n°0 à droite de la fenêtre afin de la sélectionner, puis sur la flèche vers la gauche rouge, au centre. Vous obtenez une courbe ressemblant à celle de la figure III.1 du cours. Pour la rendre totalement semblable, appuyez sur le bouton Echelles et saisissez Xmax = 6 dans le petite fenêtre qui s'ouvre, puis OK. (écran 8 ci-dessous)

Promenez maintenant le curseur de la souris sur la courbe : ses coordonnées courantes, dans vos unités, s'affichent dans la barre d'état en bas de la fenêtre. Approchez vous du point correspondant à t1/2 (Y = [A] = 0.5 10-3) puis cliquez avec le bouton droit de la souris : le curseur prend la forme d'une cible et vous ne pouvez plus le déplacer que pixel par pixel à l'aide des quatre flèches bleues (en bas au centre de la fenêtre). Amenez le le plus précisément possible au point de la courbe où Y = 0.5 10-3. Vous devez avoir quelque chose comme X = 0.688... valeur proche de (ln 2) / k = 0.693.

Le manque apparent de précision vient de deux raisons :

1. la résolution de votre écran, puisque ce sont les coordonnées du curseur sur celui-ci qui sont traduites en vos coordonnées.

2. la résolution de votre échelle de temps : appuyez de nouveau sur le bouton d de la barre principale et cherchez le temps correspondant à [A] = 0.5 10-3 : cette valeur ne fait pas partie de la liste et vous ne trouverez que des valeurs proches qui l'encadrent. Pour l'obtenir plus précisément, il faudrait choisir un incrément plus petit. Cela n'a évidemment, et heureusement, rien à voir avec la précision du calcul proprement dit, qui est, par défaut, de l'ordre de la quinzième décimale.


fenêtre graphique

écran 8 (curseur cible en position de t1/2, après clic droit sur la souris)

Pour revenir au mode normal du curseur, cliquez au centre des quatre flèches bleues.

Cliquez maintenant sur le bouton Ylog pour obtenir le tracé en échelle logarithmique : cela n'est pas possible avec Ymin = 0, vous devez choisir une valeur strictement positive, par exemple 10-6, en utilisant de nouveau le bouton Echelles. C'est fait ? Vous devez maintenant avoir une magnifique droite, comme on devait s'y attendre ! Notez cependant que c'est uniquement le tracé qui est réalisé en échelle logarithmique : vous pouvez vérifier que les coordonnées indiquées pour le curseur sont les coordonnées réelles dans votre espace temps/concentration.

Variantes

Après ce 1er tour d'horizon, nous allons maintenant faire la même chose, mais à partir de l'équation différentielle de l'ordre 1 :

dA/dt = −k A     (1)  (éq.1 du cours)

C'est un peu du luxe puisque nous disposons ici de l'équation intégrée, mais cela illustrera de manière très simple ce que vous aurez à faire plus tard.

Quittez donc Sa et réouvrez l'éditeur depuis Nestor. Il devrait s'ouvrir sur votre fichier précédent monomol_1.cpp. Si ce n'est pas le cas, ouvrez ce fichier (menu File / Open ou bouton Open file).

Allez tout de suite dans le corps de la fonction eqdiff, et créez une ligne entre les deux accolades. Ouvrez le menu Templates et sélectionnez Basic components puis eqdiff. Dans la fenêtre de Templates qui s'est ouverte, sélectionnez la ligne
dy[nn?] = <???>;
et appuyez sur Insert selection pour l'insérer dans votre fichier. Editez-la de façon à avoir votre fonction eqdiff complète :

void eqdiff (Sa_data x, Sa_data* y, Sa_data* dy)
 {
   dy[0] = - p[0]*y[0];
 }

où vous reconnaissez l'équation différentielle ci-dessus, p[0] désignant la constante de vitesse k comme précédemment, et y[0] la concentration A. Quelques explications :

eqdiff sera appelé, automatiquement, par l'intégrateur numérique à chaque pas d'intégration. Ce dernier lui transmettra la valeur courante du temps x (bien qu'elle ne soit pas utilisée ici), et la valeur courante des variables à intégrer sous la forme d'un tableau à 1 dimension y. Dans notre cas, il n'y a qu'une variable à intégrer, la concentration [A], elle a donc le numéro 0 et l'on y accède par y[0]. Le tableau dy, analogue, est destiné à recevoir les valeurs des dérivées et à les transmettre en retour à l'intégrateur.

Dans fappel, commencez par supprimer entièrement la boucle for qui s'y trouve : il ne doit rester plus rien. Ouvrez Templates, Basic component puis call srkvi, et appuyez sur Insert All. Cela doit insérer dans votre fonction fappel la ligne :

srkvi(n_diff, &ca[first_var], ind, npt, h0, tol, iset, jacob, h_compt, c_min);

srkvi est le nom de l'intégrateur numérique de Sa. Il s'agit d'une version améliorée de l'algorithme SRK (Semi implicite Runge Kutta) admettant des incréments variables (Variable Increments). Lorsqu'il est appelé par le programme, il effectue l'intégration numérique du système de  n_diff  équations différentielles écrit dans eqdiff.

Il reçoit pour cela du programme principal le tableau  ind  des valeurs de la variable indépendante (le temps par exemple) pour lesquelles il doit calculer les valeurs des variables à intégrer. C'est pourquoi, à la différence de la méthode algébrique précédente, il n'y a pas à utiliser une boucle  for...npt  pour l'intégration.

Les variables à intégrer seront rangées dans le tableau  ca  que nous avons déjà évoqué. Les numéros des variables à intégrer doivent être contigus, mais la première de ces variables ne doit pas obligatoirement avoir le numéro 0 : c'est pourquoi il faut indiquer à l'intégrateur ce numéro, à l'aide de la variable  first_var (par contre, dans eqdiff, la première variable porte toujours l'indice 0, la correspondance étant faite justement par srkvi). Les tableaux ci-dessous montrent les correspondances entre ces diverses variables :

1.   Variables globales de Sa
Cond. initiales ← t →
ind[0] (t=0) ind[1]    ...    ind[i]    ...    ind[npt-1]
ca[0][0] ca[0][1] ... ca[0][i] ... ca[0][npt-1]
... ... ... ... ... ...
ca[first_var][0] ... ... ca[first_var][i] ... ...
... ... ... ... ... ...
ca[first_var+n_diff-1][0] ... ... ca[first_var+n_diff-1][i] ... ...
... ... ... ... ... ...
ca[nvar-1][0] ... ... ca[nvar-1][i] ... ca[nvar-1][npt-1]


2.  Correspondance eqdiff / ca[ ][ ]

eqdiff

ca[0][i]
...
y[0] ←  ca[first_var][i]
... ←  ...
y[n_diff-1] ←  ca[first_var+n_di ff-1][i]
...
ca[nvar-1][i]

Au temps courant t (ind[i]), correspond la colonne vert-clair des ca dans le tableau 1. Dans cette colonne, les éléments contigus ca[first_var][i] à ca[first_var+n_diff-1][i] sont envoyés dans eqdiff, respectivement à y[0] ... y[n_diff-1] (tableau 2).

De même que npt est le nombre de colonnes (points de calcul) de ca, nvar est son nombre de lignes, c'est-à-dire le nombre total de variables du modèle. Nous admettrons que nvar = nv_mod (ce ne sera plus vrai lors du traitement simultané de plusieurs expériences). Noter que, les indices commençant à zéro, ils se terminent toujours au nombre d'éléments moins un.

Les tableaux 1 et 2 ci-dessus ne décrivent que la partie visible de ce qui se passe réellement : en réalité, eqdiff n'est pas appelé seulement pour les valeurs ind[i] de la variable indépendante mais beaucoup plus souvent, pour des valeurs intermédiaires générées par l'intégrateur numérique srkvi, de façon invisible pour vous, dans le but d'assurer la précision de l'intégration. Cependant, la correspondance est bien comme décrite ici.

Pour l'instant, nous laisserons Sa gérer les autres arguments de srkvi. Dans notre cas, nous devrons donc juste écrire n_diff = 1; et first_var = 0; dans le module Identification.

Nous pourrions sauver ce nouveau fichier modèle et il devrait aboutir exactement au même résultat que le précédent. Mais nous allons lui ajouter quelque chose. Il serait intéressant, par exemple, d'avoir aussi la variation de la concentration [B] et éventuellement celle d'une grandeur mesurable dépendant des deux concentrations, disons l'absorbance, en supposant connus les coefficients d'extinction molaire des espèces A et B à une longueur d'onde donnée. Pour cela, insérez de nouveau par la méthode devenue habituelle un élément for loop npt des Templates juste après l'appel de srkvi (ou tapez- la directement) et éditez-la de façon à avoir le programme complet suivant (les éléments nouveaux sont en rouge) :

//monomol_2.cpp // name of this file (simple comment)
//----------------------------------------------------------------------------
#include"global.h"
//----------------------------------------------------------------------------
void Identification(Modele& modele)
{
modele.Fichier = String(__FILE__);
modele.Version = String(__DATE__) + String(" ") + String(__TIME__);
modele.Auteur = "Robinson"; // Author (optional)
nom_syst = "monomol_2"; // name of the model (recommanded, no space)
n_diff = 1; // number of differential equations
first_var = 0; // number of the 1st variable to be integrated
nv_mod = 3; // number of variables of the model (v 3.3)
nexp = 1; // number of experiments (v 3.3)
}
//----------------------------------------------------------------------------
void eqdiff (Sa_data x, Sa_data* y, Sa_data* dy)
{
   dy[0] = - p[0]*y[0]; // dA/dt
}
//----------------------------------------------------------------------------
void fappel()
{
   srkvi(n_diff, &ca[first_var], ind, npt, h0, tol, iset, jacob, h_compt, c_min);
   for (int i = 0; i < npt; ++i)
   {
      ca[1][i] = ca[0][0] - ca[0][i]; // B
      ca[2][i] = p[1]*ca[0][i] + p[2]*ca[1][i]; // absorbance
   }
}
//----------------------------------------------------------------------------

télécharger monomol_2.cpp

Sauvez ce fichier sous un nouveau nom, par exemple monomol_2.cpp.

La concentration B, affectée à la variable 1, est calculée par l'équation de conservation B = A0 - A, avec ca[0][0] = A0 et ca[0][i] = A courant (on a supposé B0 = 0).

L'absorbance est affectée à la variable 2, et on utilise deux nouveaux paramètres p[1] et p[2] pour les coefficients d'extinction molaire.

La concentration de B pourrait être calculée de façon équivalente sous sa forme différentielle. Il faudrait alors initialiser
n_diff = 2;
et les fonctions eqdiff et fappel deviendraient :

void eqdiff (Sa_data x, Sa_data* y, Sa_data* dy)
{
   dy[0] = - p[0]*y[0]; // dA/dt
   dy[1] = - dy[0]; // dB/dt qui pourrait encore être écrit : dy[1] = p[0]*y[0];
}
//----------------------------------------------------------------------------
void fappel()
{
   // calcul de A et B par intégration :
   srkvi(n_diff, &ca[first_var], ind, npt, h0, tol, iset, jacob, h_compt, c_min);
   for (int i = 0; i < npt; ++i)
   {
      ca[2][i] = p[1]*ca[0][i] + p[2]*ca[1][i]; // absorbance
   }
}

Le système complet d'équations différentielles "contient" les équations de conservation. Mais il est en général préférable d'utiliser explicitement ces dernières.

Le fichier monomol_2.cpp doit apparaître maintenant dans le premier champ de File manager. Appuyer sur Mod copy pour en faire votre nouveau modèle, et compilez pour faire le nouvel exécutable correspondant : monomol_2.exe.

Lancez-le (Run).

Il s'ouvre toujours avec none comme fichier de commande (.sac). Le plus simple est de faire lire le fichier précédent monomol_1.sac (onglet Général, volet Fichier de commande, bouton Lire). Une fois lu, il faut l'adapter au nouveau programme :

- onglet Paramètres : ajoutez les 2 paramètres p[1] et p[2] correspondant aux coefficients d'extinction molaire. Baptisez-les epsA et epsB, et affectez-leur des valeurs, 10000 et 3000, par exemple.

- onglet Variables : ajoutez les 2 nouvelles variables correspondant à ca[1][0] et ca[2][0], [B] et abs. Comme on procède cette fois par intégration numérique, il est impératif de donner les valeurs initiales des variables ca[0][0]et ca[1][0], par exemple 1e-3 et 0, respectivement. De plus, cochez, en cliquant deux fois, la case "obs" (pour observable) de la variable n° 0 : ainsi, après la simulation, la fenêtre graphique tracera automatiquement sa courbe représentative.

- onglet Général : dans le volet Intégration numérique, le nombre d'équations différentielles doit être affiché (1, ou 2 si vous avez opté pour la version en note ci-dessus). Mettez la tolérance à 5e-3 (5×10−3) et c_min à 1e-8. Ces paramètres d'intégration conviendront dans la plupart des cas. Mettez le pas max. à une valeur inférieure ou égale à l'incrément (volet Var. indépendante). Vous pouvez également enfoncer le bouton Auto : Sa adaptera alors automatiquement le pas max. (cette option doit être évitée seulement dans des cas d'intégration particulièrement difficiles ; c'est loin d'être le cas ici).

Sauvez le nouveau fichier .sac, par exemple sous le nouveau nom monomol_2.sac.

télécharger monomol_2.sac

Dans le menu Fichier de la fenêtre principale de Sa, vous pouvez, si vous le voulez, activer la fonction mémorisation de la dernière session. Ainsi, lorsque vous relancerez le même exécutable, il rechargera automatiquement le dernier fichier .sac utilisé et se configurera avec toutes les options de la dernière session. Cela est très pratique dans certains cas, gênant dans d'autres. A vous de voir. En cas de problème dû à cette option, il est toujours possible de relancer sans mémoire de la dernière session, toujours dans le menu Fichier.

Lancez une simulation.

Vous devez obtenir une courbe d'évolution de A, rigoureusement identique à la précédente.

Sur le même onglet de graphique, vous pouvez ajouter la courbe de B : sélectionnez la en cliquant sur sa ligne, puis cliquez sur la flèche rouge orientée vers le graphique.

Créez un nouvel onglet, avec Page neuve. Vous allez y tracer B en fonction de A. Pour cela : appuyez sur le bouton Y/X, tapez 1 (numéro de B) du côté Y, et 0 (numéro de A) du côté X, puis appuyez sur le bouton à la diagonale de Y/X. Vous venez de tracer une magnifique droite de conservation : A + B = A0 + B0.

Créez encore un nouvel onglet, tracez-y la courbe d'absorbance.

Ce premier tour du logiciel est achevé. C'était le but principal de ce premier exercice...

mais ne le quittez pas sans faire un peu de cinétique :

● vérifiez qu'on peut prendre l'origine n'importe où sur la courbe (à un temps différent de 0) et trouver toujours la même valeur de t1/2 (utilisez les coordonnées du curseur pour faire cette vérification, ainsi que les suivantes).

● faites varier A0, sans changer k : vérifiez que t1/2 ne bouge pas

● faites varier k : vérifiez que t1/2 varie en sens inverse, retrouvez la valeur de k en examinant la courbe.

● retrouvez la valeur de k (par le t1/2) sur la courbe d'absorbance (vous ne l'avez pas encore vu dans le cours, mais vous devriez y arriver)