d6.04.01 Utilitaires d’impression de messages#
Résumé :
On présente dans ce document les utilitaires d’émission de messages d’information, d’erreur ou d’alarme en fortran (ou en python) (routine U2MESG en particulier) ainsi que le mécanisme de levée d’exception (routine UTEXCM).
Table des matières
Type de messages#
Les unités logiques d’impression sont établies en début d’exécution du travail, par le superviseur, les impressions émises par les routines décrites dans les paragraphes suivants seront effectuées sur ces unités logiques sans possibilité de redirection.
Les messages émis seront dirigés uniquement en fonction de leur type :
Code |
Type de message |
Fichiers de sortie |
F |
Message d’erreur fatale, l’exécution s’arrête après l’impression du message. |
MESSAGEERREURRESULTAT |
E |
Message d’erreur, l’exécution continue (un peu) cf.[§:ref:2.2 <RefHeading__32142778> ]. |
MESSAGEERREURRESULTAT |
A |
Message d’alarme. |
MESSAGERESULTAT |
I |
Message d’information. |
MESSAGE |
Z |
Levée d’exception récupérable en python |
Les messages de type F#
Ce type de message est suivi d’un arrêt immédiat de l’application, il est utilisé dans le cadre de la détection d’erreur grave ne pouvant permettre la poursuite normale d’une commande Aster. L’émission d’un message d’erreur F provoque l’arrêt de l’exécution.
Par défaut pour les «vrais» utilisateurs (si le mot clé DEBUT / CODE n’est pas utilisé), l’exécution s’arrête après avoir validé les concepts qui peuvent l’être :
les concepts produits par les commandes déjà exécutées
Le concept en cours de création si la commande l’a prévu (par exemple, pour la commande STAT_NON_LINE, les pas de temps déjà archivés sont validés).
En revanche, si le fichier de commande utilise DEBUT / CODE, le code s’arrête immédiatement et appelle la routine abort() afin de créer un «core file» utilisable par le débogueur post-mortem.
Les messages de type E#
Ce type de message permet d’analyser une série d’erreurs avant l’arrêt du programme. Par exemple, l’analyse syntaxique du fichier de commandes par le Superviseur ou l’analyse du fichier de maillage par la commande LIRE_MAILLAGE.
L’émetteur d’un message de type E doit émettre un message de type F à la fin de son analyse.
Les messages de type A#
Il ne faut pas abuser des messages d’alarme de type A qui peuvent inquiéter inutilement les utilisateurs. Le message doit être clair et comporter des pistes pour éviter cette alarme.
Le nombre de messages d’alarme est limité automatiquement à 5 messages successifs identiques.
Il est recommandé aux utilisateurs qui ont des messages de type A de “réparer” leur fichier de commandes pour les faire disparaitre.
Les messages de type I#
Les messages I sont des messages d’information .
Les messages de type Z#
Les messages Z sont des messages permettant le mécanisme des «exceptions» . Ce type de message n’est utilisé que dans les 2 routines utexcm et utexcp. et ne doivent pas l’être ailleurs ! Voir [§ 8 ] pour les exceptions en général.
Fonctionnement général#
Nous partons d’un exemple pour présenter le mode de fonctionnement des utilitaires d’impression de message:
Exemple#
Message imprimé
!-------------------------------------------------------!
! <A> <CHATON_2> !
! !
! Le petit chaton est de couleur rose. !
! !
! Ceci est une alarme. Si vous ne comprenez pas le sens !
! de cette alarme, vous pouvez obtenir des résultats !
! inattendus !
!-------------------------------------------------------!
Ce message utilisateur Le petit chaton est de couleur rose. est constitué de deux parties:
A : le texte fixe Le petit chaton est de couleur .
B : le texte variable rose qui représente le contenu d’une variable de type caractère.
Pour mettre en œuvre dans le fortran ou dans le python l’impression de ce message, il faut :
décrire dans un catalogue python la partie fixe (A) du message, avec le format des variables à imprimer
instrumenter le sous-programme fortran ou la fonction python pour provoquer l’impression du message.
Appel FORTRAN
SUBROUTINE CHATON(...,...)
...
...
IF(I.EQ.1) THEN
VALK = 'ROSE'
CALL U2MESK ('A','CHATON_2',1,VALK)
ENDIF
...
...
END
Les arguments du sous-programme U2MESK :
‘A’ : précise que l’on imprime un message de type alarme
‘CHATON_2’ : est l’identificateur du message : CHATON est le nom du catalogue de message chaton.py et le chiffre 2 indique que l’on prendra dans ce catalogue le message n°2.
1: on imprime une seule variable caractère
VALK : variable caractère à imprimer.
Catalogue message: chaton.py
cata_msg = {
1 : _(u"""
Le petit chat est bien de couleur verte Ouf!
"""),
2 : _(u"""
Le petit chat est de couleur %(k1)s.
"""),
3 : _(u"""
Le petit chat a %(i1)d pattes et %(i2)d yeux.
"""),
4 : _(u"""
Le petit chat pèse %(r1)f kilogrammes.
"""),
5 : _(u"""
ATTENTION: Votre chat est bizarre, il :
- a plus de 4 pattes, il en a %(i1)d,
- est de couleur %(k1)s et %(k2)s,
- est trop gros, il pèse (%(r1)f kilogrammes.
On arrête les frais, ce n'est pas un chat !!
"""),
}
Utilitaires fortran#
Nom |
Fonction |
U2MESS |
Imprime un message simple |
U2MESK |
Imprime à la fois un message et des valeurs de type caractère |
U2MESI |
Imprime à la fois un message et des valeurs de type entière |
U2MESR |
Imprime à la fois un message et des valeurs de type réelle |
U2MESG |
Imprime à la fois un message, des valeurs de type caractère, entière et réel |
Impression de messages simples#
SUBROUTINE U2MESS( TYPE , IDMESS)
TYPE |
IN |
Type de message (E,F,A,I) |
IDMESS |
IN |
identificateur du message |
Exemple:
CALL U2MESS('A','CHATON_1')
Imprime le message suivant :
<A> <CHATON_1>
Le petit chat est de couleur verte Ouf !
Impression de messages et des valeurs de type caractère#
SUBROUTINE U2MESK( TYPE , IDMESS , NK , VALK )
TYPE |
IN |
Type de message (E,F,A,I) |
IDMESS |
IN |
Identificateur du message |
NK |
IN |
Nombre paramètres de type caractère |
VALK |
IN |
Valeurs des paramètres de type caractères |
Exemple :
VALK = 'ROSE'
CALL U2MESK('A',CHATON_2', 1, VALK)''
Imprime le message suivant :
<A> <CHATON_2>
Le petit chat est de couleur rose.
Impression de messages et des valeurs de type entière#
SUBROUTINE U2MESI( TYPE , IDMESS , NI , VALI)
TYPE |
IN |
Type de message (E,F,A,I) |
IDMESS |
IN |
Identificateur du message |
NI |
IN |
Nombre de paramètres de type entier |
VALI |
IN |
Valeurs des paramètres de type entier |
Exemple :
VALI (1) = 4
VALI (2) = 2
CALL U2MESI('A','CHATON_3', 2, VALI)''
Imprime le message suivant :
<A> <CHATON_3>
Le petit chat a 4 pattes et 2 yeux.
Impression de messages et des valeurs de type réel#
SUBROUTINE U2MESR( TYPE , IDMESS , NR , VALR)
TYPE |
IN |
Type de message (E,F,A,I) |
IDMES |
IN |
Identificateur du message |
NR |
IN |
Nombre paramètres de type réel |
VALR |
IN |
Valeurs des paramètres de type réel |
Exemple :
VALR (1) = 130.
CALL U2MESR('A','CHATON_4', 1, VALR)''
Imprime le message suivant :
<A> <CHATON_4>
Le petit chat pèse 130.0 kilogrammes.
Impression de messages des valeurs de type caractères, entières et réelles#
SUBROUTINE U2MESG( TYPE , IDMESS , NK , VALK , NI , VALI , NR , VALR )
TYPE |
IN |
Type de message (E,F,A,I) |
IDMESS |
IN |
Identificateur du message |
NK |
IN |
Nombre de paramètres de type caractère |
VALK |
IN |
Valeurs des paramètres de type caractère |
NI |
IN |
Nombre de paramètres de type entier |
VALI |
IN |
Valeurs des paramètres de type entier |
NR |
IN |
Nombre de paramètres de type réel |
VALR |
IN |
Valeurs des paramètres de type réel |
Exemple :
VALK (1) = “bleue” VALK (2) = “rose” VALI = 5 VALR = 130. U2MESG(“A”,”CHATON_5”, 2, VALK, 1 , VALI, 1,VALR)””
Imprime le message suivant :
<E> <CHATON_5>
ATTENTION: Votre chat est bizarre, il :
- a plus de 4 pattes, il en a 5 ,
- est de couleur bleue et rose,
- est trop gros, il pèse 130.0 kilogrammes.
On arrête les frais, ce n'est pas un chat !!
Impression d’un message en plusieurs « morceaux »#
Il est parfois pratique d’émettre un message «par morceaux» c’est à dire d’appeler plusieurs fois la routine U2MESG. Ceci est en pricipe impossible pour les messages d’erreur fatale (F/E) car le code s’arrête dès le premier message !
Par ailleurs, on souhaite que le message complet apparaisse à l’utilisateur comme un message unique. En particulier on veut qu’il apparaisse dans un même cadre.
Pour cela, on dispose du mécanisme “A+”, “F+”, … Le principe est d’ajouter un “+” au type du message tant que le message n’est pas terminé. Le dernier message du groupe (sans le “+”) termine le message.
On pourra par exemple écrire un message en 2 morceaux en écrivant :
CALL U2MESK(“F+”, “FONCT0_11”,1,NOMF)
CALL U2MESR(“F”, “FONCT0_26”,3,VALR)
Ce qui, associé au catalogue suivant :
11 : _(u » » »
L’interpolation de la fonction “%(k1)s” n’est pas autorisée.
Le type d’interpolation de la fonction vaut “NON”
-> Risque & Conseil :
Voir le mot-clé INTERPOL des commandes qui créent des fonctions.
« « »),
26 : _(u » » »
abscisse demandée : %(r1)f
intervalle trouvé : [%(r2)f, %(r3)f]
« « »),
conduira à un message ressemblant à :
!———————————————————————-!
! <F> <FONCT0_11> !
! !
! L’interpolation de la fonction fonc3 n’est pas autorisée. !
! Le type d’interpolation de la fonction vaut “NON” !
! !
! -> Risque & Conseil : !
! Voir le mot-clé INTERPOL des commandes qui créent des fonctions. !
! !
! abscisse demandée : 105. !
! intervalle trouvé : [0., 100.] !
!———————————————————————-!
Remarques:
Dans un groupe de messages produisant un message «par morceaux», le type des différents messages dot être le même (F/A/I).
L’identifiant du message imprimé est celui du premier message du groupe.
Utilitaire Python#
L’impression des messages dans les fichiers python est réalisée par la méthode UTMESS.
Nom |
Fonction |
UTMESS |
Imprime à la fois un message, des valeurs de type caractères, entières et réelles |
def UTMESS( type, idmess, valk, vali, valr)
type |
IN |
Type de message (E,F,A,I) |
idmess |
IN |
identificateur du message |
valk |
IN |
Valeurs des paramètres de type caractères |
vali |
IN |
Valeurs des paramètres de type entier |
vali |
IN |
Valeurs des paramètres de type réel |
Contrairement au fortran, il n’y a qu’une fonction UTMESS car les arguments valk, vali et valr sont optionnels (cf. Python Tutorial, keyword arguments). La fonction de U2MESI est réalisée de cette manière :
UTMESS('A', 'MESSAGE_1', vali=(1, 2, 3))
Format d’impression dans les catalogues de message#
Format |
Fonction |
%(kn)s |
Format d’impression de la nièmevaleur de type caractère |
%(in)d |
Format d’impression de la nièmevaleur de type entière |
%(rn)f |
Format d’impression de lanièmevaleur de type réelle (on utilise parfois le format %g, %e, %F, %E, %G) |
En savoir plus sur les codes de formattage des chaines : voir String formatting operations de la documentation Python.
Il est nécessaire que les messages soient des chaines «unicode» (notez le «u» devant « « ») car les messages contiennent des caractères non-ascii.
Quelques règles simples doivent être suivies afin de conserver un maximum d’homogénéité entre les quelques 6.000 messages:
Faire des phrases, pas d’abréviations, pas de noms de routines, de structure de données qui sont éventuellement connus des développeurs mais pas des utilisateurs.
Ne pas faire de «mise en page»: pas de saut de ligne superflu, éviter de former des colonnes, etc. car il sera difficile de les conserver lors de la traduction.
Exemples#
Identificateur du message |
Catalogue de message ( chaton.py ) |
Appel fortran/python |
|
cata_msg = { |
|
CHATON_1 |
1 : _(u”““- Le petit Chat est bien de couleur verte Ouf! “““), |
→ Fortran CALL U2MESS (’A’,’CHATON_1’) → Python UTMESS(’A’,’CHATON_1’) |
CHATON_2 |
2 : _(u”““- Le petit chat est de couleur %(k1)s “““), |
→ Fortran CALL U2MESK (’I’,’CHATON_2’,1,COUL)→ Python UTMESS (’I’,’CHATON_2’,valk=…) |
CHATON_3 |
3 : _(u”““- Le petit chat a %(i1)d pattes et %(i2)d yeux. “““), |
→ Fortran VALI(I)= NBPATT VALI(2)= NBYEUXCALL U2MESI (’I’,’CHATON_3’,2,VALI,)→ Python UTMESS(’I’,’CHATON_2’,vali=…) |
CHATON_4 |
4 : _(u”““- Le petit chat pèse %(r1)f kilogrammes. “““), |
→ Fortran VALR = POIDS CALL U2MESR (’I’,’CHATON_4’,1,VALR,)→ Python UTMESS(’I’,’CHATON_4’,valr=…) |
CHATON_5 |
5 : _(u”““- ATTENTION: Votre chat est bizzare, il :→ a plus de 4 pattes, il en a %(i1)d,→ est de couleur %(k1)s et %(k2)s, → est trop gros, il pèse(%(r1)f kilogrammes.On arrête les frais, ce n’est pas un chat !! “““), |
→ Fortran VALI = CINQ VALK(1)=’BLEU’VALK(2) = ‘ROSE’ VALR= 130. CALL U2MESG (’E’,’CHATON_4’,2,VALK,2,VALI,1,VALR,)→ Python UTMESS(’E’,’CHATON_5’,valk,vali,vakr) |
} |
Utilitaires de levée d’exception#
En cours d’écriture
Les utilitaires UTEXCP et UTEXCM permettent de lever une exception python depuis le fortran et de la transmettre au jeu de commande. Cette exception peut être récupérée dans le fichier de commande (ou une macro-commande) par un bloc try/except.
Les exceptions étant des cas particuliers d’erreur <F>, si elles ne sont pas récupérées, le superviseur termine le calcul comme après une erreur <F> ordinaire (fermeture et recopie de la base). Seule l’exception FatalError échappe à la règle puisqu’elle équivaut à une erreur <F> (et encore on verra un peu plus loin que ce comportement est modifiable).
Le mécanisme d’exception permet d’essayer une commande puis de reprendre la main si celle-ci échoue en levant une exception particulière.
Ce fonctionnement est particulièrement utilisé dans les macro-commandes, soit pour se comporter différemment selon le contexte, soit pour émettre un message plus parlant à l’utilisateur que celui qui aurait été émis par une commande fille.
Remarque:
L’utilisation des exceptions et surtout des blocs try / except n’a de sens qu’en mode PAR_LOT=’NON’
Mise en œuvre dans le source#
On présente ici la mise en œuvre du mécanisme des exceptions dans le source fortran et python du point de vue du développeur. On abordera un peu plus bas les exceptions avec la vision “utilisateur” (§ 8.4 ).
Pour la description de ce qu’est une exception, les mécanismes de levée (raise) et d’interception (except), on se reportera à la Description des exceptions du Tutorial Python.
“Lever une exception” signifie émettre un signal avec (souvent) des éléments de contexte pour permettre au programme appelant de réagir ainsi :
je comprends le signal et je prends telle décision en conséquence
je ne comprends pas le signal et je m’arrête (en émettant un autre signal au programme appelant du niveau supérieur)
j’ignore le signal et je laisse le programme appelant du niveau supérieur traiter le signal
Et ainsi de suite, sachant qu’au plus haut, c’est l’interpréteur Python lui-même qui prendra la décision d’interrompre l’exécution.
Syntaxiquement et schématiquement, le fonctionnement est le suivant :
try:
...
Instructions à exécuter qui peuvent par exemple lever 3 exceptions
différentes : UneExceptionParticulière, UneAutreException, EncoreUneAutre
...
except UneExceptionParticulière, arguments:
...
On exécutera ces instructions si l'exception "UneExceptionParticulière" est levée. On peut utiliser les "arguments" utilisés lors de la levée de l'exception.
Dans le cas le plus simple (et fréquent), "arguments" est un message qui peut être imprimé avec "print" ou utilisé comme chaîne de caractères avec "str(arguments)".
...
except UneAutreException, arguments2:
...
Instructions à exécuter si l'exception UneAutreException est levée.
...
Supposons que le bloc d’instructions sous le try lève l’exception EncoreUneAutre (qui n’est pas interceptée par un bloc except), l’exécution s’arrête avec un message du type :
Traceback (most recent call last):
File ".......", line 3, in <.......> <<< permet de dire où s'est produite l'exception
EncoreUneAutre: ...... <<< éléments de contexte (arguments) fournissant
des détails sur les raisons de la levée d’exception
Pour les autres mécanismes, try/finally ou try/except/else, on se reportera à la documentation Python.
Levée d’exception dans Code_Aster#
Le plus simple : en Python, c’est-à-dire dans le fichier de commandes ou dans une macro-commande, il suffit de faire :
if nbre_iterations > nbre_maxi_autorise:
raise aster.NonConvergenceError, "Absence de convergence avec le nombre d'itérations autorisé"
Dans le source fortran (exemple dans nmerro.f qui traite les erreurs dans STAT_NON_LINE) :
...
ELSE IF (ITEMAX) THEN
CALL UTEXCP(22,'MECANONLINE_83')
...
où
22 est le numéro de l’exception
‘MECANONLINE_83’ est l’identifiant du message à imprimer
En effet, les exceptions propres à Code_Aster sont numérotées pour être accessibles facilement depuis le fortran :
numéro de l’exception |
Description |
Nom de l’exception dans le module aster |
Type erreur |
20 |
Erreur fatale |
FatalError |
F |
21 |
Erreur non fatale |
error |
F |
22 |
Non convergence |
NonConvergenceError |
F |
23 |
Echec intégration du comportement |
EchecComportementError |
F |
24 |
Bande de fréquence vide |
BandeFrequenceVideError |
F |
25 |
Matrice singulière |
MatriceSinguliereError |
F |
26 |
Echec de traitement du contact |
TraitementContactError |
F |
27 |
Matrice de contact non inversible |
MatriceContactSinguliereError |
F |
28 |
Manque de temps CPU |
ArretCPUError |
F |
29 |
Echec du pilotage |
PilotageError |
F |
Remarques
Les exceptions sont définies dans le module aster (astermodule.c). Ainsi, on y accède par aster.error.
A part FatalError, toutes les exceptions dérivent de errorqui représente donc l’enveloppe des erreurs <F>.
Le comportement en cas d’erreur fatale (FatalError ) est modifiable par l’utilisateur [U1.03.01], ce choix est déterminé dans les commande DEBUT/POURSUITE [U4.11.01],[U4.11.03] mot-clé facteur ERREUR_F. Dans les macro-commandes, on utilisera la fonction aster.onFatalError(arg)pour modifier ce comportement.
Levée d’une exception avec impression d’un message#
CALL UTEXCP( CODE, IDMESS )
CODE |
IN |
Numéro de l’exception |
IDMESS |
IN |
Identificateur du message |
Exemple :
CALL UTEXCP(23,”CHATON_7”)
Levée d’exception avec impression de messages et de valeurs de type caractères, entières et réelles#
CALL UTEXCM( CODE, IDMESS, NK, VALK, NI, VALI, NR, VALR)
CODE |
IN |
numéro de l’exception |
IDMESS |
IN |
Identificateur du message |
NK |
IN |
Nombre de paramètres de type caractère |
VALK |
IN |
Valeurs des paramètres de type caractère |
NI |
IN |
Nombre de paramètres de type entier |
VALI |
IN |
Valeurs des paramètres de type entier |
NR |
IN |
Nombre de paramètres de type réel |
VALR |
IN |
Valeurs des paramètres de type réel |
Exemple :
VALI (1) = NDIM1
VALI (2) = NDIM2
VALR = 5.D0
CALL UTEXCM(24,'CHATON_12', 0,' ',2, VALI,1,VALR)
Exemple d’utilisation#
Dans cet exemple, on souhaite :
en cas de non-convergence de STAT_NON_LINE, relancer les calculs en augmentant le nombre d’itérations,
arrêter les calculs si une autre erreur se produit.
Cette utilisation est illustrée dans le cas-test ssnp125a.
Programmation
On lève l’exception NonConvergenceError qui porte le numéro 22 :
...
ELSE IF ((.NOT.CONVER) .AND. ITEMAX .AND. (.NOT.ARRET)) THEN
ITAB(1) = NUMORD
ITAB(2) = ITERAT
CALL UTEXCM(22,'MECANONLINE_85', 0, K8B, 2, ITAB, 0, RTAB)
END IF
Fichier de commande
try :
STATNL=STAT_NON_LINE(...)
except aster.NonConvergenceError, message:
# non convergence
print "on continue en augmentant le nombre d'itérations"
STATNL=STAT_NON_LINE(reuse=STATNL,
...
CONVERGENCE=_F(ITER_GLOB_MAXI=400,)
…)
Fichier message : mecanonline.py
85 : _(u"""
Arret : absence de convergence au numéro d'instant : %(i1)d
lors de l'itération : %(i2)d
"""),
Message imprimé
!-----------------------------------------------------------------------!
! <EXCEPTION> <MECANONLINE_85> !
! !
! !
! Arret : absence de convergence au numéro d'instant : 123 !
! lors de l'itération : 51 !
! !
! !
!-----------------------------------------------------------------------!