sgs_compute_sensitivity_translation.nw (69105B)
1 % Copyright (C) 2021-2023 Centre National de la Recherche Scientifique 2 % Copyright (C) 2021-2023 INSA Lyon 3 % Copyright (C) 2021-2023 Institut Mines Télécom Albi-Carmaux 4 % Copyright (C) 2021-2023 |Méso|Star> (contact@meso-star.com) 5 % Copyright (C) 2021-2023 Institut Pascal 6 % Copyright (C) 2021-2023 PhotonLyX (info@photonlyx.com) 7 % Copyright (C) 2021-2023 Université de Lorraine 8 % Copyright (C) 2021-2023 Université Paul Sabatier 9 % Copyright (C) 2021-2023 Université Toulouse - Jean Jaurès 10 % 11 % This program is free software: you can redistribute it and/or modify 12 % it under the terms of the GNU General Public License as published by 13 % the Free Software Foundation, either version 3 of the License, or 14 % (at your option) any later version. 15 % 16 % This program is distributed in the hope that it will be useful, 17 % but WITHOUT ANY WARRANTY; without even the implied warranty of 18 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 % GNU General Public License for more details. 20 % 21 % You should have received a copy of the GNU General Public License 22 % along with this program. If not, see <http://www.gnu.org/licenses/>. 23 24 \documentclass[]{article} 25 \usepackage[utf8]{inputenc} 26 \usepackage[french]{babel} 27 \usepackage[T1]{fontenc} % Pour la césure des mots avec accents 28 \usepackage{url} 29 \usepackage{amsfonts} % \mathbb 30 \usepackage{amsmath} 31 \usepackage{graphicx} 32 \usepackage{noweb} 33 \usepackage{tikz} 34 \usepackage{pgfplots} % \begin{axis} 35 \usetikzlibrary{patterns} 36 \noweboptions{smallcode,longchunks} 37 38 % Remove clearpage after nwfilename 39 \makeatletter 40 \def\nw@laterfilename#1{\endgroup \markboth{#1}{#1}} 41 \makeatother 42 43 % Avoid a page break after a code chunk 44 \def\nwendcode{\endtrivlist \endgroup} 45 \let\nwdocspar=\par 46 %\def\nwendcode{\endtrivlist \endgroup \vfil\penalty10\vfilneg} 47 %\let\nwdocspar=\smallbreak 48 49 %Math et symboles 50 \newcommand{\PI}{\ddot \pi} 51 \newcommand{\etc}{\textit{etc.}} 52 \newcommand{\ie}{\textit{i.e.}} 53 \newcommand{\eg}{\textit{e.g.}} 54 55 \begin{document} 56 \pagestyle{noweb} 57 58 \title{Sensibilité à la translation} 59 \maketitle 60 61 Le but du présent document est d'illustrer la mise en {\oe}uvre algorithmique 62 d'un calcul de sensibilité géométrique sur l'exemple simple d'un 63 parallélépipède (figure~\ref{fig:configuration}). Nous nous intéressons ici à 64 la déformation géométrique liée à la translation de sa paroi supérieure et 65 étudions l'impact de cette translation sur le flux reçu par un récepteur situé 66 sur sa paroi inférieure. Dans cet exercice, la sensibilité du flux est estimée 67 par un algorithme de Monte Carlo analogue à la physique du transport de la 68 sensibilité géométrique. Cette pratique des algorithmes de Monte Carlo est 69 largement utilisée en transferts radiatifs et consiste à imiter numériquement 70 le transport de photons, en échantillonnant les sources du problème, puis en 71 les propageant dans le milieu selon ses propriétés et la statistique donnée par 72 les lois d'extinctions (Beer-Lambert) et de diffusions (fonction de phase). 73 L'extension de cette pratique à la sensibilité géométrique est possible en 74 s'appuyant sur le modèle de sensibilité, qui décrit les sources de sensibilité 75 géométrique et la phénoménologie de leur transport dans le milieu. La démarche 76 suivie dans ce document est la suivante: 77 \begin{itemize} 78 \item le problème de sensibilité géométrique est posé; 79 \item les sources de sensibilité sont identifiées, elles dépendent de 80 quantité décrites par d'autres physiques ({\ie} la luminance); 81 \item les couplages par les sources sont exposés; 82 \item un algorithme de Monte Carlo analogue est utilisé pour résoudre le 83 problème couplé (via la \textit{double randomization}); 84 \item la mise en {\oe}uvre de l'algorithme est explicite tout au long du 85 document. 86 \end{itemize} 87 88 L'exemple présenté dans ce document est illustratif et sans aucune ambition de 89 généralité. Il montre une application du modèle de sensibilité et une 90 utilisation de la méthode de Monte Carlo qui lui sont spécifiques. Cela se 91 traduit dans les choix de notations des variables (indice $h$ pour paroi du 92 haut, $d$ pour paroi de droite {\etc}), dans la simplification des équations du 93 modèle, et enfin dans l'écriture de l'algorithme de Monte Carlo. En effet, 94 contrairement à une pratique plus conventionnelle, l'ensemble des données qui 95 décrivent le système (la configuration géométrique et ses propriétés physiques) 96 ne sont pas séparées de la procédure d'échantillonnage des chemins. Autrement 97 dit, l'ensemble des chemins seront suivis relativement aux parois de la scène 98 et à leurs propriétés physiques. 99 100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 101 % Description du problème 102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 103 \section{Description du problème} 104 \label{sec:probleme} 105 106 L'observable radiative de notre problème est le flux $\varphi$ perçu par le 107 récepteur et s'exprime comme ci-dessous: 108 \begin{equation} 109 \varphi = \int_{A_r} dS \int_{\mathcal{H}^-} d\vec{\omega} 110 \ (\vec{\omega} \cdot \vec{n}) L(\vec{x},\vec{\omega},\PI) 111 \label{eq:flux} 112 \end{equation} 113 avec $\PI$ le paramètre géométrique, $A_r$ la surface du récepteur et 114 $\mathcal{H}^-$ l'hémisphère orientée par $\vec{n} = - \vec{e}_z$ 115 (figure~\ref{fig:configuration}). 116 117 \begin{figure}[h!] 118 \centering 119 \begin{tikzpicture} 120 121 % Paroi avant 122 \draw (0,0) -- (4,0) -- (4,3) -- (0,3) -- cycle; 123 124 % Paroi de droite 125 \draw[pattern=dots] (4,0) -- (5,1) -- (5,4) -- 126 node[below=35pt, preaction={fill, white}]{$A_d$} (4,3); 127 128 % Paroi arrière 129 \draw[dashed] (1,1) -- (5,1); 130 \draw[dashed] (1,4) -- (4.5,4); 131 \draw (4.5,4) -- (5,4); 132 133 % Paroi de gauche 134 \draw[dashed] (0,0) -- (1,1) -- (1,3); 135 \draw[fill] (1,3) -- (1,3.5); 136 \draw[dashed] (1,3.5) -- (1,4) -- (0.5,3.5); 137 \draw (0.5,3.5) -- (0,3); 138 139 % Paroi du haut, i.e. source de sensibilité 140 \draw[pattern=north west lines] (0,3.5) -- (4,3.5) -- 141 node[left=50pt, preaction={fill, white}]{$A_h$} (5,4.5) -- 142 (1,4.5) -- cycle; 143 144 % Récepteur 145 \draw[pattern=crosshatch] 146 (1.25, 0.25) -- (2.75, 0.25) -- (3.25, 0.75) -- (1.75, 0.75) -- cycle; 147 148 % Dimension du récepteur 149 \draw [latex-latex] (1.75, 0.9) -- 150 node[above, preaction={fill, white}] {$R_x$} (3.25, 0.9); 151 \draw [latex-latex] (2.95, 0.25) -- node[right=2pt] {$R_y$} (3.45, 0.75); 152 153 % Dimensions de la boîte 154 \draw [thin, dotted] (1, 4.5) -- (1, 5); 155 \draw [thin, dotted] (5, 4.5) -- (5, 5); 156 \draw [thin, dotted] (0, 3.5) -- (-0.5, 3.5); 157 \draw [thin, dotted] (1, 4.5) -- (0.5, 4.5); 158 \draw [thin, dotted] (5, 1) -- (6.25, 1); 159 \draw [thin, dotted] (5,4) -- (5.5,4); 160 \draw [thin, dotted] (5,4.5) -- (6.25,4.5); 161 \draw [latex-latex] (1, 5) -- node[above] {$D_x$} (5,5); 162 \draw [latex-latex] (-0.5, 3.5) -- node[left=2pt] {$D_y$} (0.5, 4.5); 163 \draw [latex-latex] (5.5, 1) -- node[right] {$h$} (5.5, 4); 164 \draw [latex-latex] (5.5, 4) -- node[right] {$\PI$} (5.5, 4.5); 165 \draw [latex-latex] (6.25, 1) -- node[right] {$D_z(\PI)$} (6.25, 4.5); 166 167 % Repère 168 \draw [-latex, thick] (0,0) -- node[below] {$\vec{e}_x$} (1.25,0); 169 \draw [-latex, thick] (0,0) -- node[right=2pt] {$\vec{e}_y$} (0.75,0.75); 170 \draw [-latex, thick] (0,0) -- node[left] {$\vec{e}_z$} (0,1.25); 171 \end{tikzpicture} 172 173 \flushleft 174 \caption{\textbf{La configuration géométrique} est un parallélépipède de 175 dimension $D_x \times D_y \times D_z(\PI)$, avec $D_z(\PI) = h+\PI$, repéré 176 dans la base $(\vec{e}_x, \vec{e}_y, \vec{e}_z)$. Le paramètre $\PI$ est le 177 paramètre géométrique défini sur $\mathbb{R}^{+}$. En le modifiant, la 178 position de la paroi supérieure est translatée vers le haut, ou dit 179 autrement ``la boîte s'ouvre''. Les parois latérales ne dépendent pas de 180 $\PI$. Enfin, le récepteur de surface $A_r$ est positionné sur la paroi du 181 bas et a pour dimension $R_x \times R_y$.} 182 \label{fig:configuration} 183 184 \end{figure} 185 186 \paragraph{La configuration radiative} 187 Les parois du parallélépipède sont toutes noires à l'exception de la paroi du 188 haut (de surface $A_h = D_x \times D_y$) qui est froide, spéculaire, et dont le 189 coefficient de réflexion $\rho$ est donné par: 190 \begin{equation} 191 \rho(\vec{x},-\vec{\omega}) = 0.25 \Bigl[ 1- \cos \left(2 \pi \frac{x}{Dx} 192 \right) \Bigr] \Bigl[ 1- \cos \left(2 \pi \frac{y}{Dy} \right) \Bigr] 193 \label{eq:rho} 194 \end{equation} 195 avec les constantes $D_x$ et $D_y$ décrites en figure~\ref{fig:configuration}. 196 Nous ne discutons pas ici du profil spécifique de $\rho$ mais soulignons 197 néanmoins qu'il simplifie le problème et permet ainsi de resserrer le présent 198 document sur le seul développement d'un algorithme analogue de calcul de 199 sensibilité. 200 201 En ce qui concerne les sources, seule la paroi noire de droite est émettrice. 202 Sa surface vaut $A_d = D_y \times h$ et la condition à la limite en luminance 203 correspondante est décrite par: 204 \begin{equation} 205 L(\vec{x},\vec{\omega},\PI) = S_b(\vec{x}) \quad \quad \quad \vec{x} \in A_d \ ; \ 206 \vec{\omega} \cdot \vec{n}_d > 0 207 \label{eq:cl_rad} 208 \end{equation} 209 avec $\vec{n}_d$ la normale de la paroi de droite et $S_b$ la source radiative 210 de surface qui correspond ici à son émission thermique: 211 \begin{equation} 212 S_b(\vec{x}) = L^{eq}(T) \Bigl[ 1- \cos \left(2 \pi \frac{x}{Dx} \right) \Bigr] 213 \Bigl[ 1- \cos \left(2 \pi \frac{y}{Dy} \right) \Bigr] 214 \label{eq:S_b} 215 \end{equation} 216 Enfin, le milieu englobant notre ``boîte'' est considéré comme étant froid et 217 transparent. 218 219 \paragraph{La sensibilité géométrique du flux} 220 On s'intéresse à la sensibilité du flux (équation \ref{eq:flux}) par rapport à 221 la variation de la position de la paroi spéculaire: 222 \begin{equation} 223 \partial_{\PI}\varphi = \int_{A_r} dS \int_{\mathcal{H}^-} d\vec{\omega} 224 \ (\vec{\omega} \cdot \vec{n}) \partial_{\PI} L(\vec{x},\vec{\omega},\PI) 225 \label{eq:sensib_flux} 226 \end{equation} 227 Pour évaluer le flux $\varphi$ nous avons besoin de connaître la luminance 228 $L(\vec{x},\vec{\omega},\PI)$, dans toutes les directions entrantes et en tout 229 point du récepteur. De façon similaire, pour évaluer $\partial_{\PI} \varphi$ 230 nous avons besoin de connaître la sensibilité géométrique $\partial_{\PI} 231 L(\vec{x},\vec{\omega},\PI)$, dans toutes les directions entrantes et en tout 232 point du récepteur. 233 234 La suite du document se concentre sur l'évaluation de cette sensibilité en 235 commençant par énnoncer le modèle physique qui décrit les sources et le 236 transport de la sensibilité géométrique (section~\ref{sec:modele_sensib}). 237 Nous développons alors un algorithme Monte Carlo pour résoudre le problème que 238 nous venons de poser en suivant la propagation des sources de sensibilité via 239 l'échantillonnage de chemins qui partent directement de ces sources, en 240 l'occurrence ici la seule paroi du haut (section~\ref{sec:monte_carlo}). 241 242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 243 % Le modèle de sensibilité 244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 245 \section{Modèle de sensibilité géométrique} 246 \label{sec:modele_sensib} 247 248 La sensibilité géométrique de la luminance est définie telle que: 249 \begin{equation} 250 s(\vec{x},\vec{\omega},\PI) = \partial_{3} L(\vec{x},\vec{\omega},\PI) = 251 \partial_{\PI} L(\vec{x},\vec{\omega},\PI) 252 \end{equation} 253 Elle est considérée comme une quantité physique à part entière dont la 254 phénoménologie est décrite par une équation de transfert radiatif dans le 255 domaine et par des contraintes aux frontières (conditions aux limites) sur la 256 sensibilité entrante dans le domaine. 257 258 \paragraph{Équation de transport} Dans \cite{papier_sensib} l'équation de la 259 sensibilité dans le milieu est donnée en toute généralité. Dans notre exemple 260 le milieu est transparent ($k_a = k_s = 0$) et peut donc se résumer à 261 l'équation \ref{eq:ETR-S}, avec $s = s(\vec{x},\vec{\omega},\PI)$: 262 \begin{equation} 263 \vec{w} \cdot \vec{\nabla} s = 0 264 \label{eq:ETR-S} 265 \end{equation} 266 267 \paragraph{Les conditions aux limites} Toujours dans \cite{papier_sensib} la 268 condition à la limite de la sensibilité géométrique est donnée en toute 269 généralité et dans les cas spécifiques des parois noires, parois spéculaires et 270 parois diffuses. Dans notre configuration, seule la paroi supérieure du 271 parallélépipède est paramétrée par $\PI$. Elle est donc la seule source de 272 sensibilité géométrique: 273 \begin{equation} 274 \begin{aligned} 275 s(\vec{x},\vec{\omega},\PI) & = 0 \quad \quad \quad \vec{x} \notin A_h \\ 276 s(\vec{x},\vec{\omega},\PI) & = S_{b,\PI} + \rho(\vec{x},-\vec{\omega}) 277 s(\vec{x},\vec{\omega}_{spec},\PI) \quad \quad \quad \vec{x} \in A_h \\ 278 \end{aligned} 279 \end{equation} 280 avec $S_{b,\PI}$ la source de sensibilité et $\rho(\vec{x},-\vec{\omega}) 281 s(\vec{x},\vec{\omega}_{spec},\PI)$ la réflection de la sensibilité incidente à 282 la paroi dans la direction spéculaire. Dans notre exemple, le milieu est 283 transparent et toutes les autres conditions aux limites de sensibilité sont 284 nulles. Il n'y a donc pas de sensibilité géométrique incidente à la paroi du 285 haut spéculaire. 286 %On se contente donc d'ignorer la sensibilité incidente à la paroi. On 287 %rappelle par ailleurs que la paroi du haut est spéculaire. 288 La source de sensibilité $S_{b,\PI}$ est donc définie comme ci-dessous en 289 renvoyant le lecteur à l'annexe \ref{ann:cl_sensib} pour les développements qui 290 mènent à cette expression: 291 \begin{equation} 292 \begin{aligned} 293 S_{b,\PI} = & - \beta_{\vec{\chi},h} [\partial_{1,\vec{u}_h} \ 294 \rho(\vec{x},-\vec{\omega})] L(\vec{x},\vec{\omega}_{spec},\PI) \quad \quad 295 \quad \quad \quad \vec{x} \in A_h \ ; \ \vec{\omega} \cdot \vec{n}_h > 0\\ 296 & + \rho(\vec{x},-\vec{\omega}) 297 \partial_{1,\vec{\chi}}L(\vec{x},\vec{\omega}_{spec},\PI)\\ 298 & - \rho(\vec{x},-\vec{\omega}) \beta_{\vec{\chi},h} \partial_{1,\vec{u}_h} 299 L(\vec{x},\vec{\omega}_{spec},\PI) 300 \end{aligned} 301 \label{eq:clsensib} 302 \end{equation} 303 avec $\vec{\omega}_{spec} = \vec{\omega} - 2 (\vec{\omega} \cdot \vec{n}_h) 304 \vec{n}_h$ et $\beta_{\vec{\chi},h}$ le coefficient issu de la décomposition de 305 $\vec{\chi}$ en deux vecteurs, l'un orienté par $\vec{\omega}$ et l'autre 306 orienté par un vecteur $\vec{u}_h$ tangent à la paroi du haut (voir annexe 307 \ref{ann:proj}). Enfin $\beta_{\vec{\chi},h}$ est la norme du vecteur 308 $\vec{\chi}$ projeté sur $\vec{u}_h$. La dérivée spatiale 309 $\partial_{1,\vec{\gamma}} f(\vec{x},\vec{\omega}) = \vec{\gamma} \cdot 310 \vec{\nabla}_{\vec{x}} f(\vec{x},\vec{\omega})$ est la dérivée directionnelle 311 dans la direction $\vec{\gamma}$. 312 313 \paragraph{La source de sensibilité} est dans notre cas une source de surface, 314 émise par la paroi du haut et donnée par la condition à la limite décrite par 315 l'expression~\ref{eq:clsensib}. Dans cette équation on note que la condition à 316 la limite de sensibilité dépend de: 317 \begin{itemize} 318 \item la luminance incidente à la paroi dans la direction de transport 319 spéculaire; 320 \item la dérivée spatiale de la luminance dans la direction de dérivation 321 $\vec{u}$, incidente à la paroi dans la direction de transport spéculaire; 322 \item et la dérivée spatiale de la luminance dans la direction de dérivation 323 $\vec{\chi}$, incidente à la paroi dans la direction de transport 324 spéculaire. 325 \end{itemize} 326 En résumé, la source de sensibilité émise par la paroi spéculaire est le 327 résultat du couplage entre le modèle de sensibilité, le modèle de transfert 328 radiatif et le modèle de dérivée spatiale. La dérivée spatiale de la luminance 329 est simplement considérée comme une quantité physique, au même titre que la 330 sensibilité géométrique (voir~\cite{papier_sensib} pour la description de son 331 modèle). Résoudre notre problème de sensibilité géométrique revient donc à 332 résoudre un problème de transport couplé qui dépend à la fois des source 333 radiatives (à travers $L(\vec{x},\vec{\omega}_{spec},\PI)$), des sources de 334 dérivées spatiales dans la direction $\vec{u}$ (à travers $\partial_{1,\vec{u}} 335 L(\vec{x},\vec{\omega}_{spec},\PI)$) et des sources de dérivées spatiales dans 336 la direction $\vec{\chi}$ (à travers $\partial_{1,\vec{\chi}} 337 L(\vec{x},\vec{\omega}_{spec},\PI)$). 338 339 \paragraph{Les sources du problème couplé} 340 La seule source radiative de notre configuration est donnée en 341 section~\ref{sec:probleme} par l'équation \ref{eq:cl_rad}. Elle correspond à 342 l'émission thermique $S_b$ de la paroi de droite de surface $A_d$. Pour les 343 sources de dérivée spatiale, le modèle de dérivée spatiale élaboré dans 344 \cite{papier_sensib} autorise des sources volumiques, des sources de surfaces 345 et des sources locales situées sur les arrêtes d'une géométrie triangulées. 346 Dans notre exemple ce modèle se simplifie de sorte que ces sources se résument 347 aux seules sources émises par la surface du haut $A_h$ et la surface de droite 348 $A_d$ (figure~\ref{fig:configuration}). 349 350 Pour la dérivée spatiale dans la direction $\vec{u}_h$, la source de la paroi 351 du haut est donnée par la condition à la limite: 352 \begin{equation} 353 \partial_{1,\vec{u}_h} L(\vec{x},\vec{\omega},\PI) = \beta_{\vec{u}_h,h} [ 354 \partial_{1,\vec{u}_s} \rho(\vec{x},-\vec{\omega}) ] 355 L(\vec{x},\vec{\omega}_{spec},\PI) \quad \quad \quad \vec{x} \in A_h \ ; \ 356 \vec{\omega} \cdot \vec{n}_h > 0 357 \label{eq:cl_duL_haut} 358 \end{equation} 359 et la source de la paroi de droite est donnée par la condition à la limite: 360 \begin{equation} 361 \partial_{1,\vec{u}_h} L(\vec{x},\vec{\omega},\PI) = \beta_{\vec{u}_h,d} 362 \partial_{1,\vec{u}_{hd}} S_b(\vec{x}) \quad \quad \quad \vec{x} \in A_d \ ; 363 \ \vec{\omega} \cdot \vec{n}_d > 0 364 \label{eq:cl_duL_droite} 365 \end{equation} 366 367 Pour la dérivée spatiale dans la direction $\vec{\chi}$, la source de la paroi 368 du haut est donnée par la condition à la limite: 369 \begin{equation} 370 \partial_{1,\vec{\chi}} L(\vec{x},\vec{\omega},\PI) = \beta_{\vec{\chi},h} [ 371 \partial_{1,\vec{u}_h} \rho(\vec{x},-\vec{\omega}) ] 372 L(\vec{x},\vec{\omega}_{spec},\PI) \quad \quad \quad \vec{x} \in A_h \ ; \ 373 \vec{\omega} \cdot \vec{n}_h > 0 374 \label{eq:cl_dchiL_haut} 375 \end{equation} 376 et la source de la paroi de droite est donnée par la condition à la limite: 377 \begin{equation} 378 \partial_{1,\vec{\chi}} L(\vec{x},\vec{\omega},\PI) = \beta_{\vec{\chi},d} 379 \partial_{1,\vec{u}_{\chi,d}} S_b(\vec{x}) \quad \quad \quad \vec{x} \in A_d \ 380 ; \ \vec{\omega} \cdot \vec{n}_d > 0 381 \label{eq:cl_dchiL_droite} 382 \end{equation} 383 384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 385 % Algorithme Direct 386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 387 \section{Résolution par Monte Carlo} 388 \label{sec:monte_carlo} 389 390 Dans cette section nous écrivons un algorithme de Monte Carlo pour résoudre le 391 problème décrit en section~\ref{sec:probleme} à partir du modèle de sensibilité 392 géométrique décrit en section~\ref{sec:modele_sensib}. Notre algorithme est 393 construit de manière analogue avec pour support la mise en {\oe}uvre pratique 394 de sa [[<<Fonction de réalisation>>]] en langage C~\cite{C_language}. Pour 395 cela, nous échantillonnerons des chemins qui démarrent directement de la source 396 de sensibilité, à savoir la paroi du haut, et qui la propage jusqu'au récepteur 397 positionné sur la paroi du bas. La mise en {\oe}uvre ici proposée est néanmoins 398 particulière dans le sens où chaque chemin du problème couplé est d'abord 399 échantillonné et conservé en totalité (section~\ref{subsec:chemin}). Son poids 400 n'est calculé qu'a posteriori à partir du chemin ainsi construit 401 (section~\ref{subsec:poids}). Cette proposition diffère d'un algorithme Monte 402 Carlo plus conventionnel où la position et la direction courante du chemin ne 403 sont que des données locales à chaque étape de sa construction; son poids étant 404 mis à jour si nécessaire à chacune de ces étapes. Ce choix singulier est dicté 405 par la volonté de garder à tout instant une vue d'ensemble du problème pour 406 s'éviter un travail d'abstraction et ainsi faciliter l'écriture analogue de 407 notre algorithme. Une démarche adaptée en raison de la configuration simplifiée 408 à laquelle nous nous intéressons. 409 410 <<Fonction de réalisation>>= 411 static res_T 412 realisation 413 (struct ssp_rng* rng, 414 const struct sgs_scene* scene, 415 double* w) 416 { 417 <<Données locales à la fonction de réalisation>> 418 res_T res = RES_OK; 419 420 <<Initialiser le poids>> 421 422 <<Échantillonner un chemin du problème couplé>> 423 <<Calcul du poids>> 424 425 exit: 426 <<Nettoyer les données locales de la fonction>> 427 <<Renvoyer le poids>> 428 return res; 429 } 430 @ 431 432 Notre fonction de réalisation prend en entrée un générateur de nombres 433 aléatoires ([[rng]]) et un pointeur vers les données du système ([[scene]]). 434 Dans la variable [[w]] sera renvoyé le poids de la sensibilité a $\PI$. 435 436 \subsection{Le chemin} 437 \label{subsec:chemin} 438 439 Pour construire un chemin du problème couplé on échantillonne d'abord un chemin 440 de sensibilité partant d'une position quelconque sur la surface de la source de 441 sensibilité $A_h$. Ce chemin est alors complété par l'échantillonnage d'un 442 chemin de dérivée spatiale dont la couplage avec le chemin de sensibilité forme 443 un chemin du problème couplé. 444 445 <<Échantillonner un chemin du problème couplé>>= 446 <<Échantillonner une position sur la source de sensibilité>> 447 <<Échantillonner un chemin de sensibilité>> 448 <<Échantillonner un chemin de dérivée spatiale>> 449 @ 450 451 Comme point de départ du chemin du problème couplé, on commence donc par 452 échantillonner uniformément un point sur la surface émettrice de sensibilité à 453 l'aide de la fonction [[sgs_geometry_sample_sensitivity_source]], et on stocke 454 dans les variables [[pos_h]] et [[normal_h]] sa position et la normale 455 correspondante. On récupère également dans [[surf_A_h]] l'identifiant de la 456 surface que l'on vient d'échantillonner, dans notre cas la surface supérieure 457 $A_h$ identifié dans le code par la constante [[SGS_SURFACE_Z_MAX]] (voir 458 figure~\ref{fig:configuration}). 459 460 <<Échantillonner une position sur la source de sensibilité>>= 461 /* Échantillonner uniformément une position sur la source de sensibilité */ 462 sgs_geometry_sample_sensitivity_source(scene->geom, rng, &frag); 463 d3_set(pos_h, frag.position); 464 d3_set(normal_h, frag.normal); 465 surf_A_h = frag.surface; /* surf_A_h == SGS_SURFACE_Z_MAX */ 466 @ 467 468 On rappelle que les sources de sensibilité proviennent des parois perturbées 469 par une modification du paramètre $\PI$. En toute hypothèse, toute source de 470 sensibilité incidente à $A_h$ serait réfléchie de façon spéculaire. Or, dans 471 notre cas, nous n'avons qu'une seule source de sensibilité, la surface $A_h$ 472 elle-même, et par conséquent nous n'avons pas à tenir compte de ces 473 sensibilités réfléchies. Nous n'échantillons donc que le seul chemin qui 474 propage l'émission de sensibilité par $A_h$. Ce chemin sera notre chemin de 475 sensibilité. Pour cela, il suffit d'échantillonner une direction d'émission 476 lambertienne [[dir_emit_h]] autour de la normale [[normal_h]] de la surface 477 $A_h$, et de lancer un rayon dans cette direction. Nous stockons alors dans 478 [[hit0]] l'intersection de ce rayon avec la géométrie de la scène. 479 480 <<Échantillonner un chemin de sensibilité>>= 481 /* Échantillonner une direction d'émission de sensibilité */ 482 ssp_ran_hemisphere_cos(rng, normal_h, dir_emit_h, NULL); 483 /* Lancer le rayon qui propage l'émission de sensibilité */ 484 TRACE_RAY(pos_h, dir_emit_h, surf_A_h, &hit0); 485 @ 486 487 La source de sensibilité est donnée dans la condition à la limite décrite par 488 l'équation~\ref{eq:clsensib}. Elle dépend de la dérivée spatiale selon 489 $\vec{\chi}$ incidente dans la direction spéculaire $\vec{\omega}_{spec}$ et de 490 la dérivée spatiale selon $\vec{u}$ incidente à la même direction spéculaire. 491 Ces contributions à l'émission de sensibilité ne sont pas connues et sont ici 492 échantillonnées par \textit{double randomization}. Comme ces deux dérivées 493 spatiales sont incidentes à la même direction $\vec{\omega}_{spec}$ nous 494 pouvons nous contenter de ne suivre qu'un seul chemin dans cette direction. Ce 495 chemin sera notre chemin de dérivée spatiale. Pour échantillonner ce chemin 496 nous calculons d'abord $\vec{\omega}_{spec}$ ([[dir_spec_h]]) par réflexion 497 spéculaire de la direction d'émission $\vec{\omega}$ ([[dir_emit_h]]) avant de 498 lancer un rayon dans cette direction jusqu'à l'intersection [[hit1]] avec une 499 surface . 500 501 <<Échantillonner un chemin de dérivée spatiale>>= 502 /* Calculer la direction spéculaire à dir_emit_h */ 503 reflect(dir_spec_h, dir_emit_h, normal_h); 504 /* Tracer le rayon spéculaire partant de surf_A_h */ 505 TRACE_RAY(pos_h, dir_spec_h, surf_A_h, &hit1); 506 @ 507 508 \subsection{Le poids} 509 \label{subsec:poids} 510 511 Dans notre problème, un chemin du problème couplé est composé d'un chemin de 512 sensibilité et d'un chemin de dérivée spatiale, chacun d'entre eux se résumant 513 à un segment dont l'origine commune se situe sur la paroi du haut, source de 514 sensibilité. Or, on peut dès à présent déterminer qu'un chemin couplé aura une 515 contribution nulle si le chemin de sensibilité n'atteint pas le récepteur ou si 516 le chemin de dérivé spatiale n'atteint pas la source radiative, à savoir la 517 paroi de droite. 518 519 <<Initialiser le poids>>= 520 sensib = 0; 521 @ 522 <<Échantillonner un chemin de sensibilité>>= 523 if(!hit_receiver(scene, pos_h, dir_emit_h, &hit0)) { 524 goto exit; 525 } 526 @ 527 <<Échantillonner un chemin de dérivée spatiale>>= 528 if(!hit_source(scene, pos_h, dir_spec_h, &hit1)) { 529 goto exit; 530 } 531 @ 532 533 En conséquence nous pouvons assumer dans la suite de la fonction que nous 534 n'aurons à calculer le poids que des seuls chemin couplés dont la contribution 535 est non nulle. Dès lors, [[hit1]] représente une intersection sur la source 536 radiative. On stocke dans [[normal_d]] la normale de la paroi correspondante 537 dont on aura besoin pour le calcul du poids. De même, on initialise la variable 538 [[dir_emit_d]] à $-\vec{\omega}_s$, cette direction nous sera également utile 539 pour évaluer la source de dérivée spatiale. 540 541 <<Échantillonner un chemin de dérivée spatiale>>= 542 d3_normalize(normal_d, hit1.normal); 543 d3_minus(dir_emit_d, dir_spec_h); 544 @ 545 546 Dans notre problème couplé, la contribution du chemin, {\ie} le poids Monte 547 Carlo, va s'exprimer à travers la condition à la limite de sensibilité 548 (équation \ref{eq:clsensib}) et des sources de chacun de ses couplages. 549 550 <<Calcul du poids>>= 551 <<Décomposition du vecteur de déformation $\vec{\chi}$>> 552 553 <<Calcul de la dérivée surfacique de $\rho$>> 554 <<Calcul des sources de dérivées spatiales>> 555 556 <<Calculer le poids de sensibilité>> 557 @ 558 559 La décomposition du vecteur de déformation $\vec{\chi}$ permet d'obtenir le 560 vecteur tangent $\vec{u}$ nécessaire dans l'expression de la source de 561 sensibilité et de ses dérivées surfaciques (équation \ref{eq:clsensib}). 562 563 <<Décomposition du vecteur de déformation $\vec{\chi}$>>= 564 decomposition(chi, normal_h, dir_emit_h, &proj_chi_h); 565 @ 566 567 Étant donné que le coefficient de réflection n'est défini qu'en frontière, à 568 savoir sur un plan en deux dimensions, calculer la dérivée surfacique de $\rho$ 569 revient à travailler dans le plan. Et cette dérivée surfacique est le 570 produit scalaire entre le gradient surfacique de $\rho$ et la direction de 571 dérivation $\vec{u}$ transformée dans ce plan ([[u_2d]]). 572 573 <<Calcul de la dérivée surfacique de $\rho$>>= 574 <<Récupérer le gradient surfacique de $\rho$>> 575 576 /* Transformer u dans le plan XY */ 577 u_2d[0] = proj_chi_h.u[X]; 578 u_2d[1] = proj_chi_h.u[Y]; 579 580 /* Calculer la dérivée surfacique de rho */ 581 d_rho = d2_dot(grad_rho_2d, u_2d); 582 @ 583 584 Pour récupérer $\rho$ et son gradient, il nous suffit de transformer dans le 585 plan la position d'émission [[pos_h]], et d'interroger les données associées à 586 la position ainsi transformée ([[pos_h_2d]]). 587 588 <<Récupérer le gradient surfacique de $\rho$>>= 589 /* Transformer pos_h dans le plan XY */ 590 pos_h_2d[0] = pos_h[X]; 591 pos_h_2d[1] = pos_h[Y]; 592 593 rho = get_rho(scene, pos_h_2d); 594 get_grad_rho(scene, pos_h_2d, grad_rho_2d); 595 @ 596 597 On rappelle que la sensibilité est couplée à deux dérivées spatiales (selon 598 $\vec{\chi}$ et $\vec{u}$) dont les sources sont données par les équations 599 \ref{eq:cl_duL_haut}, \ref{eq:cl_duL_droite}, \ref{eq:cl_dchiL_haut} et 600 \ref{eq:cl_dchiL_droite}. 601 602 <<Calcul des sources de dérivées spatiales>>= 603 <<Décomposition du vecteur $\vec{\chi}$>> 604 <<Décomposition du vecteur $\vec{u}$>> 605 <<Calcul de la dérivée surfacique de $Sb$ dans la direction $\vec{u}_e$>> 606 <<Calcul de la dérivée surfacique de $Sb$ dans la direction $\vec{u}_{cs}$>> 607 @ 608 609 Sur la paroi de droite, la décomposition du vecteur de déformation $\vec{\chi}$ 610 permet d'obtenir le vecteur tangent $\vec{u}$ nécessaire dans l'expression de 611 la source de de la dérivée spatiale dans la direction $\vec{\chi}$ et de sa 612 dérivée surfacique (équation \ref{eq:cl_dchiL_droite}). 613 614 <<Décomposition du vecteur $\vec{\chi}$>>= 615 decomposition(chi, normal_d, dir_emit_d, &proj_chi_d); 616 @ 617 618 De la même façon, la décomposition du vecteur $\vec{u}$ permet d'obtenir le 619 vecteur tangent $\vec{u}_e$ nécessaire dans l'expression de la source de la 620 dérivée spatiale dans la direction $\vec{u}$ et de sa dérivée surfacique 621 (equation \ref{eq:cl_duL_droite}). 622 623 <<Décomposition du vecteur $\vec{u}$>>= 624 decomposition(proj_chi_h.u, normal_d, dir_emit_d, &proj_uh_d); 625 @ 626 627 La dérivée surfacique de $S_b$ dans la direction $\vec{u}_{e}$ ([[dSb_uhd]]) 628 est le produit scalaire entre le gradient surfacique de $S_b$ et la direction 629 de dérivation $\vec{u}_{e}$ transformée dans le plan de la paroi de droite 630 ([[u_hd_2d]]). Mais pour effectuer ce calcul nous devons au préalable récupérer 631 le gradient de $S_b$ ([[grad_Sb_2d]]). Pour cela il nous suffit là encore de 632 transformer dans le plan de la paroi de droite la position d'émission 633 [[pos_d]], et d'interroger les données associées à la position ainsi 634 transformée ([[pos_d_2d]]). Et nous en profitons au passage pour récupérer 635 $S_b$ qui nous sera utile pour le calcul du poids. Pour rappel, dans notre 636 configuration les deux dérivées spatiales $\partial_{\vec{\chi}} I$ et 637 $\partial_{\vec{u}} I$ partagent une même position d'émission ([[pos_d]]). 638 639 <<Calcul de la dérivée surfacique de $Sb$ dans la direction $\vec{u}_e$>>= 640 /* Calculer la position sur l'émetteur */ 641 pos_d[X] = pos_h[X] + dir_spec_h[X]*hit1.distance; 642 pos_d[Y] = pos_h[Y] + dir_spec_h[Y]*hit1.distance; 643 pos_d[Z] = pos_h[Z] + dir_spec_h[Z]*hit1.distance; 644 645 /* Transformer pos_d dans le plan YZ */ 646 pos_d_2d[0] = pos_d[Y]; 647 pos_d_2d[1] = pos_d[Z]; 648 649 /* Récupérer le gradient surfacique de Sb */ 650 Sb = get_Sb(scene, pos_d_2d); 651 get_grad_Sb(scene, pos_d_2d, grad_Sb_2d); 652 653 /* Transformer u_e dans le plan YZ */ 654 u_hd_2d[0] = proj_uh_d.u[Y]; 655 u_hd_2d[1] = proj_uh_d.u[Z]; 656 657 /* Dérivée surfacique de Sb dans la direction u_e */ 658 dSb_uhd = d2_dot(grad_Sb_2d, u_hd_2d); 659 @ 660 661 Ne reste plus qu'à calculer la dérivée surfacique de $S_b$ dans la direction 662 $\vec{u}_{cs}$ ([[dSb_uchid]]) comme étant le produit scalaire entre le 663 gradient surfacique de $S_b$ et la direction $\vec{u}_{cs}$ transformée dans le 664 plan de la paroi de droite ([[u_chid_2d]]). 665 666 <<Calcul de la dérivée surfacique de $Sb$ dans la direction $\vec{u}_{cs}$>>= 667 /* Transformer u_cs dans le plan YZ */ 668 u_chid_2d[0] = proj_chi_d.u[Y]; 669 u_chid_2d[1] = proj_chi_d.u[Z]; 670 671 /* Dérivée surfacique de Sb dans la direction u_cs */ 672 dSb_uchid = d2_dot(grad_Sb_2d, u_chid_2d); 673 @ 674 675 On est alors en mesure d'évaluer le poids de sensibilité comme la contribution 676 portée par le chemin du problème couplé, soit les sources de dérivées spatiales 677 propagées jusqu'à la paroi du haut puis intégrées dans les sources de 678 sensibilité propagées ensuite vers le récepteur. Cette contribution est 679 ensuite multipliée par la surface $A_h$ et l'angle $\pi$ ([[PI]]) étant donné 680 l'échantillonnage des densités de probabilités de la position sur la surface et 681 de la direction dans l'hémisphère sortante de la paroi. 682 683 <<Calculer le poids de sensibilité>>= 684 /* Calcul de la contribution du chemin couplé */ 685 Sb_sensib = 686 - proj_chi_h.beta * d_rho * Sb 687 - rho * proj_chi_h.beta * proj_uh_d.beta * dSb_uhd 688 + rho * proj_chi_d.beta * dSb_uchid; 689 690 /* Poids de sensibilité */ 691 sensib = Sb_sensib * PI * get_Sr(scene); 692 @ 693 694 <<Renvoyer le poids>>= 695 w[0] = sensib; 696 @ 697 698 \subsection{Variables locales et macro} 699 700 Lors de l'échantillonnage des chemins (section~\ref{subsec:chemin}) nous nous 701 sommes appuyé sur la fonction [[TRACE_RAY]] nous permettant de lancer un rayon 702 dans la scène. Cette fonction est en réalité un macro, locale à la fonction, 703 qui encapsule l'appel à la fonction qui lance un rayon. En plus de l'origine et 704 de la direction du rayon, cette fonction nécessite en entrée une plage des 705 distances d'intersection possible ([[range]]), dans notre cas toujours définie 706 à $[0, \infty]$. À noter également le paramètre d'entrée [[StartFrom]] qui 707 stocke le triangle sur lequel se trouve l'origine du rayon, une donnée d'entrée 708 utilisée pour éviter une auto-intersection, c'est à dire l'intersection du 709 rayon avec le triangle dont il est issu. 710 711 <<Données locales à la fonction de réalisation>>= 712 /* Macro utilisée comme sucre syntaxique */ 713 #define TRACE_RAY(Org, Dir, StartFrom, Hit) { \ 714 double range[2]; \ 715 range[0] = 0; \ 716 range[1] = INF; \ 717 sgs_geometry_trace_ray \ 718 (scene->geom, (Org), (Dir), range, (StartFrom), (Hit));\ 719 } (void)0 720 @ 721 722 <<Nettoyer les données locales de la fonction>>= 723 #undef TRACE_RAY 724 @ 725 726 \paragraph{} 727 Enfin, nous déclarons ci-après l'ensemble des variables locales nécessaires à 728 notre [[<<Fonction de réalisation>>]]: 729 730 <<Données locales à la fonction de réalisation>>= 731 /* Variables de la source de sensibilité */ 732 double dir_emit_h[3]; 733 double pos_h[3]; 734 double normal_h[3]; 735 double dir_spec_h[3]; 736 double pos_h_2d[2]; 737 enum sgs_surface_type surf_A_h; 738 struct sgs_fragment frag; /* Position échantillonnée */ 739 740 /* Variables de la source radiative */ 741 double pos_d[3]; 742 double normal_d[3]; 743 double dir_emit_d[3]; 744 double pos_d_2d[2]; 745 746 /* Propriétés radiatives des surfaces et leur dérivée */ 747 double rho; 748 double d_rho; 749 double grad_rho_2d[2]; 750 double Sb; 751 double dSb_uhd; 752 double dSb_uchid; 753 double grad_Sb_2d[2]; 754 755 /* Vecteurs des déformations et variables de projection */ 756 const double chi[3] = {0, 0, 1}; 757 double u_2d[2]; 758 double u_hd_2d[2]; 759 double u_chid_2d[2]; 760 struct projection proj_chi_h; 761 struct projection proj_chi_d; 762 struct projection proj_uh_d; 763 764 /* Pour le calcul du poids */ 765 double Sb_sensib; 766 double sensib; 767 768 /* Intersections avec la géométrie */ 769 struct sgs_hit hit0; 770 struct sgs_hit hit1; 771 @ 772 773 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 774 % Résultats 775 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 776 \section{Résultats} 777 \label{sec:results} 778 779 Au delà du simple calcul de sensibilité nous proposons ici une vérification des 780 résultats par le calcul de différences finies. La différentiation est effectuée 781 à partir des estimations du flux $\varphi(\PI)$ reçu par le capteur pour 782 différentes valeurs du paramètre géométrique $\PI$, soit pour différentes 783 hauteurs de la paroi spéculaire. Le calcul du poids associé au calcul du flux 784 est décrit en annexe \ref{annex:flux}. La figure \ref{fig:resultats} présente les 785 estimations de la sensibilité du flux et des différences finies correspondantes. 786 Les paramètres des simulations Monte Carlo et des calculs en différences finies, 787 et plus généralement le code source des scripts à l'origine de ces résultats 788 sont données en annexe~\ref{annex:scripts}. 789 790 \begin{figure}[h!] 791 \centering 792 \begin{tikzpicture} 793 \begin{axis}[ 794 xlabel=$\frac{\PI}{h}$, 795 ylabel=$\partial_{\PI} \hat{\varphi}$, 796 width=0.7\linewidth, 797 legend style={at={(0.95,0.3)}} 798 ] 799 \addplot[ 800 color=black, 801 mark=square*, 802 only marks, 803 mark size=2pt, 804 every mark/.append style={solid, fill=black}, 805 error bars/.cd, 806 y dir=both, 807 y explicit, 808 error mark=|, 809 error mark options={mark size=1pt}, 810 error bar style={ 811 line width=0.6pt, 812 color=black} 813 ] 814 table[x=pi_over_h, y=sen_mc, y error=err_mc, col sep=space]{results.fd}; 815 \addlegendentry{Monte Carlo} 816 817 \addplot[ 818 color=black, 819 mark=*, 820 only marks, 821 mark size=1.5pt, 822 every mark/.append style={solid, fill=white}, 823 error bars/.cd, 824 y dir=both, 825 y explicit, 826 error mark=|, 827 error mark options={mark size=1pt}, 828 error bar style={ 829 line width=0.6pt, 830 color=black} 831 ] 832 table[x=pi_over_h, y=sen_fd, y error=err_fd, col sep=space]{results.fd}; 833 \addlegendentry{Différences Finies} 834 \end{axis} 835 836 \end{tikzpicture} 837 \flushleft 838 \caption{Estimations des sensibilités du flux par Monte Carlo et comparaison 839 avec les différences finies du flux. Les résultats sont adimensionnalisés et 840 affichés en fonction de l'ouverture du parallélépipède, qui est paramétrée 841 par $\PI$. La sensibilité du flux $\partial_{\PI} \hat{\varphi} = 842 \frac{\partial_{\PI} \varphi}{\varphi_{max}} h$ avec $\varphi_{max} = 843 \varphi_{spec}(\PI=0)$. Dans cette expression, $\varphi_{spec}$ correspond 844 uniquement à la partie du flux qui arrive au récepteur après avoir été 845 réfléchie sur la paroi spéculaire (voir annexe~\ref{annex:flux}). Le nombre 846 d'échantillonnage du poids de Monte Carlo nécessaire à la reproduction de ce 847 résultat est $10^{8}$.} 848 \label{fig:resultats} 849 \end{figure} 850 851 \appendix 852 853 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 854 % Annexe CL de sensibilité 855 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 856 \section{Détails de la condition à la limite de sensibilité} 857 \label{ann:cl_sensib} 858 859 Nous récupérons ici la condition à la limite pour une paroi spéculaire donnée 860 dans \cite{papier_sensib} $s = s(\vec{x},\vec{\omega},\PI)$: 861 \begin{equation} 862 s = \mathcal{C}_b \lbrack s \rbrack + S_{b,\PI} \lbrack L, \partial_{1,\vec{u}}L, 863 \partial_{1,\vec{\chi}} L, \partial_{2,\vec{\gamma}_t}L \rbrack \quad \quad \quad 864 \vec{x} \in \partial G(\PI) ; \vec{\omega} \cdot \vec{n} > 0 865 \label{eq:cl_sensib_gen} 866 \end{equation} 867 avec $S_{b,\PI}$ la source surfacique de sensibilité: 868 \begin{equation} 869 \begin{aligned} 870 S_{b,\PI} = & - \alpha (\mathcal{C}[L] + S) \\ 871 & - \beta \partial_{1,\vec{u}} S_b - \partial_{2,\vec{\gamma}} S_b + 872 \partial_{\PI} S_b \\ 873 & - \beta \partial_{1,\vec{u}} \mathcal{C}_b[L] + \partial_{\PI} \mathcal{C}_b 874 [L] \\ 875 & - \partial_{2,\vec{\gamma}} \rho(\vec{x},-\vec{\omega}) \int_{H'} 876 p_{\Omega'}(-\vec{\omega}'|\vec{x},-\vec{\omega})d\vec{\omega}' L \\ 877 & - \beta \mathcal{C}_b[\partial_{1,\vec{u}}L] + 878 \mathcal{C}_b[\partial_{1,\vec{\chi}} L] \\ 879 & + 2 \mu \partial_{2,\vec{\gamma}_t} L(\vec{x},\vec{\omega}_{spec},\PI) 880 \end{aligned} 881 \end{equation} 882 883 Dans cette équation $\mathcal{C}$ est l'opérateur collisionnel du milieu: 884 \begin{equation} 885 \mathcal{C}[L] = -k_a L(\vec{x},\vec{\omega},\PI) - k_s 886 L(\vec{x},\vec{\omega},\PI) + k_s \int_{\mathcal{S}} 887 p_{\Omega'}(\vec{\omega}'|\vec{x},\vec{\omega}) d\vec{\omega}' 888 L(\vec{x},\vec{\omega}',\PI) 889 \end{equation} 890 La source $S$ est la source radiative du milieu (émission thermique $k_a 891 L^{eq}(T)$). On trouve également $\mathcal{C}_b$ l'opérateur collisionnel de la 892 surface. Appliqué à la luminance et dans le cas d'une paroi spéculaire il 893 s'écrit: 894 \begin{equation} 895 \mathcal{C}_b[L] = \rho(\vec{x},-\vec{\omega}) \int_{H'} \delta(\vec{\omega}' - 896 \vec{\omega}_{spec}) L(\vec{x},\vec{\omega}',\PI) d\vec{\omega}' 897 \end{equation} 898 avec $\vec{\omega}_{spec} = \vec{\omega} - 2(\vec{\omega} \cdot 899 \vec{n})\vec{n}$ 900 901 \paragraph{Condition à la limite de notre exemple} 902 Pour commencer, seule la paroi spéculaire est source de sensibilité géométrique. 903 Nous voyons dans l'équation \ref{eq:cl_sensib_gen} que le terme collisionnel 904 $\mathcal{C}_b[s]$ traduit la réflexion de la sensibilité incidente à la paroi 905 spéculaire. Ce terme est obligatoirement nul puisque il n'y a aucune autre 906 source qui pourrait émettre une sensibilité géométrique et aucune autre paroi 907 réfléchissante qui pourrait réfléchir la sensibilité émise par la paroi 908 spéculaire. 909 910 Dans notre exemple le milieu est transparent, les termes 911 $\mathcal{C}[L]$ et $S$ sont donc nuls. La paroi spéculaire est 912 froide, la source surfacique $S_b$ qui dans cet exemple 913 correspondrait à l'émission thermique de la paroi est donc aussi 914 nulle. L'opérateur collisionnel de la surface $\mathcal{C}_b$ est 915 indépendant de $\PI$, la dérivée $\partial_{\PI} \mathcal{C}_b$ est 916 donc nulle. Pour finir la déformation géométrique de la paroi 917 spéculaire est une translation, l'axe de rotation $\vec{\gamma}$ est 918 donc nul et toutes les dérivées angulaires n'ont plus lieux d'être 919 dans la condition à la limite. 920 921 La condition à la limite de sensibilité de la paroi spéculaire de la boite 922 devient donc: 923 \begin{equation} 924 \begin{aligned} 925 s = & - \beta \partial_{1,\vec{u}} \mathcal{C}_b[L] \\ 926 & + \mathcal{C}_b[\partial_{1,\vec{\chi}}L - \beta \partial_{1,\vec{u}} L] 927 \end{aligned} 928 \end{equation} 929 avec 930 \begin{equation} 931 \beta \partial_{1,\vec{u}} \mathcal{C}_b [L] = \beta \left(\partial_{1,\vec{u}} 932 \rho(\vec{x},-\vec{\omega}) \right) \int_{H'} 933 \delta(\vec{\omega}'-\vec{\omega}_{spec}) L(\vec{x},\vec{\omega}',\PI) 934 d\vec{\omega}' 935 \end{equation} 936 En prenant en compte le fait que: 937 \begin{equation} 938 \int_{H'} \delta(\vec{\omega}' - \vec{\omega}_{spec}) f(\vec{\omega}') 939 d\vec{\omega}' = f(\vec{\omega}_{spec}) 940 \end{equation} 941 on trouve finalement: 942 \begin{equation} 943 \begin{aligned} 944 s(\vec{x},\vec{\omega},\PI) = & - \beta 945 \left(\partial_{1,\vec{u}}\rho(\vec{x},-\vec{\omega}) \right) 946 L(\vec{x},\vec{\omega}_{spec},\PI) \\ 947 & + \partial_{1,\vec{\chi}}L(\vec{x},\vec{\omega}_{spec},\PI) - \beta 948 \partial_{1,\vec{u}} L(\vec{x},\vec{\omega}_{spec},\PI) 949 \end{aligned} 950 \end{equation} 951 952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 953 % Annexe décomposition 954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 955 \section{Décomposition du vecteur de déformation} 956 \label{ann:proj} 957 958 Dans le modèle de sensibilité la déformation est caractérisée par le 959 vecteur de déformation $\vec{\chi}$. La condition à la limite de 960 sensibilité dépend alors de la dérivée spatiale 961 $\partial_{1,\vec{\chi}}L$ (équation \ref{eq:clsensib}). Le champs 962 de luminance n'étant pas connu il n'existe pas de solution 963 analytique à cette dérivée. À la frontière nous avons donc choisi de 964 décomposer la direction $\vec{\chi}$ ([[chi]]) en deux directions 965 distinctes, une direction tangente à la frontière $\vec{u}$ ([[u]]) 966 et la direction de transport $\vec{\omega}$ ([[omega]]). Ainsi la 967 dérivée de $L$ selon $\vec{\chi}$ devient une composition de 968 dérivées de $L$ le long de la paroi (sur laquelle la luminance est 969 connue) et le long de la direction de transport (retrouvant ainsi le 970 terme de transport de l'ETR). 971 972 La décomposition de $\vec{\chi}$ s'écrit: 973 \begin{equation} 974 \vec{\chi} = \alpha \vec{\omega} + \beta \vec{u} 975 \label{eq:chi_decomp} 976 \end{equation} 977 avec $\alpha$ ([[alpha]]) et $\beta$ ([[beta]]) les coefficients issus de la 978 projection de $\vec{\chi}$ sur $\vec{n}$ ([[normal]]) et $\vec{u}$. Pour plus 979 de précisions sur la base non-orthogonale utilisée pour cette décomposition, 980 nous renvoyons le lecteur vers \cite{papier_sensib}. Nous nous contentons de 981 donner ici les résultats: 982 \begin{equation} 983 \alpha = \frac{\vec{\chi}.\vec{n}}{\vec{\omega}.\vec{n}} \ \; \quad \beta = 984 \|\vec{\chi} - \alpha \vec{\omega} \| \ \; \quad \vec{u} = \frac{\vec{\chi} - 985 \alpha \vec{\omega}}{\beta} 986 \end{equation} 987 Ce qui permet d'obtenir: 988 \begin{equation} 989 \partial_{1,\vec{\chi}}L = \alpha \partial_{1,\vec{\omega}} L + \beta 990 \partial_{1,\vec{u}} L 991 \end{equation} 992 et de résoudre la dérivée en estimant $\partial_{1,\vec{u}}L$ le long de la 993 surface et en utilisant l'ETR pour résoudre $\partial_{1,\vec{\omega}}L$: 994 \begin{equation} 995 \partial_{1,\vec{\omega}}L = \mathcal{C} \lbrack L \rbrack 996 \end{equation} 997 998 La fonction [[decomposition]] réalise cette décomposition et les résultats 999 ([[alpha]], [[beta]] et [[u]]) sont retournés via les variables membres de la 1000 structure [[projection]]: 1001 1002 <<Fonctions utilitaires>>= 1003 struct projection { 1004 double alpha; 1005 double beta; 1006 double u[3]; 1007 }; 1008 1009 static void 1010 decomposition 1011 (const double chi[3], 1012 const double normal[3], 1013 const double omega[3], 1014 struct projection* projection) 1015 { 1016 ASSERT(chi && normal && omega && projection); 1017 ASSERT(d3_is_normalized(normal)); 1018 ASSERT(d3_is_normalized(omega)); 1019 1020 projection->alpha = d3_dot(chi, normal) / d3_dot(omega, normal); 1021 projection->u[X] = chi[X] - projection->alpha*omega[X]; 1022 projection->u[Y] = chi[Y] - projection->alpha*omega[Y]; 1023 projection->u[Z] = chi[Z] - projection->alpha*omega[Z]; 1024 projection->beta = d3_normalize(projection->u, projection->u); 1025 } 1026 @ 1027 1028 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1029 % Annexe "luminance" 1030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1031 \section{Calcul de la contribution de la luminance qui dépend de $\PI$} 1032 \label{annex:flux} 1033 1034 Le flux reçu par le capteur est décrit par l'équation \ref{eq:flux}. Dans notre 1035 problème, la luminance $L(\vec{x},\vec{\omega},\PI)$ incidente au récepteur 1036 dépend de deux sortes de chemins radiatifs qui traduisent le transport de la 1037 source émise par la paroi de droite : 1038 \begin{itemize} 1039 \item soit la source est transportée directement depuis la paroi de droite 1040 jusqu'au récepteur; 1041 \item soit la source est transportée en direction de la paroi spéculaire puis 1042 réfléchie jusqu'au récepteur. 1043 \end{itemize} 1044 Dans notre configuration le paramètre géométrique $\PI$ n'a d'influence que sur 1045 la hauteur de la paroi spéculaire. Ainsi, la contribution radiative de la source 1046 émise par la paroi de droite, transportée directement vers le récepteur, reste 1047 identique pour toutes valeurs de $\PI$ (c'est à dire quelle que soit la hauteur 1048 de la paroi spéculaire). Du point de vue de la sensibilité 1049 cette contribution n'aura donc aucune influence. 1050 1051 En pratique cela signifie que, en vue d'une validation via un calcul des 1052 différences finies, le calcul par Monte Carlo du flux au récepteur n'est pas 1053 entièrement nécessaire. Nous pouvons nous contenter d'estimer l'unique partie du 1054 flux qui sera perturbée par une variation de $\PI$, soit les contributions 1055 portées par les chemins réfléchis par la paroi spéculaire. En terme d'algorithme 1056 nous pouvons donc réutiliser les chemins déjà échantillonnés pour le problème 1057 couplé puisque leur statistique correspond exactement à celle d'un chemin émis 1058 par la paroi de droite et réfléchi par la paroi du haut. 1059 1060 Le poids ([[weight_flux_part_spec]]) correspondant à la partie du flux venant 1061 de la réflection sur la paroi spéculaire est donc calculé au même moment que 1062 celui de la sensibilité. 1063 1064 <<Données locales à la fonction de réalisation>>= 1065 double weight_flux_part_spec; 1066 @ 1067 1068 Le poids de cette contribution correspond à la source radiative $S_b$ 1069 (equation~\ref{eq:cl_rad}) représentée par la variable [[Sb]] multipliées par 1070 l'angle $\pi$ ([[PI]]), la surface $A_h$ et le coefficient de réflection $\rho$ 1071 ([[rho]]). 1072 1073 <<Calcul du poids>>= 1074 weight_flux_part_spec = Sb * rho * PI * get_Sr(scene); 1075 @ 1076 1077 <<Renvoyer le poids>>= 1078 w[1] = weight_flux_part_spec; 1079 @ 1080 1081 Ce poids est également initialisé en même temps que celui de la sensibilité de 1082 sorte que les chemins réfléchis n'atteignant pas le récepteur aient une 1083 contribution nulle. 1084 1085 <<Initialiser le poids>>= 1086 weight_flux_part_spec = 0; 1087 @ 1088 1089 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1090 % Annexe fonction de calcul 1091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1092 \section{Fonction de calcul} 1093 \label{sec:fonction_de_calul} 1094 1095 Le programme présenté jusqu'alors s'est concentré sur la mise en {\oe}uvre de 1096 la seule fonction de réalisation de notre algorithme de Monte Carlo; la boucle 1097 d'intégration, l'accumulation des poids ou encore l'affichage des résultats y 1098 sont absents. Dans cette section nous détaillons ces étapes manquantes afin de 1099 compléter le programme écrit jusqu'ici et ainsi proposer une mise en {\oe}uvre 1100 complète de l'algorithme de Monte Carlo objet du présent document. Ces étapes 1101 sont regroupées dans la fonction qui suit: 1102 1103 <<Calculer la sensibilité à la translation>>= 1104 res_T 1105 compute_sensitivity_translation(struct sgs* sgs) 1106 { 1107 <<Variables locales au calcul de sensibilité>> 1108 res_T res = RES_OK; 1109 1110 <<Exécuter l'intégration Monte Carlo>> 1111 <<Afficher les résultats de l'estimation>> 1112 1113 exit: 1114 <<Libérer les variables locales au calcul de sensibilité>> 1115 return res; 1116 error: 1117 goto exit; 1118 } 1119 @ 1120 1121 Dans cette fonction on commence par exécuter l'intégration Monte Carlo. Cette 1122 étape consiste à invoquer notre [[<<Fonction de réalisation>>]] autant de fois 1123 que de nombre de réalisations demandées, et à accumuler les poids qu'elle 1124 retourne. D'apparence triviale, cette simple boucle s'avère plus compliquée 1125 pour qui souhaite paralléliser son calcul. Au delà des questions propres à une 1126 exécution parallèle, d'aucun doit s'assurer que chaque processus dispose d'une 1127 séquence de nombre aléatoires qui lui est propre. C'est pourquoi nous utilisons 1128 ici la bibliothèque \texttt{Star-MonteCarlo} en charge de cette intégration 1129 parallèle. Pour cela nous créons d'abord un système \texttt{Star-MonteCarlo}, 1130 c'est à dire une variable qui matérialise la bibliothèque à l'échelle de notre 1131 programme ([[smc]]). Et nous le configurons pour qu'il utilise le journal 1132 d'évènement ([[logger]]), l'allocateur mémoire ([[allocator]]) et le nombre de 1133 processus légers ([[nthreads]]) soumis en entrée de la fonction via la variable 1134 [[sgs]]. Nous configurons enfin le type de générateur aléatoire à utiliser, en 1135 l'occurrence le générateur pseudo alétoire 1136 Mersenne-Twister~\cite{matsumoto1998mersenne} ([[SSP_RNG_MT19937_64]]). Nous 1137 pouvons alors lancer l'intégration Monte Carlo à proprement parler. Pour cela 1138 nous définissons un intégrateur qui détermine la fonction à appeler à chaque 1139 réalisation ([[run_realisation]]), le type de poids calculés ([[smc_doubleN]], 1140 {\ie} un vecteur de réels) et le nombre total de réalisations 1141 ([[nrealisations]]) défini comme paramètre d'entrée via la variable [[sgs]]. 1142 1143 <<Exécuter l'intégration Monte Carlo>>= 1144 /* Configurer et créer le système Star-MonteCarlo */ 1145 smc_args.logger = &sgs->logger; 1146 smc_args.allocator = sgs->allocator; 1147 smc_args.nthreads_hint = sgs->nthreads; 1148 smc_args.rng_type = SSP_RNG_MT19937_64; 1149 res = smc_device_create(&smc_args, &smc); 1150 if(res != RES_OK) goto error; 1151 1152 /* Configurer l'intégrateur */ 1153 integrator.integrand = run_realisation; 1154 integrator.type = &smc_doubleN; 1155 integrator.max_realisations = sgs->nrealisations; 1156 ctx.count = 2; /* Nombre de poids calculés (Sensibilité & "luminance") */ 1157 ctx.integrand_data = sgs; /* Données d'entrée de la fonction integrand */ 1158 1159 /* Intégration Monte Carlo */ 1160 res = smc_solve(smc, &integrator, &ctx, &estimator); 1161 if(res != RES_OK) goto error; 1162 @ 1163 1164 En sortie de l'intégration Monte Carlo (fonction [[smc_solve]]) nous disposons 1165 d'un estimateur de nos variables aléatoires, en l'occurrence la sensibilité à 1166 la translation et la fraction de la luminance qui dépend du paramètre {$\PI$}. 1167 Nous pouvons dès lors récupérer l'état de notre estimateur pour afficher 1168 l'espérance et l'écart type de ces variables. 1169 1170 <<Afficher les résultats de l'estimation>>= 1171 res = smc_estimator_get_status(estimator, &status); 1172 if(res != RES_OK) goto error; 1173 1174 sgs_log(sgs, "Sensibilité ~ %g +/- %g\n", 1175 SMC_DOUBLEN(status.E)[0], /* Espérance */ 1176 SMC_DOUBLEN(status.SE)[0]); /* Écart type */ 1177 1178 sgs_log(sgs, "Luminance ~ %g +/- %g\n", 1179 SMC_DOUBLEN(status.E)[1], /* Espérance */ 1180 SMC_DOUBLEN(status.SE)[1]); /* Écart type */ 1181 @ 1182 1183 Ne reste plus qu'à déclarer les variables locales utilisées par notre fonction 1184 de calcul et de libérer en sortie l'espace mémoire allouée dynamiquement pour 1185 ces variables. 1186 1187 <<Variables locales au calcul de sensibilité>>= 1188 /* Système */ 1189 struct smc_device_create_args smc_args = SMC_DEVICE_CREATE_ARGS_DEFAULT; 1190 struct smc_device* smc = NULL; 1191 1192 /* Intégrateur */ 1193 struct smc_integrator integrator = SMC_INTEGRATOR_NULL; 1194 struct smc_doubleN_context ctx = SMC_DOUBLEN_CONTEXT_NULL; 1195 1196 /* Résultat de l'estimatation */ 1197 struct smc_estimator* estimator = NULL; 1198 struct smc_estimator_status status = SMC_ESTIMATOR_STATUS_NULL; 1199 @ 1200 1201 <<Libérer les variables locales au calcul de sensibilité>>= 1202 if(estimator) smc_estimator_ref_put(estimator); 1203 if(smc) smc_device_ref_put(smc); 1204 @ 1205 1206 Le lecteur attentif aura remarqué que l'intégrateur utilise la fonction 1207 [[run_realisation]] et non directement la [[<<Fonction de réalisation>>]] 1208 développée dans ce document (voir [[<<Exécuter l'intégration Monte Carlo>>]]). 1209 [[run_realisation]] est une fonction intermédiaire qui ne fait qu'appeler la 1210 fonction de réalisation. [[run_realisation]] est donc parfaitement dispensable 1211 sauf à la bibliothèque \texttt{Star-MonteCarlo} qui nous impose la signature de 1212 la fonction à utiliser, c'est à dire le type des paramètres d'entrées et de 1213 sorties. En d'autres termes, l'utilisation de cette fonction intermédiaire nous 1214 permet de faciliter l'écriture et la lecture de la fonction de réalisation en 1215 la libérant de contraintes fonctionnelles imposées par 1216 \texttt{Star-MonteCarlo}. 1217 1218 <<Fonctions utilitaires>>= 1219 static res_T 1220 realisation 1221 (struct ssp_rng* rng, 1222 const struct sgs_scene* scene, 1223 double* weight); 1224 1225 static res_T 1226 run_realisation 1227 (void* output, 1228 struct ssp_rng* rng, 1229 const unsigned ithread, 1230 void* ctx) 1231 { 1232 struct smc_doubleN_context* context = NULL; 1233 struct sgs* sgs = NULL; 1234 ASSERT(ctx && output); 1235 (void)ithread; /* Éviter l'avertissement "variable inutilisée" */ 1236 context = ctx; 1237 sgs = context->integrand_data; 1238 return realisation(rng, &sgs->scene, SMC_DOUBLEN(output)); 1239 } 1240 @ 1241 1242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1243 % Annexe structure du C 1244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1245 \section{Structure de mise {\oe}uvre} 1246 1247 Cette partie décrit la structure du fichier C dans lequel l'algorithme de 1248 calcul de sensibilité est mis en oeuvre: 1249 1250 <<sgs\_compute\_sensitivity\_translation.c>>= 1251 <<Liste des inclusions>> 1252 1253 <<Constantes>> 1254 1255 <<Fonctions utilitaires>> 1256 <<Fonction de réalisation>> 1257 <<Calculer la sensibilité à la translation>> 1258 @ 1259 1260 En plus des fonctions de calcul écrites dans les sections précédents, notre 1261 fichier contient des fonctions utilitaires notamment utilisées pour interroger 1262 les propriétés physiques du système (figure~\ref{fig:configuration}) telles que 1263 $\rho$, la réflectivité de la paroi du haut (equation~\ref{eq:rho}), ou $S_b$, 1264 l'émission thermique de la paroi de droite (équation~\ref{eq:S_b}). Le calcul 1265 de leur gradient surfacique, utilisé pour évaluer leur dérivée surfacique 1266 (section~\ref{subsec:poids}), est également ajouté comme fonction utilitaire: 1267 1268 <<Fonctions utilitaires>>= 1269 static double 1270 get_rho 1271 (const struct sgs_scene* scene, 1272 const double pos[2]) 1273 { 1274 ASSERT(scene && pos); 1275 1276 return 0.25 1277 * (1 - cos(2*PI*pos[X]/scene->D[X])) 1278 * (1 - cos(2*PI*pos[Y]/scene->D[Y])); 1279 } 1280 1281 static void 1282 get_grad_rho 1283 (const struct sgs_scene* scene, 1284 const double pos[2], 1285 double grad[2]) 1286 { 1287 ASSERT(scene && pos && grad); 1288 1289 grad[X] = 0.25 1290 * (((2*PI)/scene->D[X])*sin(2*PI*pos[X]/scene->D[X])) 1291 * (1 - cos(2*PI*pos[Y]/scene->D[Y])); 1292 grad[Y] = 0.25 1293 * (((2*PI)/scene->D[Y])*sin(2*PI*pos[Y]/scene->D[Y])) 1294 * (1 - cos(2*PI*pos[X]/scene->D[X])); 1295 } 1296 1297 static double 1298 get_Sb 1299 (const struct sgs_scene* scene, 1300 const double pos[2]) 1301 { 1302 ASSERT(scene && pos); 1303 return 1304 (1 - cos(2*PI*pos[X]/scene->D[Y])) 1305 * (1 - cos(2*PI*pos[Y]/scene->D[Z])); 1306 } 1307 1308 static void 1309 get_grad_Sb 1310 (const struct sgs_scene* scene, 1311 const double pos[2], 1312 double grad[2]) 1313 { 1314 ASSERT(scene && pos && grad); 1315 1316 grad[X] = 1317 (((2*PI)/scene->D[Y])*sin(2*PI*pos[X]/scene->D[Y])) 1318 * (1 - cos(2*PI*pos[Y]/scene->D[Z])); 1319 grad[Y] = 1320 (((2*PI)/scene->D[Z])*sin(2*PI*pos[Y]/scene->D[Z])) 1321 * (1 - cos(2*PI*pos[X]/scene->D[Y])); 1322 } 1323 @ 1324 1325 Autres fonctions utilitaires, les fonctions utilisées lors du suivi des chemins 1326 pour déterminer si un rayon a intersecté le récepteur (fonction 1327 [[hit_receiver]]) ou la source (fonction [[hit_source]]). Pour la source il 1328 suffit de s'assurer que le rayon intersecte le côté droit de la boîte, ici 1329 identifié par la constante [[SGS_SURFACE_X_MAX]]. 1330 1331 <<Fonctions utilitaires>>= 1332 static int 1333 hit_source 1334 (const struct sgs_scene* scene, 1335 const double ray_org[3], 1336 const double ray_dir[3], 1337 const struct sgs_hit* hit) 1338 { 1339 ASSERT(scene && ray_org && ray_dir && hit); 1340 /* Éviter l'avertissement de compilation "variable inutilisée" */ 1341 (void)scene, (void)ray_org, (void)ray_dir; 1342 1343 if(SGS_HIT_NONE(hit) || hit->surface != SGS_SURFACE_X_MAX) { 1344 return 0; 1345 } else { 1346 return 1; /* L'intersection a lieu sur la source */ 1347 } 1348 } 1349 @ 1350 1351 Pour le récepteur on teste d'abord si l'intersection a lieu sur la paroi du 1352 parallélépipède sur laquelle celui-ci est positionné, une paroi identifiée dans 1353 le code par la constante [[SGS_SURFACE_Z_MIN]]. Reste alors à déterminer si 1354 l'intersection se situe sur le récepteur lui même. Pour cela il nous suffit de 1355 tester si la position d'intersection appartient au sous domaine de la surface 1356 sur lequel le récepteur est défini. 1357 1358 <<Fonctions utilitaires>>= 1359 static int 1360 hit_receiver 1361 (const struct sgs_scene* scene, 1362 const double ray_org[3], 1363 const double ray_dir[3], 1364 const struct sgs_hit* hit) 1365 { 1366 double hit_pos[3]; 1367 ASSERT(scene && ray_org && ray_dir && hit); 1368 1369 /* Le rayon n'intersecte pas la surface où le récepteur se trouve */ 1370 if(SGS_HIT_NONE(hit) || hit->surface != SGS_SURFACE_Z_MIN) { 1371 return 0; 1372 } 1373 1374 /* Calculer la position de l'intersection */ 1375 hit_pos[X] = ray_org[X] + hit->distance*ray_dir[X]; 1376 hit_pos[Y] = ray_org[Y] + hit->distance*ray_dir[Y]; 1377 hit_pos[Z] = ray_org[Z] + hit->distance*ray_dir[Z]; 1378 1379 /* Le rayon n'intersecte pas le récepteur*/ 1380 if(hit_pos[X] < scene->recv_min[X] || hit_pos[X] > scene->recv_max[X] 1381 || hit_pos[Y] < scene->recv_min[Y] || hit_pos[Y] > scene->recv_max[Y]) { 1382 return 0; 1383 1384 /* Le rayon intersecte le récepteur*/ 1385 } else { 1386 return 1; 1387 } 1388 } 1389 @ 1390 1391 Dernière fonction utilitaire à écrire, la fonction qui calcule la surface $A_h$ 1392 de la paroi spéculaire: 1393 1394 <<Fonctions utilitaires>>= 1395 static double 1396 get_Sr(const struct sgs_scene* scene) 1397 { 1398 ASSERT(scene); 1399 return scene->D[X] * scene->D[Y]; 1400 } 1401 @ 1402 1403 On complète notre fichier en définissant les constantes [[X]], [[Y]] et [[Z]] 1404 utilisées tout du long pour simplifier la lecture du code lors des accès aux 1405 éléments d'un vecteur. 1406 1407 <<Constantes>>= 1408 enum {X, Y, Z}; 1409 @ 1410 1411 Enfin, on liste en début des sources les fichiers d'en-tête utilisés par notre 1412 code. 1413 1414 <<Liste des inclusions>>= 1415 #include "sgs_c.h" 1416 #include "sgs_geometry.h" 1417 #include "sgs_log.h" 1418 1419 #include <star/smc.h> /* Calcul Monte Carlo */ 1420 #include <star/ssp.h> /* Générateur de nombre aléatoire et distributions */ 1421 1422 /* Manipuler des vecteurs de double à 2 et 3 dimensions */ 1423 #include <rsys/double2.h> 1424 #include <rsys/double3.h> 1425 @ 1426 1427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1428 % Annexe script de résultat 1429 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1430 \section{Script d'exécution du calcul et résultats} 1431 \label{annex:scripts} 1432 1433 Nous écrivons ici les scripts \textit{shell} qui calculent la sensibilité du 1434 flux à $\PI$ d'abord par Monte Carlo puis par différences finies en vue d'une 1435 validation croisée des résulats. Le premier script [[<<mc.sh>>]] lance 1436 plusieurs fois le programme dont le présent document décrit la fonction de 1437 réalisation; l'objet étant de calculer à différentes valeurs de $\PI$ la 1438 sensibilité du flux $\varphi$ reçu par le capteur (équation~\ref{eq:flux}) 1439 ainsi que la fraction de ce même flux qui dépend de $\PI$ 1440 (annexe~\ref{annex:flux}). 1441 1442 <<mc.sh>>= 1443 #!/bin/sh -e 1444 1445 # Estimation par Monte Carlo de la sensibilité et de la fraction du 1446 # flux qui dépend de pi 1447 1448 <<Configuration géométrique>> 1449 <<Paramètres des calculs Monte Carlo>> 1450 1451 <<Pour différentes valeurs de $\PI$>> 1452 do 1453 <<Lancer un calcul Monte Carlo>> 1454 <<Post traiter le résultat>> 1455 <<Passer à la valeur de $\PI$ suivante>> 1456 done 1457 @ 1458 1459 Chaque calcul Monte Carlo se résume à exécuter ledit programme nommé [[sgs]] 1460 (acronyme de \textit{Star Geometric Sensitivity}) pour une valeur de $\PI$ 1461 considérée. On notera que la configuration géométrique décrite en 1462 figure~\ref{fig:configuration} est indépendante de ses dimensions réelles. Dans 1463 notre script ces dimensions sont fixées via deux variables qui définissent le 1464 coin inférieur ([[lower]]) et le coin supérieur ([[upper]]) d'un parallélépipède 1465 aligné aux axes, deux variables passées en arguments du programme via l'option 1466 [[-b]]. 1467 1468 <<Lancer un calcul Monte Carlo>>= 1469 out=$(./sgs \ 1470 -n "${nrealisations}" \ 1471 -b low="${lower}":upp="${upper}":pi="${pi}") 1472 @ 1473 1474 avec [[nrealisations]] le nombre de réalisations utilisées par le calcul Monte 1475 Carlo. Si ce document décrit en détail les sources C de sa 1476 [[<<Fonction de réalisation>>]], nous renvoyons le lecteur vers les autres 1477 fichiers C et l'aide du programme [[sgs]] (affichée via l'option [[-h]]) pour 1478 plus d'informations quant aux fonctionnement et options du programme. 1479 1480 Une fois le calcul terminé, en post-traiter le résultat se résume à afficher 1481 sur la sortie standard la valeur de $\PI$ courante suivie de l'estimation et de 1482 l'écart type de la sensibilité et du flux que nous venons d'estimer. Ci-après 1483 nous utilisons la commande [[sed]] pour extraire et afficher ces valeurs 1484 stockées dans la variable [[out]] à l'issu de notre calcul Monte Carlo. 1485 1486 <<Post traiter le résultat>>= 1487 prompt="[^~]\{1,\}~ " 1488 estimation="[^[:blank:]]\{1,\}" 1489 error="[^\n$]\{1,\}" 1490 line0="${prompt}\(${estimation}\) +/- \(${error}\)\n" # Sensibilité 1491 line1="${prompt}\(${estimation}\) +/- \(${error}\)$" # Flux 1492 printf "%s " "${pi}" 1493 echo "${out}" | sed -n "1{N;s#^${line0}${line1}#\1 \2 \3 \4#p}" 1494 @ 1495 1496 Ces deux étapes, à savoir le calcul Monte Carlo et son post-traitement, sont 1497 lancées [[nsteps]] fois pour différentes valeurs de $\PI$, la valeur de $\PI$ à 1498 chaque itération étant simplement sa valeur précédente incrémentée d'un pas 1499 constant égal à [[pi_step]]. 1500 1501 <<Pour différentes valeurs de $\PI$>>= 1502 i=0 1503 pi=0 1504 while [ "${i}" -lt "${nsteps}" ] 1505 @ 1506 <<Passer à la valeur de $\PI$ suivante>>= 1507 i=$((i + 1)) 1508 pi=$(printf "%s + %s\n" "${pi}" "${pi_step}" | bc) 1509 @ 1510 1511 Pour compléter le script, ne reste plus qu'à définir les variables qui 1512 caractérisent notre configuration géométrique ainsi que les paramètres qui 1513 pilotent nos différents calculs, tels que le nombre de calculs à lancer ou 1514 encore le nombre de réalisations par calcul. 1515 1516 <<Configuration géométrique>>= 1517 h=1 # Hauteur du parallélépipède 1518 lower="0,0,0" 1519 upper="1,1,${h}" 1520 @ 1521 <<Paramètres des calculs Monte Carlo>>= 1522 nrealisations=100000000 1523 nsteps=14 1524 pi_step=0.1 1525 @ 1526 1527 Dans un nouveau script [[fd.sh]] nous pouvons alors calculer par différences 1528 finies la sensibilité du flux à $\PI$ à partir des estimations Monte Carlo en 1529 sortie de [[<<mc.sh>>]], des résultats lus via l'entrée standard. Pour pouvoir 1530 comparer les résultats, ce second script recopie en sortie les sensibilités 1531 estimées par Monte Carlo ([[sen_mc]]) en plus d'écrire ces mêmes sensibilités 1532 calculées cette fois par différences finies ([[sen_fd]]). Leur écarts types 1533 respectif ([[err_mc]] et [[err_fd]]) sont également des données de sortie. On 1534 notera enfin que l'ensemble des résultats sont adimentionnalisés et sont par 1535 conséquent donnés pour une valeur de $\PI$ indépendante de la hauteur du 1536 parallélépipède ([[pi_over_h]]). 1537 1538 <<fd.sh>>= 1539 #!/bin/sh -e 1540 1541 # Calcule la sensibilité par différences finies à partir des 1542 # estimations par Monte Carlo de la fraction du flux qui dépend de pi 1543 1544 # Liste des données pour chaque ligne écrite en sortie 1545 printf "pi_over_h sen_mc err_mc sen_fd err_fd\n" 1546 1547 <<Fonctions utilitaires à [[fd.sh]]>> 1548 1549 <<Lire les paramètres d'entrée>> 1550 1551 <<Pour chaque valeur de $\PI$ considérée>> 1552 do 1553 <<Lire la valeur du flux autour de $\PI$>> 1554 <<Calculer par différences finies la sensibilité du flux à $\PI$>> 1555 <<Lire l'estimation Monte Carlo de la sensibilité du flux à $\PI$>> 1556 <<Écrire les résultats adimensionnaliser>> 1557 <<Passer au calcul suivant>> 1558 done 1559 @ 1560 1561 Pour les calculs en différences finies nous avons besoin de connaître les 1562 paramètres utilisés par les estimations Monte Carlo, comme le $\delta$ entre 1563 chaque valeur de $\PI$ ([[pi_step]]) ou encore la hauteur du parallélépipède 1564 nécessaire pour adimensionnaliser les résultats ([[h]]). Pour passer ces 1565 données d'un script à l'autre, on ajoute aux sorties de [[mc.sh]] un en-tête 1566 contenant ces paramètres, en-tête qui peut alors être lu par le script 1567 [[fd.sh]]. 1568 1569 <<Paramètres des calculs Monte Carlo>>= 1570 printf "%s %s\n" "${h}" "${pi_step}" 1571 @ 1572 <<Lire les paramètres d'entrée>>= 1573 read -r header 1574 h=$(echo "${header}" | cut -d' ' -f1) 1575 pi_step=$(echo "${header}" | cut -d' ' -f2) 1576 @ 1577 1578 Autre donnée nécessaire par l'adimensionnement, la valeur maximale du flux. 1579 Celle-ci correspond à la valeur de $\varphi$ lorsque la boîte est fermée, c'est 1580 à dire lorsque $\PI$ vaut $0$, soit la valeur de $\PI$ du premier calcul Monte 1581 Carlo lancé par [[mc.sh]]. Après avoir lu l'en-tête de ses sorties nous lisons 1582 donc ce premier résultat que l'on stocke dans la variable [[p]] avant d'en 1583 extraire la valeur $\varphi$ ([[phi_max]]). 1584 1585 <<Lire les paramètres d'entrée>>= 1586 read -r p 1587 phi_max=$(echo "${p}" | cut -d' ' -f4 | float_to_bc) 1588 @ 1589 1590 La boucle principale du script consiste à lire l'entrée standard jusqu'à ce 1591 qu'il n'y ait plus de résultat Monte Carlo à traiter. À chaque itération, le 1592 résultat Monte Carlo pour la valeur de $\PI$ courante est stocké dans la 1593 variable [[c]] tandis que le résultat précédent et suivant sont respectivement 1594 stockés dans les variables [[p]] et [[n]]. 1595 1596 <<Pour chaque valeur de $\PI$ considérée>>= 1597 read -r c 1598 while read -r n 1599 @ 1600 <<Passer au calcul suivant>>= 1601 p="${c}" 1602 c="${n}" 1603 @ 1604 1605 Il suffit alors d'extraire le flux ([[phi]]) et son erreur ([[err]]) aux 1606 valeurs de $\PI$ précédente ([[p]]) et suivante ([[n]]) pour calculer par 1607 différences finies la sensibilité et l'erreur associée pour la valeur de $\PI$ 1608 courante: 1609 1610 <<Lire la valeur du flux autour de $\PI$>>= 1611 phi_p=$(echo "${p}" | cut -d' ' -f4 | float_to_bc) 1612 err_p=$(echo "${p}" | cut -d' ' -f5 | float_to_bc) 1613 phi_n=$(echo "${n}" | cut -d' ' -f4 | float_to_bc) 1614 err_n=$(echo "${n}" | cut -d' ' -f5 | float_to_bc) 1615 @ 1616 <<Calculer par différences finies la sensibilité du flux à $\PI$>>= 1617 sen_fd=$(echo "(${phi_n}-${phi_p})/(2*${pi_step})" | bc_cmd) 1618 err_fd=$(echo "(${err_n}+${err_p})/(2*${pi_step})" | bc_cmd) 1619 @ 1620 1621 On utilise alors le résultat Monte Carlo au $\PI$ considéré pour retrouver non 1622 seulement la valeur de $\PI$ mais aussi pour extraire l'estimation Monte Carlo 1623 de la sensibilité de $\varphi$ à $\PI$: 1624 1625 <<Lire l'estimation Monte Carlo de la sensibilité du flux à $\PI$>>= 1626 pi=$(echo "${c}" | cut -d' ' -f1 | float_to_bc) 1627 sen_mc=$(echo "${c}" | cut -d' ' -f2 | float_to_bc) 1628 err_mc=$(echo "${c}" | cut -d' ' -f3 | float_to_bc) 1629 @ 1630 1631 Ne reste plus qu'à écrire l'ensemble des résultats attendus: 1632 1633 <<Écrire les résultats adimensionnaliser>>= 1634 pi_over_h=$(echo "${pi}/${h}" | bc_cmd) 1635 sen_mc=$(echo "${sen_mc}/${phi_max}*${h}" | bc_cmd) 1636 err_mc=$(echo "${err_mc}/${phi_max}*${h}" | bc_cmd) 1637 sen_fd=$(echo "${sen_fd}/${phi_max}*${h}" | bc_cmd) 1638 err_fd=$(echo "${err_fd}/${phi_max}*${h}" | bc_cmd) 1639 printf "%s %s %s %s %s\n" \ 1640 "${pi_over_h}" "${sen_mc}" "${err_mc}" "${sen_fd}" "${err_fd}" 1641 @ 1642 1643 On complète finalement notre script par les fonctions utilitaires utilisées 1644 tout du long, à savoir la fonction [[float_to_bc]] qui convertie un nombre à 1645 virgule flottante dans le format attendu par le programme \texttt{bc}, et la 1646 fonction [[bc_cmd]] qui exécute le programme \texttt{bc} et en post-traite le 1647 résultat pour supprimer les zéros qui suivent le dernier chiffre significatif. 1648 1649 <<Fonctions utilitaires à [[fd.sh]]>>= 1650 float_to_bc() 1651 { 1652 sed 's/\([+-]\{0,1\}[0-9]\{0,\}\.\{0,1\}[0-9]\{1,\}\)'\ 1653 '[eE]+\{0,1\}\(-\{0,1\}\)\([0-9]\{1,\}\)/(\1*10^\2\3)/g' 1654 } 1655 1656 bc_cmd() 1657 { 1658 bc -l | sed '/\./s/\.\{0,\}0\{1,\}$//' 1659 } 1660 @ 1661 1662 \bibliographystyle{apalike} 1663 \bibliography{biblio} 1664 1665 \end{document} 1666 \nwfilename{test}