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 # copier le dossier star-build
 589 #
 590 # TODO
 591 # On ne repartira pas de star-build cloné mais de celui en place sur la
 592 # clé pour éviter des problèmes d'incompatibilité du TP lorsque stardis aura
 593 # évolué.
 594 
 595 # la copie de star-build qui est dans lafrier, maintenant sur le home de
 596 # l'étudiant :
 597 # TODO
 598 # à changer - ajouter tag ?
 599 
 600 git clone https://gitlab.com/edstar/star-build.git
 601 cd star-build/
 602 
 603 # installer stardis et ses dépendances :
 604 
 605 make clean
 606 rm -fr cache local
 607 make BUILD=src/stardis_0.11.sh
 608 
 609 # On va maintenant utiliser ce stardis plutôt que celui installé chez lafrier :
 610 
 611 . ./local/etc/stardis.profile
 612 
 613 # On va repartir des sources qui ont été installées dans cache/stardis-solver.
 614 # On copie ce dossier et on va le modifier plus tard :
 615 
 616 cp -r cache/stardis-solver/0.16/ ../stardis-solver-0.16
 617 
 618 # On nettoie les fichiers temporaires qui ont été générés :
 619 
 620 cd ../stardis-solver-0.16
 621 make distclean
 622 ls
 623 
 624 # On commence donc par vérifier qu'on est en capacité de le modifier puis faire
 625 # tourner ce code là. Pour cela, on vous propose d'écrire "Hello World" dans la
 626 # console et de retourner une erreur pour arrêter le programme :
 627 
 628 vim src/sdis_solve_probe_Xd.h
 629 
 630 # Dans la fonction `XD(solve_probe)`, ajoutez les lignes suivantes :
 631 #  XD(solve_probe)(...)
 632 #  {
 633 #    ...
 634 #    ATOMIC res = RES_OK;
 635 #
 636 # >> log_err(scn->dev, "Hello World !\n");
 637 # >> goto error;
 638 #    ...
 639 #  }
 640 
 641 # On souhaite écraser la bibliothèque 'stardis-solver' installée dans le dossier
 642 # 'star-build/local' par la version que nous venons de modifier dans le dossier
 643 # 'stardis-solver-0.16'. Pour cela, on édite le fichier config.mk :
 644 
 645 vim config.mk
 646 
 647 # Remplacer le chemin d'installation PREFIX par le chemin absolu vers le dossier
 648 # star-build/local. On s'attend à un chemin de la forme :
 649 # PREFIX=/home/etudiant/nom/TP6/hack_puissance_volumique/star-build/local
 650 
 651 # Installer stardis-solver dans le dossier spécifié :
 652 
 653 make install
 654 
 655 # On exécute maintenant stardis :
 656 
 657 cd ../cube
 658 stardis -M model.txt -p 0.5,0.5,0.5
 659 
 660 # Vous devez constater qu'il y a bien 'Hello world' écrit dans votre console.
 661 # BRAVO ! Vous êtes maintenant prêt à développer.
 662 
 663 # Avant de continuer, commentez la ligne `goto error;` pour éviter que le
 664 # programme ne s'arrête :
 665 
 666 cd ../stardis-solver-0.16
 667 vim src/sdis_solve_probe_Xd.h
 668 
 669 # NOTE : pour l'exercice suivant, le git diff ainsi que les fichiers modifiés
 670 # sont stockés (au cas-où) dans le dossier
 671 # ${DEMONSTRATEUR_2}/TP6/src/code_hack_puissance_volumique.
 672 
 673 
 674 # Partie 3.2 : puissance volumique donnée comme une espérance
 675 # -----------------------------------------------------------
 676 
 677 # Vous allez d'abord modifier le calcul de la puissance volumique.
 678 # On fait le choix de modifier l'algorithme du WOS car le code est le plus
 679 # lisible, donc du fichier src/sdis_heat_path_conductive_wos_Xd.h :
 680 
 681 vim src/sdis_heat_path_conductive_wos_Xd.h
 682 
 683 # Recherchez `power` dans le fichier. Vous identifiez que la fonction
 684 # `handle_volumic_power_wos` est dédiée à la gestion de la puissance volumique,
 685 # et qu'elle est appelée par la fonction `XD(conductive_path_wos)`.
 686 # Vous voyez (ligne 210) que la température accumulée est
 687 # `T->value += props->power * term;`
 688 # Ici, il s'agira de ne plus utiliser `props->power` de façon déterministe mais
 689 # une réalisation de la variable aléatoire de loi normale.
 690 
 691 # Dupliquez la fonction `handle_volumic_power_wos` pour créer votre nouvelle
 692 # fonction `handle_gaussian_volumic_power_wos`. Définissez et initialisez une
 693 # nouvelle variable `power` de type double :
 694 #   double power = 0;
 695 # La puissance volumique est cette fois obtenue en échantillonnant la
 696 # distribution normale autour de props->power, avec un écart-type choisi
 697 # arbitrairement. Pour cela, il existe déjà la fonction `ssp_ran_gaussian` dans
 698 # la bibliothèque `ssp`. Sa définition est donnée dans le fichier d'API
 699 # `star-build/local/include/star/ssp.h`.
 700 
 701 vim ../star-build/local/include/star/ssp.h
 702 
 703 vim src/sdis_heat_path_conductive_wos_Xd.h
 704 
 705 # Vous pouvez donc écrire :
 706 #   power = ssp_ran_gaussian(rng, props->power, 100000);
 707 #   T->value += power * term;
 708 
 709 # Vous voyez qu'il faut un générateur aléatoire `rng` comme premier argument de
 710 # cette fonction. La fonction `handle_volumic_power_wos` ne dispose pas de
 711 # telle variable, par contre c'est le cas de la fonction appelante
 712 # `XD(conductive_path_wos)`. Vous devez donc modifier les arguments de votre
 713 # nouvelle fonction pour y ajouter `struct ssp_rng* rng`.
 714 
 715 # La fonction est bien définie mais n'est pas appelée, vous allez donc
 716 # maintenant modifier la fonction `XD(conductive_path_wos)`. Afin de pouvoir
 717 # appeler votre version modifiée de stardis ou alternativement le calcul
 718 # originel, vous utiliserez une macro pré-processeur.
 719 
 720 # Ajoutez les lignes suivantes :
 721 #    /* Add the volumic power density */
 722 # >> #define HACKED_VOLUMIC_POWER /* à commenter pour désactiver le hack */
 723 # >> #ifdef HACKED_VOLUMIC_POWER
 724 # >> res = XD(handle_gaussian_volumic_power_wos)(scn, &props, rng, dst, &power_term, T);
 725 # >> #else
 726 # >> res = XD(handle_volumic_power_wos)(scn, &props, dst, &power_term, T);
 727 # >> #endif
 728 #    if(res != RES_OK) goto error;
 729 
 730 make install
 731 
 732 # On va tester sur la scène du cube du starter_pack :
 733 
 734 cd ../cube
 735 stardis -V 3 -M model.txt -p 0.5,0.5,0.5 -n 10000 -e -a wos
 736 
 737 
 738 # Analyse physique :
 739 # ------------------
 740 
 741 # Dans un nouveau terminal, sourcez stardis "normal" et exécutez le script
 742 # suivant qui estime la température à différents point dans le cube solide.
 743 # Ou alternativement commentez la ligne :
 744 #  #define HACKED_VOLUMIC_POWER /* à commenter pour déactiver le hack */
 745 # et recompilez avant d'exécuter :
 746 
 747 ./run_stardis_several_positions.sh data_stardis.txt
 748 
 749 # Faite de même dans le terminal qui a sourcé la version hackée de stardis
 750 # avec une puissance volumique qui est échantillonnée
 751 
 752 ./run_stardis_several_positions.sh data_hacked_stardis.txt
 753 
 754 # Comparez les deux :
 755 # vous pouvez lire les fichiers data_stardis.txt et data_hacked_stardis.txt ou
 756 # bien lancer le plot suivant :
 757 
 758 {
 759   echo "plot 'data_stardis.txt' u 1:2:3 w yerrorbar title" \
 760     "'constant vol. power', 'data_hacked_stardis.txt'" \
 761     "u 1:2:3 w yerrorbar title 'sampled vol. power'"
 762   echo "pause -1"
 763 } > plot.gp
 764 gnuplot plot.gp
 765 
 766 # L'estimation de la température dans la tranche est donc très peu impactée par
 767 # le fait que la puissance volumique soit elle-même échantillonnée.
 768 # C'est une bonne nouvelle !
 769 # Si vous le souhaitez vous pouvez faire le test avec différentes valeurs
 770 # d'écart-type pour la gaussienne.
 771 
 772 # TODO
 773 # Eventuellement un commentaire physique sur le profil quadratique de la
 774 # température dans la tranche.
 775 
 776 
 777 # Partie 3.3 : paramètres contrôlés par l'utilisateur
 778 # ---------------------------------------------------
 779 
 780 # Maintenant, on souhaite que le paramètre d'écart-type de la loi normale soit
 781 # donné comme un paramètre dans le fichier d'entrée de Stardis.
 782 
 783 # ATTENTION, comme décrit dans le paragraphe de la fin, on voit que c'est plus
 784 # long...
 785 
 786 # De la même manière qu'il y a `props->power`, on voudrait maintenant un champ
 787 # `props->power_std` pour l'écart-type. Identifier dans le code le type de la
 788 # variable props ('const struct solid_props* props'). Recherchez où cette
 789 # structure est définie pour la modifier ensuite :
 790 
 791 cd ../stardis-solver-0.16/
 792 grep "struct solid_props {" src/*
 793 
 794 # Editez donc la structure pour ajouter un champ
 795 # `double power_std; /* Ecart-type de la puissance volumique */`
 796 # juste après la déclaration de `power`. A la ligne juste en dessous, modifiez
 797 # l'initalisateur par défaut pour initialiser ce nouveau champ par exemple à 0.
 798 
 799 vim src/sdis_medium_c.h
 800 
 801 # Vous devez avoir :
 802 #    struct solid_props {
 803 #      ...
 804 #      double power; /* Volumic power */
 805 #      double power_std_dev; /* Ecart-type de la puissance volumique */
 806 #      ...
 807 #    }
 808 #    #define SOLID_PROPS_NULL__ {0,0,0,0,0,0,0,0}
 809 
 810 # En cherchant les appels à `power`, vous voyez que ce champ est rempli par la
 811 # fonction `solid_get_properties`. Modifiez là pour tenir compte de l'écart-type
 812 # sur la puissance volumique. Vous devriez avoir :
 813 
 814 #    static INLINE res_T
 815 #    solid_get_properties
 816 #      (const struct sdis_medium* mdm,
 817 #       const struct sdis_rwalk_vertex* vtx,
 818 #       struct solid_props* props)
 819 #    {
 820 #      ...
 821 #      props->power = solid_get_volumic_power(mdm, vtx);
 822 #      props->power_std_dev = solid_get_volumic_power_std(mdm, vtx);
 823 #      ...
 824 #    }
 825 
 826 # Il faut alors définir une nouvelle fonction :
 827 
 828 #    static INLINE double
 829 #    solid_get_volumic_power_std
 830 #      (const struct sdis_medium* mdm,
 831 #       const struct sdis_rwalk_vertex* vtx)
 832 #    {
 833 #      ASSERT(mdm && mdm->type == SDIS_SOLID);
 834 #      return mdm->shader.solid.volumic_power_std_dev
 835 #        ? mdm->shader.solid.volumic_power_std_dev(vtx, mdm->data)
 836 #        : SDIS_VOLUMIC_POWER_NONE;
 837 #    }
 838 
 839 # Faite appel à ce nouveau champ lors du tirage de la puissance volumique :
 840 
 841 vim src/sdis_heat_path_conductive_wos_Xd.h
 842 
 843 # Vous devez donc avoir remplacé
 844 #   power = ssp_ran_gaussian(rng, props->power, 100000);
 845 # par
 846 #   power = ssp_ran_gaussian(rng, props->power, props->power_std_dev);
 847 
 848 make install
 849 
 850 # On obtient une erreur :
 851 #  erreur: « const struct sdis_solid_shader » n'a pas de membre nommé
 852 #          « volumic_power_std_dev »
 853 
 854 grep "struct sdis_solid_shader {" src/*
 855 
 856 # on voit que cette structure est définie dans
 857 # src/sdis.h
 858 
 859 # TODO
 860 # Mettre une définition pour l'API sdis et le fait que c'est cette interface
 861 # qui définit le point d'entrée vers le solveur.
 862 
 863 # En fait, depuis stardis, le seul moyen d'accéder à cette valeur est de
 864 # passer par les structures définies dans l'API "dis.h" :
 865 
 866 vim src/sdis.h
 867 
 868 # Recherchez les occurences de `volumic_power`, vous voyez que ce champ apparaît
 869 # dans `struct sdis_solid_shader`. Ajoutez un nouveau champ
 870 # `volumic_power_std_dev` dans la structure, en copiant ce qui est fait pour
 871 # `volumic_power`. Vous devriez avoir :
 872 
 873 #   struct sdis_solid_shader {
 874 #     ...
 875 #     sdis_medium_getter_T volumic_power;  /* In W.m^-3 */
 876 #     sdis_medium_getter_T volumic_power_std_dev;  /* In W.m^-3 */
 877 #     ...
 878 #   }
 879 
 880 # Ici il faut aussi mettre à jour l'initialisateur par défaut.
 881 #    #define SDIS_SOLID_SHADER_NULL__ {NULL, NULL, NULL, NULL, NULL, NULL, 0}
 882 # A remplacer par la ligne suivante, où la fonction définissant l'écart-type
 883 # sera initialisé à NULL :
 884 #    #define SDIS_SOLID_SHADER_NULL__ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0}
 885 
 886 make install
 887 
 888 # Le solveur est prêt pour recevoir ce nouveau paramètre, maintenant vous allez
 889 # modifier stardis :
 890 
 891 cd ..
 892 cp -r star-build/cache/stardis/0.11/ stardis-0.11/
 893 cd stardis-0.11/
 894 make distclean
 895 vim config.mk
 896 
 897 # Comme dans la Partie 3.1, il vous faut spécifier PREFIX vers le dossier
 898 # star-build/local
 899 
 900 make install
 901 
 902 # Dans le fichier décrivant le système, on souhaite maintenant modifier la
 903 # grammaire associée au mot clé "SOLID" pour ajouter le paramètre
 904 # volumic_power_std_err après volumic_power :
 905 #   SOLID  name  lambda  rho  cp  delta  initial-temp  imposed-temp
 906 #          volumic-power  side-specifier  slt_file
 907 # devient
 908 #   SOLID  name  lambda  rho  cp  delta  initial-temp  imposed-temp 
 909 #          volumic-power  volumic-power-std-dev  side-specifier  slt_file
 910 
 911 # Pour cela, vous devez modifier le parsing, c'est-à-dire la lecture et le
 912 # traitement de ces données :
 913 
 914 vim src/stardis-parsing.c
 915 
 916 # Dans la fonction `process_solid` :
 917 
 918 #    if(solid->vpower != 0 && stardis->picard_order > 1) {
 919 #      ...
 920 #    }
 921 #
 922 # >> CHK_ARG(idx, "volumic power std");
 923 # >> res = cstr_to_double(arg, &solid->vpower_std_dev); /* seule ligne à
 924 #                                                                ajouter */
 925 # >> logger_print(stardis->logger, LOG_ERROR, "Std lue : %f\n",
 926 #          solid->vpower_std_dev); /* juste pour vérifier que cette
 927 #                                                  fonction est lue */
 928 #
 929 #    /* Actual solid creation is defered until geometry is read to allow
 930 #    * enclosure shape VS delta analysis (and auto delta computation) */
 931 
 932 
 933 # Exercice : rajoutez ce nouveau champ à la structure `struct solid`
 934 # ------------------------------------------------------------------
 935 
 936 # Solution :
 937 # ----------
 938 
 939 grep "struct solid {" src/*
 940 vim src/stardis-solid.h
 941 
 942 # Vous devriez avoir :
 943 #    struct solid {
 944 #      ...
 945 #      double vpower;
 946 # >>>  double vpower_std_dev;
 947 #      ...
 948 #    }
 949 
 950 # Compiler et il faut maintenant initialiser ce champ de la structure :
 951 
 952 vim src/stardis-solid.c
 953 
 954 # Dans la fonction `init_solid`, ajoutez la ligne :
 955 #    (*dst)->vpower_std_dev = 0;
 956 
 957 # La fonction `create_solver_solid` établit un lien entre les structures de
 958 # stardis et celle du solver.
 959 
 960 # Exercice : a partir de l'exemple de la puissance volumique, établissez le lien
 961 #     entre l'écart-type lu par stardis et celui qui sera utilisé par le solveur
 962 # ------------------------------------------------------------------------------
 963 
 964 # Solution :
 965 # ----------
 966 
 967 # Vous devriez avoir :
 968 
 969 # res_T
 970 #  create_solver_solid
 971 #    (struct stardis* stardis,
 972 #     const struct solid* solid_props)
 973 #  {
 974 #     ...
 975 #     if(solid_props->vpower != 0) solid_shader.volumic_power = solid_get_power;
 976 # >>> if(solid_props->vpower != 0) solid_shader.volumic_power_std_dev = solid_get_power_std_dev;
 977 #     if(solid_props->solid_id >= darray_media_ptr_size_get(&stardis->media)) {
 978 #     ...
 979 #  }
 980 
 981 # Ainsi que la fonction suivante, inspirée de `solid_get_power` :
 982 
 983 # static double
 984 # solid_get_power_std_dev
 985 #   (const struct sdis_rwalk_vertex* vtx,
 986 #    struct sdis_data* data)
 987 # {
 988 #   const struct solid* const* solid_props = sdis_data_cget(data);
 989 #   (void)vtx;
 990 #   return (*solid_props)->vpower_std_dev;
 991 # }
 992 
 993 make install
 994 cd ../cube
 995 stardis -V 3 -M model_std_dev.txt -p 0.5,0.5,0.5 -n 10000 -e -a wos
 996 
 997 # A l'issue de cet exercice, on voit donc que la modification dans le solveur
 998 # est assez directe, mais ça se complique grandement quand on doit cette fois
 999 # modifier stardis. "Et c'est normal." Une option peut être de ne pas passer
1000 # par stardis mais par un détournement des tests de non régression.
1001 # Ces tests servent à vérifier que le résultat de stardis est conforme à la
1002 # solution analytique sur certains cas. Ce découpage stardis / solveur a même
1003 # permis d'aller encore plus loin en intégrant le solveur à Syrthes, qui
1004 # possédait déjà un solveur maillé. Cela permet de faire tourner les deux
1005 # codes sur un même système (même CAO).
1006 
1007 # TODO
1008 # Une vidéo d'Isabelle pour parler du papier d'EDF sur la comparaison entre
1009 # les deux méthodes (MC / maillée).
1010 
1011 
1012 #============================================================================
1013 # TP6 - Partie 4 : des hacks plus compliqués ; exemple du flux solaire dans #
1014 #                                                                 l'habitat #
1015 #============================================================================
1016 
1017 # Objectif : bénéficier de l'infrastructure solide de stardis pour y développer
1018 # une nouvelle fonctionnalité très spécifique, sans subir tout le poids de la
1019 # structure, c'est-à-dire qu'on ne se soucie pas de casser d'autres
1020 # fonctionnalités qu'on n'utilise pas.
1021 
1022 # C'est faisble et on présente ici un exemple issu du projet ANR MC2,
1023 # basé sur la présentation de Vincent F. aux journées Consortium.
1024 # nastar:/nastar/mesostar/git/stardis-journees-consortium-2024.git
1025 #  - le contexte du projet MC2, papier de Cyril
1026 #  - les features ajoutées
1027 #  - 4 développeurs
1028 #  - Peu de lignes de codes modifiées finalement !
1029 #    Elles sont très localisées, rincipalement dans le solveur.
1030 #    Quelques nouveaux fichiers pour les nouvelles fonctionnalités :
1031 #    sdis_solar et sdis_spa
1032 
1033 # Ce hack a si bien fonctionné, que les features ont été redéveloppées dans
1034 # la version officielle de stardis. Les propriétés programmables sont aussi
1035 # au coeur de la proposition, pour avoir des propriétés variables issues de
1036 # simulations climatiques par exemple. Cette partie reste à la charge du
1037 # physicien développeur, de façon indépendante de Stardis comme on l'a vu dans
1038 # l'exercice 2.
1039 
1040 # Mettre l'image de la ville avec des "ombres solaires".
1041 
1042 
1043 # TODO
1044 # Une vidéo de Cyril qui nous raconte le projet MC2.