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.