star-gs

Literate program for a geometric sensitivity calculation
git clone git://git.meso-star.fr/star-gs.git
Log | Files | Refs | README | LICENSE

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}