168 | | * De nombreuses variables possèdent un pendant isotopique (souvent repéré par un **x** additionnel dans le préfixe) ; les opérations s'appliquant à ces variables comme à leurs descendantes forçent pour l'instant la création explicite de ces descendantes ainsi que la duplication des lignes de code correspondant aux opérations en question. |
169 | | L'utilisation d'un pointeur semble toute indiquée. Par exemple, pour **q_seri** étendue à ses isotopes, pour l'exemple donné plus haut, il faudrait pouvoir écrire: |
| 168 | * De nombreuses variables possèdent un pendant isotopique (souvent repéré par un **x** additionnel dans le préfixe) ; les opérations s'appliquant à ces variables comme à leurs descendantes forcent pour l'instant la création explicite de ces descendantes ainsi que la duplication des lignes de code correspondant aux opérations en question. |
| 169 | L'utilisation d'un pointeur semble toute indiquée. Par exemple, pour **q_seri** (exemple purement illustratif: qx doit être mis à jour en fin de pas de temps, non pas à chaque ajout de tendance comme q_seri: q_seri ne peut donc être un alias de qx, mais doit être sa copie partielle en début de pas de temps !) étendue à ses isotopes, pour l'exemple donné plus haut, il faudrait pouvoir écrire: |
183 | | Dans le cas de **q_seri**: |
| 186 | Lorsque typ=='a', on se contente d'un alias (POINTER), alors que pour typ=='c', on copie la variable concernée (ALLOCATABLE).\\ |
| 187 | Dans les deux cas, le contenu est accessible via les composantes out(:)%v. |
| 188 | |
| 189 | La fonction **defVar** encapsule les opérations nécessaires à la création de l'objet voulu: |
| 190 | {{{ |
| 191 | FUNCTION defVar(name,typ,nGen) RESULT(out) |
| 192 | TYPE(tr2), ALLOCATABLE :: out(:) !--- Output object |
| 193 | CHARACTER(LEN=*), INTENT(IN) :: name !--- Tracer name |
| 194 | CHARACTER(LEN=*), OPTIONAL, INTENT(IN) :: typ !--- 'a'lias or 'c'opy |
| 195 | INTEGER, OPTIONAL, INTENT(IN) :: nGen !--- Number of generations kept |
| 196 | INTEGER :: iq, ng, k |
| 197 | CHARACTER(LEN=1) :: tp |
| 198 | LOGICAL, ALLOCATABLE :: ll(:) |
| 199 | tp = 'c'; IF(PRESENT(typ)) tp = typ |
| 200 | ng = 2 ; IF(PRESENT(nGen)) ng = nGen |
| 201 | ALLOCATE(ll(nqtrue)); ll(idxTracer(name)) = .TRUE. !--- Main tracer index |
| 202 | DO iq=1,nqtrue !--- Identify the kept tracers |
| 203 | IF(tracers(iq)%igen>ng) EXIT |
| 204 | IF(ll(idxTracer(tracers(iq)%prnt))) ll(iq)=.TRUE. !--- Tracer "name" is an ancestor |
| 205 | END DO |
| 206 | ALLOCATE(out(COUNT(ll))); out(:)%typ = typ; k = 0 |
| 207 | DO iq=1,nqtrue; IF(.NOT.ll(iq)) CYCLE |
| 208 | k = k + 1; out(k)%iq = iq |
| 209 | IF(tp=='p') THEN; out(k)%v => qx(:,:,iq) |
| 210 | ELSE; out(k)%f = qx(:,:,iq); out(k)%v => out(k)%f; END IF |
| 211 | k = k+1 |
| 212 | END DO |
| 213 | END FUNCTION defVar |
| 214 | }}} |
| 215 | |
| 216 | Et pour **q_seri**, la syntaxe se réduit à (par défaut: copie de variables, 2 générations utilisées): |
188 | | La fonction **defVar** encapsule les opérations nécessaires: |
189 | | {{{ |
190 | | TYPE(tr2) FUNCTION defVar(name) RESULT(out) |
191 | | CHARACTER(LEN=*), INTENT(IN) :: name |
192 | | INTEGER :: ix, n |
193 | | ix = idxTracer(name) |
194 | | out%iq = [ix, tracers(ix)%ichild(:)] |
195 | | out%v = [ ( qx(:,:,out%iq(k)), k=1, SIZE(out(:), DIM=1) ) ] |
196 | | END FUNCTION defVar |
197 | | }}} |
198 | | On peut envisager d'ajouter un second argument à defVar: la génération maximale (2 dans l'exemple ci-dessus). |
199 | | La boucle typique pour une opération agissant sur une grandeur de génération 1 et ses dérivés isotopiques prend alors la forme (exemple pour **q_seri**): |
200 | | {{{ |
201 | | DO k=1,SIZE(t_seri%iq, DIM=1) |
202 | | Opérations sur t_seri%v(:,:,t_seri%iq(k)) |
| 221 | Si les opérations à pratiquer sur la vapeur et ses descendants sont identiques, la boucle suivante suffit: |
| 222 | {{{ |
| 223 | DO k=1,SIZE(t_seri, DIM=1) |
| 224 | Opérations sur t_seri(k)%v(:,:) |
205 | | Si l'objectif est d'agir directement sur des composantes de **qx**, sans création d'une variable spécifique **t_seri%v(:,:,:)**, il suffit de remplacer **t_seri%v(:,:,t_seri%iq(k))** par **qx(:,:,iq(k))**, où **iq(:)** est le vecteur d'undices non encapsulé dans un type dérivé. |
| 227 | Les informations des traceurs constituant cet objet sont accessibles via l'indice iq et le descripteur de traceurs tracers(:).\\ |
| 228 | Par exemple, le nom de la kième composante de **t_seri** est: {{{tracers(t_seri(k)%iq)%name}}}. |
260 | | La solution initiale (pas de base de données complète dans tout fichier **tracer_*.def** concernant des paramètres supplémentaires du type **tnat** ou **alpha_ideal**) semble donc préférable. |
| 283 | La solution initiale (pas de base de données complète dans tout fichier **tracer_*.def** concernant des paramètres supplémentaires du type **tnat** ou **alpha_ideal**) semble donc préférable.\\ |
| 284 | => Avis de Camille: les **tnat** sont des constantes immuables, et les **alpha** ne servent que pour l'initialisation: autant les garder en dur dans le code.\\ |
| 285 | => Idée: garder séparément d'infotrac, assez générique, toutes les grandeurs spécifiques. On pourrait donc imaginer un fichier **isotopes_params_mod.F90** où regrouper ces informations (tnat et alpha notamment), ou encore un fichier de paramètres (à lire comme tracers_*.def) qui ne serait pas susceptible d'être modifié. |