1 #!\bin/sh -e
   2 
   3 
   4 #============================================================================
   5 # TP6 : couplage et hack de stardis pour y développer ses propres couplages #
   6 #============================================================================
   7 
   8 # Voir le TP1 pour la prise en main du système d'exploitation EDIX.
   9 # Les commandes suivantes sont identiques à celles du début du TP1.
  10 
  11 . /home/lafrier/star-build/local/etc/stardis.profile
  12 mkdir TP6
  13 cd TP6
  14 
  15 
  16 #==========================================================
  17 # TP6 - Partie 1 : explication des couplages dans Stardis #
  18 #==========================================================
  19 
  20 # Intention : le modèle physique a été présenté en introduction. Ici on invite
  21 # le praticien à ouvrir le code pour se donner confiance sur ce qui est fait.
  22 
  23 # Partie 1.1 : partie théorique
  24 # -----------------------------
  25 #
  26 # Ajouter des informations complémentaires à l'introduction.
  27 # Introduire à cette occasion l'idée qu'il existe deux marches conductives
  28 # implémentées : delta-sphères et Walk-on-Spheres. Le Walk-on-sphere est plus
  29 # lisible et sera modifié dans le second exercice de ce TP6.
  30 
  31 # Prendre le temps d'expliquer la double randomisation au niveau d'une paroi
  32 # solide-solide puis solide-fluide.
  33 
  34 # Partie 1.2 : implémentation
  35 # ---------------------------
  36 
  37 # Expliquer rapidement l'édifice stardis en deux parties : un solveur et un
  38 # applicatif, qui reposent sur des bibliothèques tierces (ex : génération de
  39 # nombres aléatoires). En particulier, ils contiennent :
  40 #  - solveur : espaces de chemins, différents types d'observable (point sonde,
  41 #    image, etc) ...
  42 #  - applicatif : gestion des entrées / sorties utilisateur ...
  43 # Les deux sont installés via star-build qui gère automatiquement
  44 # l'installation de toutes les dépendances. L'exercice 3 de ce TP traite
  45 # spécifiquement de l'installation de stardis, mais nous n'en avons pas besoin
  46 # dans ce premier exercice. Ici, on s'intéresse en particulier au solveur. On
  47 # va aller regarder comment les espaces de chemins sont implémentés.
  48 # Le code source peut être lu dans le dossier défini ci-dessous :
  49 
  50 STARDIS_SRC=/home/lafrier/star-build/cache/stardis-solver/0.16/src/
  51 
  52 # Avant propos :
  53 # Code C89 avec un paradigme de programmation structurée.
  54 # On suppose que le lecteur est familier du langage C, en particulier des types
  55 # structurés et du concept de pointeur et de pointeur de fonction (faire
  56 # référence au "Livre de programmation littéraire" pour cela).
  57 # Sinon on conseille le livre "Le langage C Norme ANSI - 2nde édition" de
  58 # Kernighan et Ritchie. Ici on a une difficulté en plus qui est la
  59 # généricité : les fonctions appelées par la macro XD(), seront expansées par le
  60 # préprocesseur avec les termes _2d et _3d pour former deux nouvelles fonctions.
  61 # TODO
  62 # Faire un point avancé sur cela dans le "Livre de programmation littéraire".
  63 
  64 # Les éléments qu'il semble important de parcourir :
  65 
  66 # Partie 1.2.1 : fonction principale avec boucle MC et moyenne des réalisations
  67 # -----------------------------------------------------------------------------
  68 #
  69 # On choisit l'exemple de la fonction solve_one_probe dans le fichier
  70 # sdis_solve_probe_Xd.h. On fait ce choix parce que cette fonction est simple à
  71 # lire (par opposition à solve_probe présentée ensuite).
  72 
  73 vim "${STARDIS_SRC}"/sdis_solve_probe_Xd.h
  74 
  75 # Globalement, toujours la même structure :
  76 
  77 # static res_T
  78 # XD(solve_one_probe)
  79 #   (struct sdis_scene* scn,
  80 #    struct ssp_rng* rng,
  81 #    const struct sdis_solve_probe_args* args,
  82 #    struct accum* acc_temp,
  83 #    struct accum* acc_time)
  84 # La fonction solve_one_probe prend 5 paramètres en entrée, tous avec des types
  85 # structurés internes au solveur ; elle renvoie une valeur de type res_T qui
  86 # indique s'il y a eu une erreur d'exécution ou pas :
  87 #  - scn pointe vers une structure contenant les informations liées à la scène,
  88 #  - rng pointe vers une structure permettant la génération de nombres
  89 #    aléatoires,
  90 #  - sdis_solve_probe_args pointe vers une structure contenant les informations
  91 #    relatives à la simulation,
  92 #  - acc_temp pointe vers une structure qui stocke des informations sur les
  93 #    poids des réalisations pour estimer la température et la barre d'erreur
  94 #    associée,
  95 #  - idem pour acc_time concernant le temps de calcul.
  96 
  97 # Les accumulateurs sont d'abord vidés.
  98 # Pour chaque réalisation (FOR_EACH) :
  99 #  - le temps initial est enregistré,
 100 #  - un temps échantillonné sur la période d'intégration temporelle
 101 #  - la fonction probe_realisation appelée avec l'argument realis_args dont les
 102 #    champs ont été remplis.
 103 #  - le temps d'éxécution est calculé
 104 #  - les accumulateurs mis à jour avec le poids du chemin (température atteinte)
 105 #    et le temps de calcul
 106 
 107 
 108 # Partie 1.2.2 : pour chaque réalisation, comment est construit un chemin ?
 109 #                           par un appel de fonction, jusqu'à T->done == 1.
 110 # -------------------------------------------------------------------------
 111 
 112 cat "${STARDIS_SRC}"/sdis_realisation_Xd.h
 113 
 114 # Regarder la fonction XD(probe_realisation).
 115 # D'abord, le chemin est initialisé (temps et position de départ).
 116 # En fonction du milieu dans lequel se trouve le point sonde, le chemin
 117 # commencera en mode convectif ou bien conductif. Ces informations sont
 118 # enregistrées.
 119 
 120 # Si la condition initiale est atteinte, on ne lance pas le calcul. Sinon appel
 121 # à XD(sample_coupled_path). Le poids de MC sera le champ `value` de T.
 122 
 123 # Allons voir cette fonction sample_coupled_path.
 124 # On voit que, tant que le chemin n'est pas fini, ce qui se traduit par le champ
 125 # `done` de la structure pointée par T n'est pas mis à 1 : while(!T->done) {...}
 126 # Alors, on répète la même action :
 127 #  - On appelle la fonction `T->func(scn, ctx, rwalk, rng, T)` pour construire une
 128 #    portion de chemin.
 129 #  - Le `do {} while()` sert à recommencer l'action si la portion de chemin a été
 130 #    rejetée.
 131 #  - On identifie ensuite le mode physique dans lequel le chemin se trouve
 132 #    (conduction / convection ou rayonnement).
 133 #
 134 #
 135 # Partie 1.2.3 : construction d'une portion de chemin
 136 # ---------------------------------------------------#
 137 
 138 
 139 # Quelle que soit la physique, la fonction qui construit la portion de chemin a
 140 # toujours la même forme :
 141 #  - Récupérer des paramètres de contexte sur l'endroit où se trouve le chemin,
 142 #  - Calculs de jeux de probabilité basé sur les paramètres physiques
 143 #  - Tirage aléatoire selon ce jeu de probabilité pour déterminer la suite du
 144 #    chemin (spatio-temporel)
 145 #  - Si la condition initiale est atteinte, T->done = 1;
 146 #  - Mise à jour du chemin, en particulier de T->func pour le prochain mode
 147 #    physique
 148 
 149 # L'exercice consiste ici à faire le parallèle entre l'algorithme et le code
 150 # sur une seule des physiques. On choisit le cas de l'interface fluide-solide.
 151 
 152 # Ci-dessous, on pointe les fonctions implémentant les chemins dans les autres
 153 # physiques.
 154 
 155 # En fonction de la physique,
 156 #  - convection :
 157 #    sdis_heat_path_convective_Xd.h:XD(convective_path)
 158 #  - rayonnement :
 159 #    sdis_heat_path_radiative_Xd.h:XD(radiative_path)
 160 #  - conduction :
 161 #    XD(conductive_path)
 162 #    C'est en fait
 163 #      sdis_heat_path_conductive.c:conductive_path_3d
 164 #    qui est appelée, et qui redirige vers les deux marches distinctes :
 165 #      sdis_heat_path_conductive_wos_Xd.h:XD(conductive_path_wos)
 166 #      sdis_heat_path_conductive_delta_sphere_Xd.h:
 167 #        XD(conductive_path_delta_sphere)
 168 #  - interface :
 169 #    sdis_heat_path_boundary_Xd.h:XD(boundary_path)
 170 #    cette fonction renvoie ensuite vers
 171 #     - fluide-solide :
 172 #       sdis_heat_path_boundary_Xd_solid_fluid_picard1.h:
 173 #         XD(solid_fluid_boundary_picard1_path)
 174 #       On expliquera Picard dans le TP7.
 175 #     - interface solide-solide :
 176 #       sdis_heat_path_boundary_Xd_solid_solid.h:XD(solid_solid_boundary_path)
 177 
 178 # On présente maintenant le cas de l'interface fluide-solide. Beaucoup de
 179 # choses ! Donc on va guider la lecture en colorant les parties à commenter.
 180 # L'objectif n'est pas que l'étudiant comprenne les détails, mais qu'il sache
 181 # qu'il peut se référer au code, le lire et le comprendre en ayant le modèle
 182 # physique à côté.
 183 
 184 vim "${STARDIS_SRC}"/sdis_heat_path_boundary_Xd_solid_fluid_picard1.h
 185 
 186 # Les éléments à mettre en couleur dans l'énoncé du TP :
 187 #  h_conv = interface_get_convection_coef(interf, frag);
 188 #  h_cond = lambda / delta_m;
 189 #  h_radi_hat = 4.0 * BOLTZMANN_CONSTANT * ctx->That3 * epsilon;
 190 #  ...
 191 #  h_hat = h_conv + h_cond + h_radi_hat;
 192 #  ...
 193 #  p_conv = h_conv / h_hat;
 194 #  p_cond = h_cond / h_hat;
 195 #  ...
 196 
 197 #  /* Handle the net flux if any */
 198 #  res = XD(handle_net_flux)(scn, &handle_net_flux_args, T);
 199 
 200 #  /* Handle the external net flux if any */
 201 #  res = XD(handle_external_net_flux)(scn, rng, &handle_external_net_flux_args, T);
 202 #  ...
 203 
 204 #  /* Null collision */
 205 #  for(;;) {
 206 #    r = ssp_rng_canonical(rng);
 207 #    ...
 208 
 209 #    /* Switch in convective path */
 210 #    if(r < p_conv) {
 211 #      T->func = XD(convective_path);
 212 #      ...
 213 #      break;
 214 #    }
 215 
 216 #    /* Switch in conductive path */
 217 #    if(r < p_conv + p_cond) {
 218 #      ...
 219 #      res = XD(solid_reinjection)(scn, enc_ids[solid_side], &solid_reinject_args);
 220 #      ...
 221 #      break;
 222 #    }
 223 
 224 #    /* Sample a radiative path and get the Tref at its end. */
 225 #    ...
 226 #    res = XD(radiative_path)(scn, ctx, &rwalk_s, rng, &T_s);
 227 
 228 #    /* Get the Tref at the end of the candidate radiative path */
 229 #    res = XD(rwalk_get_Tref)(scn, &rwalk_s, &T_s, &Tref_s);
 230 
 231 #    h_radi = BOLTZMANN_CONSTANT * epsilon *
 232 #      ( Tref*Tref*Tref
 233 #      + Tref*Tref * Tref_s
 234 #      + Tref * Tref_s*Tref_s
 235 #      + Tref_s*Tref_s*Tref_s);
 236 
 237 #    p_radi = h_radi / h_hat;
 238 #    if(r < p_conv + p_cond + p_radi) { /* Radiative path */
 239 #      *rwalk = rwalk_s;
 240 #      *T = T_s;
 241 #      break;
 242 
 243 #    /* Null collision: the sampled path is rejected. */
 244 #    } else {
 245 #      ...
 246 #    }
 247 #  }
 248 
 249 # Astuce - Comment naviguer en autonomie ?
 250 # Utiliser l'outil grep pour rechercher la définition d'une structure dans tout
 251 # l'édifice stardis.
 252 
 253 # "Point théorique" sur les notions :
 254 #  - d'édition de code source, édition du fichier source par le programmeur ;
 255 #  - compilation du code source en un code interprêtable pour la machine.
 256 #    A cette étape il faut que les librairies statiques soient identifiées.
 257 #  - exécution de ce code interprêtable par la machine.
 258 #    Il faut spécifier le chemin vers cet exécutable par exemple`./a.out`,
 259 #    ou que l'exécutable soit placé dans les dossiers parcourus par le shell
 260 #    (par exemple /usr/local/) ou encore enrichir ces dossiers parcourus avec
 261 #    le dossier courant (c'est la stratégie utilisée lorsque l'on fait
 262 #    `. path-to/local/etc/stardis.profile`).
 263 
 264 # Ce point est nécessaire ici, même si ces concepts étaient déjà
 265 # nécessaires pour le TP3, parce que ce TP6 est tourné vers le développement.
 266 
 267 
 268 #============================================
 269 # TP6 - Partie 2 : propriétés programmables #
 270 #============================================
 271 
 272 # Avant d'entrer dans le fonctionnement du hack de stardis, on va présenter
 273 # les propriétés programmables. On peut déjà faire beaucoup de choses avec
 274 # les propriétés programmables, notamment faire varier de façon
 275 # spatio-temporelle certains paramètres des conditions limites. Vous avez
 276 # déjà croisé un exemple dans le TP2 : celui de l'insensibilité du temps de
 277 # calcul au raffinement de la finesse de description temporelle des données.
 278 
 279 
 280 # Partie 2.1 : comprendre et faire tourner
 281 # ----------------------------------------
 282 
 283 # Bibliothèque fournie par l'utilisateur au logiciel stardis, qui seront
 284 # appelées pendant la simulation MC. Il faut donc que les fonctions dont
 285 # stardis a besoin soient implémentées. Elles sont définies dans le fichier
 286 # suivant :
 287 
 288 vim /home/lafrier/star-build/local/include/stardis/stardis-prog-properties.h
 289 
 290 # Ce fichier commence par définir les fonctions obligatoires à toute
 291 # propriété programmable, puis celles qui concernent chaque type de propriété
 292 # programmable. Un exemple est donné ici :
 293 
 294 vim "${DEMONSTRATEUR_2}"/TP6/src/proprietes_programmables/src/tbound.c
 295 
 296 # Vous voyez que toutes ces fonctions sont bien définies. Dans cet exemple,
 297 # la température renvoyée (`stardis_boundary_temperature`) est exactement
 298 # celle qui est lue via `stardis_create_data`.
 299 
 300 # L'utilisation de cette bibliothèque comme propriété programmable se fait
 301 # dans le fichier model.txt en deux temps :
 302 
 303 vim "${DEMONSTRATEUR_2}"/TP6/src/proprietes_programmables/scene/model_prog.txt
 304 
 305 #  - Import de la bibliothèque programmable, elle est associée à un nom.
 306 #    Elle est éventuellement initialisée si la bibliothèque a des variables
 307 #    internes.
 308 #       ` PROGRAM                   TBOUND   libtbound_demonstrateur.so`
 309 #  - Définition de conditions limites comme programmables, via les mots clés
 310 #    "*_PROG" (voir manuel de stardis-input).
 311 #    Celles-ci peuvent nécessiter des arguments, qui sont récupérés et passés
 312 #    à la fonction `stardis_create_data`
 313 #      `T_BOUNDARY_FOR_SOLID_PROG   TEMP  TBOUND  left_bc.stl  PROG_PARAMS 310`
 314 #                                                                          ^^^
 315 #                         paramètres de la propriété programmable (ici un seul)
 316 
 317 # Compilation :
 318 # On va maintenant compiler cette bibliothèque de fonction programmable pour
 319 # que vous puissiez la modifier ensuite.
 320 
 321 # Ici nous utilisons l'ancien système de compilation, basé sur cmake et qui
 322 # repose à l'heure actuelle sur Makefile (et pkgconfig) plutôt.
 323 # TODO
 324 # A terme, Makefile ?
 325 
 326 # On commence par réaliser une copie locale des propriétés programmables :
 327 
 328 cd TP6
 329 cp -r "${DEMONSTRATEUR_2}"/TP6/src/proprietes_programmables .
 330 cd proprietes_programmables
 331 ls
 332 
 333 # Observer l'organisation avec les répertoires :
 334 #  - src/ : contient les sources de la bibliothèque de propriétés
 335 #           programmables
 336 #  - cmake/ : contient le fichier CMake qui va permettre la compilation
 337 #             de la bibliothèque
 338 #  - scene/ : contient un exemple de scène utilisant la bibliothèque de
 339 #             propriétés programmables
 340 # On va maintenant créer le répertoire build dans lequel on compilera et
 341 # installera la bibliothèque.
 342 
 343 mkdir build
 344 cd build
 345 
 346 # On localise les bibliothèques dont on aura besoin :
 347 
 348 . /home/lafrier/star-build/local/etc/stardis.profile
 349 
 350 # Procédure pour compiler les propriétés programmables :
 351 
 352 cmake ../cmake -DCMAKE_INSTALL_PREFIX=local
 353 
 354 # installation des propriétés programmables dans le répertoire local :
 355 
 356 make install
 357 
 358 # Observer la création du répartoire "local" :
 359 
 360 ls
 361 ls local/
 362 ls local/lib/
 363 
 364 # Observer que la bibliothèque a bien été installée. Afin d'ajouter cette
 365 # bibliothèque à la variable d'environnement utilisée par l'éditeur de liens :
 366 
 367 LD_LIBRARY_PATH=$(pwd)/local/lib:${LD_LIBRARY_PATH}
 368 
 369 # Il n'y a besoin de le faire qu'une seule fois.
 370 
 371 # Exécution :
 372 
 373 cd ../scene/
 374 ls
 375 
 376 # Il y a deux fichiers décrivant deux systèmes physiques identiques, l'un
 377 # utilisant les propriétés programmables ("model_prog.txt") et l'autre non
 378 # (model.txt). Observer que c'est bien le cas :
 379 
 380 vim model.txt
 381 vim model_prog.txt
 382 
 383 # Vérifier que le résultat est le même :
 384 
 385 stardis -M model.txt -p 0.5,0.5,0.5
 386 stardis -M model_prog.txt -p 0.5,0.5,0.5
 387 
 388 # Ici on obtient exactement le même résultat. Dans la suite, on réalisera
 389 # des images infrarouges pour visualiser aussi les conditions limites.
 390 
 391 stardis -M model_prog.txt \
 392   -R spp=4:img=100x100:fov=30:pos=-2,-2,2:up=0,0,1:tgt=0.5,0.5,0.5 > basic.ht
 393 htpp -f -o basic.ppm -v -m default basic.ht
 394 feh basic.ppm
 395 
 396 
 397 # Partie 2.2 : variation des propriétés spatiales
 398 # -----------------------------------------------
 399 
 400 # Note : c'est volontaire de laisser l'étudiant naviguer dans l'arborescence
 401 # et comprendre par lui-même comment modifier les sources, recompiler,
 402 # re-exécuter, etc.
 403 
 404 # Dans la fonction `stardis_boundary_temperature` de src/tbound.c, remplacez la
 405 # ligne `return bound->temp;` qui renvoie la constante lue par la fonction
 406 # suivante :
 407 #   return bound->temp + 3.0 * \
 408 #     ( sin(2*frag->P[0]) + sin(2*frag->P[1]) + sin(2*frag->P[2]));
 409 # Recompilez et lancez maintenant le calcul d'une image infrarouge.
 410 #
 411 # TODO
 412 # Attention avec la version 0.16 de stardis-solveur : la face apparaît
 413 # complètement noire et on ne voit donc pas ces variations spatiales.
 414 # Il faut la version develop de stardis-solveur pour le moment.
 415 
 416 stardis -M model_prog.txt \
 417   -R spp=4:img=100x100:fov=30:pos=-2,-2,2:up=0,0,1:tgt=0.5,0.5,0.5 > prog.ht
 418 htpp -f -o prog.ppm -v -m default prog.ht
 419 feh prog.ppm
 420 
 421 # Vous devez observer que la température imposée sur la face gauche varie
 422 # spatialement.
 423 
 424 
 425 # Partie 2.3 : variations temporelles
 426 # -----------------------------------
 427 
 428 
 429 # Partie 2.3.1 : construisez en autonomie un exemple avec un cube MINCE chaud
 430 #             qui est plongé dans un milieu à température imposée plus froide
 431 # ---------------------------------------------------------------------------
 432 #
 433 # Supprimez tout rayonnement en mettant Tref = 0. Observez l'évolution
 434 # temporelle de la température de surface du cube. Vous devriez obtenir une
 435 # courbe exponentielle.
 436 # Aide : vous n'avez pas besoin des propriétés programmables pour cela, vous
 437 # pouvez vous inspirer des scripts gnuplot du TP4.
 438 
 439 
 440 # Partie 2.3.2 : que se passe-t-il si ce h est maintenant sinusoïdal ?
 441 # --------------------------------------------------------------------
 442 
 443 # Vous pourrez par exemple choisir la fonction $h_c * (1 + 0.9 * \sin(t))$
 444 # et modifier le fichier `src/hbound.c`
 445 
 446 
 447 # Partie 2.3.3 : que se passe-t-il si le solide n'est plus mince ?
 448 # ----------------------------------------------------------------
 449 
 450 
 451 # Corrections :
 452 # -------------
 453 
 454 # Les fichiers corrigés sont donnés dans le dossier
 455 # `proprietes_programmables_correction`.
 456 
 457 # Correction 2.3.1 :
 458 # ------------------
 459 
 460 cd ..
 461 cp -r scene scene_convection
 462 cd scene_convection
 463 
 464 # Remplir le modèle sans propriétés programmables pour répondre à la
 465 # consigne :
 466 
 467 vim model.txt
 468 
 469 # Tracer une courbe exponentielle :
 470 
 471 cp "${DEMONSTRATEUR_2}"/TP4/src/vary_time.sh .
 472 sh vary_time.sh
 473 
 474 # Corrections 2.3.2 et 2.3.3 :
 475 # ----------------------------
 476 
 477 # Implémentation de la propriété programmable.
 478 # Remplacer `stardis_convection_coefficient` dans hbound.c par
 479 #   return bound->hc * (1.0 + 0.9555 * sin(frag->time));
 480 # Le champ `time` de la structure `stardis_interface_fragment` est donné dans
 481 # `stardis-prog-properties.h` :
 482 
 483 vim ../src/hbound.c
 484 
 485 # Compilation :
 486 
 487 cd ../build
 488 make install
 489 cd ../scene_convection
 490 
 491 # Exécution :
 492 
 493 vim model_prog.txt
 494 
 495 # Appeler la fonction programmable, `libhbound_demonstrateur.so`
 496 # Consulter le manuel de stardis-input (`man stardis-input`) pour utiliser
 497 # cette propriété programmable en tant que condition limite :
 498 # H_BOUNDARY_FOR_SOLID_PROG ...
 499 
 500 # Exécuter stardis et tracer un graphique :
 501 
 502 cp vary_time.sh vary_time_prog.txt
 503 vim vary_time_prog.sh
 504 
 505 # Ajouter "_prog" à différents endroits pour lancer stardis sur model_prog.txt
 506 # mais aussi sauvegarder les données et le script gnuplot dans de nouveaux
 507 # fichiers. Choisissez bien la plage temporelle sur laquelle réaliser les
 508 # simulations.
 509 
 510 # Analyse :
 511 
 512 sh vary_time_prog.sh
 513 
 514 # TODO
 515 # Si vous avez choisi un nombre de Biot suffisamment faible, alors vous verrez
 516 # une exponentielle, sinon vous observez que la température remonte ...
 517 # En fait, lorsque h est proche de 0, la température de surface augmente car le
 518 # coeur du solide est chaud, la température de surface est par contre refroidie
 519 # lorsque h augmente, la température du fluide extérieur étant plus faible.
 520 # Pour se convaincre de ces arguments, vous pourriez tracer la température dans
 521 # une coupe en fonction du temps.
 522 
 523 # On peut ici illustrer avec les images
 524 # `proprietes_programmables_correction/scene_corr/graphique_*.png`
 525 
 526 
 527 # Partie 2.4 : pour aller plus loin, faite en sorte que l'utilisateur spécifie
 528 #                                            la fréquence du signal sinusoidal
 529 # ----------------------------------------------------------------------------
 530 
 531 # Correction :
 532 # ------------
 533 
 534 #  - TP6/src/proprietes_programmables_correction/src/hbound_frequence.c :
 535 #    lecture de l'argument 6 dans la fonction `stardis_create_data`, création
 536 #    d'un champ dans la structure `my_hbound` pour le stockage de cette
 537 #    information, ensuite utilisée pour calculer le coefficient h dans la
 538 #    fonction `stardis_convection_coefficient`
 539 #  - TP6/src/proprietes_programmables_correction/cmake/CMakeList.txt : ajout
 540 #    d'un nouvel exécutable à la compilation
 541 #  - TP6/src/proprietes_programmables_correction/scene_corr
 542 #      /modele_modele_h_sin_frequence.txt :
 543 #    changement de la bibliothèque utilisée
 544 #    (`libhbound_demonstrateur_frequence.so`) et ajout de la fréquence en
 545 #    argument de `H_BOUNDARY_FOR_SOLID_PROG`.
 546 
 547 # revenir au niveau du dossier TP6
 548 
 549 cd ../..
 550 
 551 
 552 #====================================================================
 553 # TP6 - Partie 3 : Hack du solveur : puissance volumique donnée par #
 554 #                   une espérance [autre chose que de la thermique] #
 555 #====================================================================
 556 
 557 # On va maintenant présenter des hacks. Dans cette Partie 3, il s'agit d'un
 558 # exercice académique. Dans la Partie 4 suivante, un deuxième exemple sera
 559 # décrit qui a finalement été intégré dans le stardis officiel.
 560 
 561 # Donner une explication "large" du besoin de coupler la thermique à
 562 # différentes physiques (chimie, électricité, etc). On peut alors hacker
 563 # stardis pour prendre en compte cette nouvelle physique, qu'on suppose décrite
 564 # par l'espérance d'une variable aléatoire.
 565 
 566 # Ici on prend un exemple où c'est la puissance volumique qui est décrite comme
 567 # l'espérance d'une variable aléatoire. Plutôt que de choisir un modèle
 568 # physique, on prend le cas caricatural d'une puissance volumique donnée par
 569 # une gaussienne.
 570 
 571 # Intention en trois étapes :
 572 #  Partie 3.1 : installer son propre projet dérivé de stardis
 573 #  Partie 3.2 : changer une fonction dans le solveur
 574 #  Partie 3.3 : ajouter un nouveau paramètre dans la description du système
 575 #               physique lue par stardis
 576 
 577 cp -r ${DEMONSTRATEUR_2}/TP6/src/hack_puissance_volumique .
 578 cd hack_puissance_volumique
 579 
 580 # Partie 3.1 : installation du contexte pour hacker
 581 # -------------------------------------------------
 582 
 583 # On commence par expliciter les gestes pour l'installation.
 584 # On présente rapidement star-build (juste le concept de gestionnaire de paquet
 585 # pour que les versions des paquets installés soient cohérents avec la version
 586 # de stardis installée par exemple).
 587 
 588 git clone https://gitlab.com/meso-star/star-build.git -b 0.0
 589 cd star-build/
 590 
 591 # installer stardis et ses dépendances :
 592 
 593 make clean
 594 rm -fr cache local
 595 make BUILD=src/stardis_0.11.1.sh \
 596 REPO_BIN_ONLINE=https://www.meso-star.com/packages/v0.4 \
 597 DISTRIB_PARALLELISM=None
 598 
 599 # On va maintenant utiliser ce stardis plutôt que celui installé chez lafrier :
 600 
 601 . ./local/etc/stardis.profile
 602 
 603 # On va repartir des sources qui ont été installées dans cache/stardis-solver.
 604 # On copie ce dossier et on va le modifier plus tard :
 605 
 606 cp -r cache/stardis-solver/0.16.1/ ../stardis-solver-0.16.1
 607 
 608 # On nettoie les fichiers temporaires qui ont été générés :
 609 
 610 cd ../stardis-solver-0.16.1
 611 make distclean
 612 ls
 613 
 614 # On commence donc par vérifier qu'on est en capacité de le modifier puis faire
 615 # tourner ce code là. Pour cela, on vous propose d'écrire "Hello World" dans la
 616 # console et de retourner une erreur pour arrêter le programme :
 617 
 618 vim src/sdis_solve_probe_Xd.h
 619 
 620 # Dans la fonction `XD(solve_probe)`, ajoutez les lignes suivantes :
 621 #  XD(solve_probe)(...)
 622 #  {
 623 #    ...
 624 #    ATOMIC res = RES_OK;
 625 #
 626 # >> log_err(scn->dev, "Hello World !\n");
 627 # >> goto error;
 628 #    ...
 629 #  }
 630 
 631 # On souhaite écraser la bibliothèque 'stardis-solver' installée dans le dossier
 632 # 'star-build/local' par la version que nous venons de modifier dans le dossier
 633 # 'stardis-solver-0.16.1'. Pour cela, on édite le fichier config.mk :
 634 
 635 vim config.mk
 636 
 637 # Remplacer le chemin d'installation PREFIX par le chemin absolu vers le dossier
 638 # star-build/local. On s'attend à un chemin de la forme :
 639 # PREFIX=/home/etudiant/nom/TP6/hack_puissance_volumique/star-build/local
 640 # Changer le DISTRIB_PARALLELISM en remplaçant la ligne par:
 641 # DISTRIB_PARALLELISM = None
 642 
 643 # Installer stardis-solver dans le dossier spécifié :
 644 
 645 make install
 646 
 647 # On exécute maintenant stardis :
 648 
 649 cd ../cube
 650 stardis -M model.txt -p 0.5,0.5,0.5
 651 
 652 # Vous devez constater qu'il y a bien 'Hello world' écrit dans votre console.
 653 # BRAVO ! Vous êtes maintenant prêt à développer vos propres fonctionnalités !
 654 
 655 # Avant de continuer, commentez la ligne `goto error;` pour éviter que le
 656 # programme ne s'arrête :
 657 
 658 cd ../stardis-solver-0.16.1
 659 vim src/sdis_solve_probe_Xd.h
 660 
 661 # NOTE : pour l'exercice suivant, le git diff ainsi que les fichiers modifiés
 662 # sont stockés (au cas-où) dans le dossier
 663 # ${DEMONSTRATEUR_2}/TP6/src/code_hack_puissance_volumique.
 664 
 665 
 666 # Partie 3.2 : puissance volumique donnée comme une espérance
 667 # -----------------------------------------------------------
 668 
 669 # Vous allez d'abord modifier le calcul de la puissance volumique.
 670 # On fait le choix de modifier l'algorithme du WOS car le code est le plus
 671 # lisible, donc du fichier src/sdis_heat_path_conductive_wos_Xd.h :
 672 
 673 vim src/sdis_heat_path_conductive_wos_Xd.h
 674 
 675 # Recherchez `power` dans le fichier. Vous identifiez que la fonction
 676 # `handle_volumic_power_wos` est dédiée à la gestion de la puissance volumique,
 677 # et qu'elle est appelée par la fonction `XD(conductive_path_wos)`.
 678 # Vous voyez (ligne 210) que la température accumulée est
 679 # `T->value += props->power * term;`
 680 # Ici, il s'agira de ne plus utiliser `props->power` de façon déterministe mais
 681 # une réalisation de la variable aléatoire de loi normale.
 682 
 683 # Dupliquez la fonction `handle_volumic_power_wos` pour créer votre nouvelle
 684 # fonction `handle_gaussian_volumic_power_wos`. Définissez et initialisez une
 685 # nouvelle variable `power` de type double :
 686 #   double power = 0;
 687 # La puissance volumique est cette fois obtenue en échantillonnant la
 688 # distribution normale autour de props->power, avec un écart-type choisi
 689 # arbitrairement. Pour cela, il existe déjà la fonction `ssp_ran_gaussian` dans
 690 # la bibliothèque `ssp`. Sa définition est donnée dans le fichier d'API
 691 # `star-build/local/include/star/ssp.h`.
 692 
 693 vim ../star-build/local/include/star/ssp.h
 694 
 695 vim src/sdis_heat_path_conductive_wos_Xd.h
 696 
 697 # Vous pouvez donc écrire :
 698 #   power = ssp_ran_gaussian(rng, props->power, 100000);
 699 #   T->value += power * term;
 700 
 701 # Vous voyez qu'il faut un générateur aléatoire `rng` comme premier argument de
 702 # cette fonction. La fonction `handle_volumic_power_wos` ne dispose pas de
 703 # telle variable, par contre c'est le cas de la fonction appelante
 704 # `XD(conductive_path_wos)`. Vous devez donc modifier les arguments de votre
 705 # nouvelle fonction pour y ajouter `struct ssp_rng* rng`.
 706 
 707 # La fonction est bien définie mais n'est pas appelée, vous allez donc
 708 # maintenant modifier la fonction `XD(conductive_path_wos)`. Afin de pouvoir
 709 # appeler votre version modifiée de stardis ou alternativement le calcul
 710 # originel, vous utiliserez une macro pré-processeur.
 711 
 712 # Ajoutez les lignes suivantes :
 713 #    /* Add the volumic power density */
 714 # >> #define HACKED_VOLUMIC_POWER /* à commenter pour désactiver le hack */
 715 # >> #ifdef HACKED_VOLUMIC_POWER
 716 # >> res = XD(handle_gaussian_volumic_power_wos)(scn, &props, rng, dst, &power_term, T);
 717 # >> #else
 718 # >> res = XD(handle_volumic_power_wos)(scn, &props, dst, &power_term, T);
 719 # >> #endif
 720 #    if(res != RES_OK) goto error;
 721 
 722 make install
 723 
 724 # On va tester sur la scène du cube du starter_pack :
 725 
 726 cd ../cube
 727 stardis -V 3 -M model.txt -p 0.5,0.5,0.5 -n 10000 -e -a wos
 728 
 729 
 730 # Analyse physique :
 731 # ------------------
 732 
 733 # Dans un nouveau terminal, sourcez stardis "normal" et exécutez le script
 734 # suivant qui estime la température à différents point dans le cube solide.
 735 # Ou alternativement commentez la ligne :
 736 #  #define HACKED_VOLUMIC_POWER /* à commenter pour déactiver le hack */
 737 # et recompilez avant d'exécuter :
 738 
 739 ./run_stardis_several_positions.sh data_stardis.txt
 740 
 741 # Faite de même dans le terminal qui a sourcé la version hackée de stardis
 742 # avec une puissance volumique qui est échantillonnée
 743 
 744 ./run_stardis_several_positions.sh data_hacked_stardis.txt
 745 
 746 # Comparez les deux :
 747 # vous pouvez lire les fichiers data_stardis.txt et data_hacked_stardis.txt ou
 748 # bien lancer le plot suivant :
 749 
 750 {
 751   echo "plot 'data_stardis.txt' u 1:2:3 w yerrorbar title" \
 752     "'constant vol. power', 'data_hacked_stardis.txt'" \
 753     "u 1:2:3 w yerrorbar title 'sampled vol. power'"
 754   echo "pause -1"
 755 } > plot.gp
 756 gnuplot plot.gp
 757 
 758 # L'estimation de la température dans la tranche est donc très peu impactée par
 759 # le fait que la puissance volumique soit elle-même échantillonnée.
 760 # C'est une bonne nouvelle !
 761 # Si vous le souhaitez vous pouvez faire le test avec différentes valeurs
 762 # d'écart-type pour la gaussienne.
 763 
 764 # TODO
 765 # Eventuellement un commentaire physique sur le profil quadratique de la
 766 # température dans la tranche.
 767 
 768 
 769 # Partie 3.3 : paramètres contrôlés par l'utilisateur
 770 # ---------------------------------------------------
 771 
 772 # Maintenant, on souhaite que le paramètre d'écart-type de la loi normale soit
 773 # donné comme un paramètre dans le fichier d'entrée de Stardis.
 774 
 775 # ATTENTION, comme décrit dans le paragraphe de la fin, on voit que c'est plus
 776 # long...
 777 
 778 # De la même manière qu'il y a `props->power`, on voudrait maintenant un champ
 779 # `props->power_std` pour l'écart-type. Identifier dans le code le type de la
 780 # variable props ('const struct solid_props* props'). Recherchez où cette
 781 # structure est définie pour la modifier ensuite :
 782 
 783 cd ../stardis-solver-0.16.1/
 784 grep "struct solid_props {" src/*
 785 
 786 # Editez donc la structure pour ajouter un champ
 787 # `double power_std; /* Ecart-type de la puissance volumique */`
 788 # juste après la déclaration de `power`. A la ligne juste en dessous, modifiez
 789 # l'initalisateur par défaut pour initialiser ce nouveau champ par exemple à 0.
 790 
 791 vim src/sdis_medium_c.h
 792 
 793 # Vous devez avoir :
 794 #    struct solid_props {
 795 #      ...
 796 #      double power; /* Volumic power */
 797 #      double power_std_dev; /* Ecart-type de la puissance volumique */
 798 #      ...
 799 #    }
 800 #    #define SOLID_PROPS_NULL__ {0,0,0,0,0,0,0,0}
 801 
 802 # En cherchant les appels à `power`, vous voyez que ce champ est rempli par la
 803 # fonction `solid_get_properties`. Modifiez là pour tenir compte de l'écart-type
 804 # sur la puissance volumique. Vous devriez avoir :
 805 
 806 #    static INLINE res_T
 807 #    solid_get_properties
 808 #      (const struct sdis_medium* mdm,
 809 #       const struct sdis_rwalk_vertex* vtx,
 810 #       struct solid_props* props)
 811 #    {
 812 #      ...
 813 #      props->power = solid_get_volumic_power(mdm, vtx);
 814 #      props->power_std_dev = solid_get_volumic_power_std(mdm, vtx);
 815 #      ...
 816 #    }
 817 
 818 # Il faut alors définir une nouvelle fonction :
 819 
 820 #    static INLINE double
 821 #    solid_get_volumic_power_std
 822 #      (const struct sdis_medium* mdm,
 823 #       const struct sdis_rwalk_vertex* vtx)
 824 #    {
 825 #      ASSERT(mdm && mdm->type == SDIS_SOLID);
 826 #      return mdm->shader.solid.volumic_power_std_dev
 827 #        ? mdm->shader.solid.volumic_power_std_dev(vtx, mdm->data)
 828 #        : SDIS_VOLUMIC_POWER_NONE;
 829 #    }
 830 
 831 # Faite appel à ce nouveau champ lors du tirage de la puissance volumique :
 832 
 833 vim src/sdis_heat_path_conductive_wos_Xd.h
 834 
 835 # Vous devez donc avoir remplacé
 836 #   power = ssp_ran_gaussian(rng, props->power, 100000);
 837 # par
 838 #   power = ssp_ran_gaussian(rng, props->power, props->power_std_dev);
 839 
 840 make install
 841 
 842 # On obtient une erreur :
 843 #  erreur: « const struct sdis_solid_shader » n'a pas de membre nommé
 844 #          « volumic_power_std_dev »
 845 
 846 grep "struct sdis_solid_shader {" src/*
 847 
 848 # on voit que cette structure est définie dans
 849 # src/sdis.h
 850 
 851 # TODO
 852 # Mettre une définition pour l'API sdis et le fait que c'est cette interface
 853 # qui définit le point d'entrée vers le solveur.
 854 
 855 # En fait, depuis stardis, le seul moyen d'accéder à cette valeur est de
 856 # passer par les structures définies dans l'API "dis.h" :
 857 
 858 vim src/sdis.h
 859 
 860 # Recherchez les occurences de `volumic_power`, vous voyez que ce champ apparaît
 861 # dans `struct sdis_solid_shader`. Ajoutez un nouveau champ
 862 # `volumic_power_std_dev` dans la structure, en copiant ce qui est fait pour
 863 # `volumic_power`. Vous devriez avoir :
 864 
 865 #   struct sdis_solid_shader {
 866 #     ...
 867 #     sdis_medium_getter_T volumic_power;  /* In W.m^-3 */
 868 #     sdis_medium_getter_T volumic_power_std_dev;  /* In W.m^-3 */
 869 #     ...
 870 #   }
 871 
 872 # Ici il faut aussi mettre à jour l'initialisateur par défaut.
 873 #    #define SDIS_SOLID_SHADER_NULL__ {NULL, NULL, NULL, NULL, NULL, NULL, 0}
 874 # A remplacer par la ligne suivante, où la fonction définissant l'écart-type
 875 # sera initialisé à NULL :
 876 #    #define SDIS_SOLID_SHADER_NULL__ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0}
 877 
 878 make install
 879 
 880 # Le solveur est prêt pour recevoir ce nouveau paramètre, maintenant vous allez
 881 # modifier stardis :
 882 
 883 cd ..
 884 cp -r star-build/cache/stardis/0.11.1/ stardis-0.11.1/
 885 cd stardis-0.11.1/
 886 make distclean
 887 vim config.mk
 888 
 889 # Comme dans la Partie 3.1, il vous faut spécifier PREFIX vers le dossier
 890 # star-build/local et changer le DISTRIB_PARALLELISM en remplaçant la ligne par:
 891 # DISTRIB_PARALLELISM = None
 892 
 893 make install
 894 
 895 # Dans le fichier décrivant le système, on souhaite maintenant modifier la
 896 # grammaire associée au mot clé "SOLID" pour ajouter le paramètre
 897 # volumic_power_std_dev après volumic_power :
 898 #   SOLID  name  lambda  rho  cp  delta  initial-temp  imposed-temp
 899 #          volumic-power  side-specifier  slt_file
 900 # devient
 901 #   SOLID  name  lambda  rho  cp  delta  initial-temp  imposed-temp 
 902 #          volumic-power  volumic-power-std-dev  side-specifier  slt_file
 903 
 904 # Pour cela, vous devez modifier le parsing, c'est-à-dire la lecture et le
 905 # traitement de ces données :
 906 
 907 vim src/stardis-parsing.c
 908 
 909 # Dans la fonction `process_solid` :
 910 
 911 #    if(solid->vpower != 0 && stardis->picard_order > 1) {
 912 #      ...
 913 #    }
 914 #
 915 # >> CHK_ARG(idx, "volumic power std");
 916 # >> res = cstr_to_double(arg, &solid->vpower_std_dev); /* seule ligne à
 917 #                                                                ajouter */
 918 # >> logger_print(stardis->logger, LOG_ERROR, "Std lue : %f\n",
 919 #          solid->vpower_std_dev); /* juste pour vérifier que cette
 920 #                                                  fonction est lue */
 921 #
 922 #    /* Actual solid creation is defered until geometry is read to allow
 923 #    * enclosure shape VS delta analysis (and auto delta computation) */
 924 
 925 
 926 # Exercice : rajoutez ce nouveau champ à la structure `struct solid`
 927 # ------------------------------------------------------------------
 928 
 929 # Solution :
 930 # ----------
 931 
 932 grep "struct solid {" src/*
 933 vim src/stardis-solid.h
 934 
 935 # Vous devriez avoir :
 936 #    struct solid {
 937 #      ...
 938 #      double vpower;
 939 # >>>  double vpower_std_dev;
 940 #      ...
 941 #    }
 942 
 943 # Compiler et il faut maintenant initialiser ce champ de la structure :
 944 
 945 vim src/stardis-solid.c
 946 
 947 # Dans la fonction `init_solid`, ajoutez la ligne :
 948 #    (*dst)->vpower_std_dev = 0;
 949 
 950 # La fonction `create_solver_solid` établit un lien entre les structures de
 951 # stardis et celle du solver.
 952 
 953 # Exercice : a partir de l'exemple de la puissance volumique, établissez le lien
 954 #     entre l'écart-type lu par stardis et celui qui sera utilisé par le solveur
 955 # ------------------------------------------------------------------------------
 956 
 957 # Solution :
 958 # ----------
 959 
 960 # Vous devriez avoir :
 961 
 962 # res_T
 963 #  create_solver_solid
 964 #    (struct stardis* stardis,
 965 #     const struct solid* solid_props)
 966 #  {
 967 #     ...
 968 #     if(solid_props->vpower != 0) solid_shader.volumic_power = solid_get_power;
 969 # >>> if(solid_props->vpower != 0) solid_shader.volumic_power_std_dev = solid_get_power_std_dev;
 970 #     if(solid_props->solid_id >= darray_media_ptr_size_get(&stardis->media)) {
 971 #     ...
 972 #  }
 973 
 974 # Ainsi que la fonction suivante, inspirée de `solid_get_power` :
 975 
 976 # static double
 977 # solid_get_power_std_dev
 978 #   (const struct sdis_rwalk_vertex* vtx,
 979 #    struct sdis_data* data)
 980 # {
 981 #   const struct solid* const* solid_props = sdis_data_cget(data);
 982 #   (void)vtx;
 983 #   return (*solid_props)->vpower_std_dev;
 984 # }
 985 
 986 make install
 987 cd ../cube
 988 stardis -V 3 -M model_std_dev.txt -p 0.5,0.5,0.5 -n 10000 -e -a wos
 989 
 990 # A l'issue de cet exercice, on voit donc que la modification dans le solveur
 991 # est assez directe, mais ça se complique grandement quand on doit cette fois
 992 # modifier stardis. "Et c'est normal." Une option peut être de ne pas passer
 993 # par stardis mais par un détournement des tests de non régression.
 994 # Ces tests servent à vérifier que le résultat de stardis est conforme à la
 995 # solution analytique sur certains cas. Ce découpage stardis / solveur a même
 996 # permis d'aller encore plus loin en intégrant le solveur à Syrthes, qui
 997 # possédait déjà un solveur maillé. Cela permet de faire tourner les deux
 998 # codes sur un même système (même CAO).
 999 
1000 # TODO
1001 # Une vidéo d'Isabelle pour parler du papier d'EDF sur la comparaison entre
1002 # les deux méthodes (MC / maillée).
1003 
1004 
1005 #============================================================================
1006 # TP6 - Partie 4 : des hacks plus compliqués ; exemple du flux solaire dans #
1007 #                                                                 l'habitat #
1008 #============================================================================
1009 
1010 # Objectif : bénéficier de l'infrastructure solide de stardis pour y développer
1011 # une nouvelle fonctionnalité très spécifique, sans subir tout le poids de la
1012 # structure, c'est-à-dire qu'on ne se soucie pas de casser d'autres
1013 # fonctionnalités qu'on n'utilise pas.
1014 
1015 # C'est faisble et on présente ici un exemple issu du projet ANR MC2,
1016 # basé sur la présentation de Vincent F. aux journées Consortium.
1017 # nastar:/nastar/mesostar/git/stardis-journees-consortium-2024.git
1018 #  - le contexte du projet MC2, papier de Cyril
1019 #  - les features ajoutées
1020 #  - 4 développeurs
1021 #  - Peu de lignes de codes modifiées finalement !
1022 #    Elles sont très localisées, rincipalement dans le solveur.
1023 #    Quelques nouveaux fichiers pour les nouvelles fonctionnalités :
1024 #    sdis_solar et sdis_spa
1025 
1026 # Ce hack a si bien fonctionné, que les features ont été redéveloppées dans
1027 # la version officielle de stardis. Les propriétés programmables sont aussi
1028 # au coeur de la proposition, pour avoir des propriétés variables issues de
1029 # simulations climatiques par exemple. Cette partie reste à la charge du
1030 # physicien développeur, de façon indépendante de Stardis comme on l'a vu dans
1031 # l'exercice 2.
1032 
1033 # Mettre l'image de la ville avec des "ombres solaires".
1034 
1035 
1036 # TODO
1037 # Une vidéo de Cyril qui nous raconte le projet MC2.