<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Aérodynamique | Valentin Caries</title><link>https://vcaries.github.io/tag/aerodynamique/</link><atom:link href="https://vcaries.github.io/tag/aerodynamique/index.xml" rel="self" type="application/rss+xml"/><description>Aérodynamique</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>fr-fr</language><lastBuildDate>Fri, 12 Jun 2026 00:00:00 +0000</lastBuildDate><image><url>https://vcaries.github.io/media/icon_hu536d0651d21529ac336731b24f3e073f_144279_512x512_fill_lanczos_center_3.png</url><title>Aérodynamique</title><link>https://vcaries.github.io/tag/aerodynamique/</link></image><item><title>Web-LBM : une soufflerie CFD temps réel dans le navigateur</title><link>https://vcaries.github.io/project/web-lbm/</link><pubDate>Fri, 12 Jun 2026 00:00:00 +0000</pubDate><guid>https://vcaries.github.io/project/web-lbm/</guid><description>&lt;h2 id="en-une-minute">En une minute&lt;/h2>
&lt;p>&lt;strong>Web-LBM&lt;/strong> est une soufflerie numérique bidimensionnelle interactive qui s&amp;rsquo;exécute entièrement dans votre navigateur. Derrière le canvas se trouve un véritable solveur de &lt;strong>mécanique des fluides numérique (CFD)&lt;/strong> : un moteur &lt;strong>Boltzmann sur réseau (D2Q9)&lt;/strong> écrit en C, compilé en &lt;strong>WebAssembly&lt;/strong> et rendu sur le GPU via &lt;strong>WebGL2&lt;/strong>. On peut y déposer un cylindre ou un profil NACA, changer l&amp;rsquo;angle d&amp;rsquo;attaque, mettre un obstacle en rotation pour ressentir l&amp;rsquo;effet Magnus, ou peindre sa propre géométrie à la souris et observer la réponse du sillage. Les coefficients de portance et de traînée s&amp;rsquo;actualisent en direct, et des microphones virtuels permettent même de &lt;em>voir le son&lt;/em> du lâcher tourbillonnaire.&lt;/p>
&lt;p>La CFD vit d&amp;rsquo;ordinaire sur des clusters et des calculs de nuit. L&amp;rsquo;amener dans un onglet de navigateur, sans installation, sans serveur, sans framework, et hébergée en simples fichiers statiques sur GitHub Pages, est à la fois un parti pris pédagogique et un exercice d&amp;rsquo;ingénierie. Chaque contrainte de la plateforme a dû être résolue sans sacrifier ni la fidélité physique ni l&amp;rsquo;interactivité : pas de mémoire partagée par défaut, pas de système de fichiers, et un seul thread sauf à le mériter.&lt;/p>
&lt;p>👉 &lt;strong>&lt;a href="https://vcaries.github.io/web_lbm/" target="_blank" rel="noopener">Essayer la simulation&lt;/a>&lt;/strong> · &lt;strong>&lt;a href="https://github.com/vcaries/web_lbm" target="_blank" rel="noopener">Code source sur GitHub&lt;/a>&lt;/strong>&lt;/p>
&lt;h3 id="points-clés">Points clés&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Un vrai solveur.&lt;/strong> Boltzmann sur réseau D2Q9 avec collision BGK (ou MRT à la compilation), un modèle de turbulence &lt;strong>LES de Smagorinsky&lt;/strong>, une collision régularisée de Hermite pour la stabilité, une entrée en vitesse de Zou–He, des couches éponges absorbantes et une évaluation des efforts par échange de quantité de mouvement qui produit des $C_l$ et $C_d$ en direct.&lt;/li>
&lt;li>&lt;strong>Des performances temps réel.&lt;/strong> Une boucle chaude sans branchement et vectorisée SIMD, associée à des &lt;strong>threads WebAssembly&lt;/strong> (pthreads sur &lt;code>SharedArrayBuffer&lt;/code>) et à un partitionnement par lignes déterministe et sans verrou.&lt;/li>
&lt;li>&lt;strong>Un rendu sans copie.&lt;/strong> Les champs voyagent du tas wasm jusqu&amp;rsquo;à l&amp;rsquo;écran sans la moindre copie intermédiaire : des vues typées alimentent une texture WebGL2 &lt;code>R32F&lt;/code>, et une table de couleurs est appliquée dans le fragment shader.&lt;/li>
&lt;li>&lt;strong>L&amp;rsquo;aéroacoustique en prime.&lt;/strong> La LBM étant faiblement compressible, le moteur résout les ondes acoustiques. Il propose des vues schlieren ($|\nabla\rho|$) et dilatation ($\nabla\cdot\mathbf{u}$), plus des microphones virtuels avec FFT en direct qui captent le sifflement éolien du sillage.&lt;/li>
&lt;li>&lt;strong>Un déploiement 100 % statique.&lt;/strong> Deux variantes du moteur (mono- et multi-thread) sont sélectionnées à l&amp;rsquo;exécution, et un service worker fournit les en-têtes d&amp;rsquo;isolation cross-origin que GitHub Pages ne peut pas envoyer.&lt;/li>
&lt;/ul>
&lt;h2 id="pourquoi-la-cfd-dans-le-navigateur-">Pourquoi la CFD dans le navigateur ?&lt;/h2>
&lt;p>Trois raisons, par ordre de difficulté croissante.&lt;/p>
&lt;p>&lt;strong>La pédagogie.&lt;/strong> La mécanique des fluides s&amp;rsquo;enseigne avec des équations et se valide avec des simulations coûteuses, mais &lt;em>l&amp;rsquo;intuition&lt;/em> naît du lien immédiat entre cause et effet : inclinez un profil et observez le décrochage, faites tourner un cylindre et regardez la portance apparaître. Une simulation interactive dont la boucle de rétroaction se mesure en millisecondes est un outil d&amp;rsquo;apprentissage fondamentalement différent d&amp;rsquo;une figure statique.&lt;/p>
&lt;p>&lt;strong>L&amp;rsquo;accessibilité.&lt;/strong> Une page web sans installation ni backend touche tout le monde (étudiants, collègues, recruteurs) sur n&amp;rsquo;importe quelle machine, indéfiniment, pour un coût d&amp;rsquo;hébergement nul. Cela impose que tout le solveur tourne côté client, exactement ce que WebAssembly rend possible.&lt;/p>
&lt;p>&lt;strong>Le défi d&amp;rsquo;ingénierie.&lt;/strong> La CFD temps réel met toute la pile à l&amp;rsquo;épreuve d&amp;rsquo;un seul coup : une méthode numérique assez stable pour survivre à tout ce que l&amp;rsquo;utilisateur lui impose, une organisation mémoire que le compilateur sait vectoriser, un modèle de threading compatible avec les contraintes de sécurité du navigateur et un chemin de rendu assez rapide pour ne jamais devenir le goulot d&amp;rsquo;étranglement. Résoudre les quatre à la fois est le cœur de ce projet.&lt;/p>
&lt;h2 id="la-physique--boltzmann-sur-réseau-en-bref">La physique : Boltzmann sur réseau en bref&lt;/h2>
&lt;h3 id="un-autre-chemin-vers-la-dynamique-des-fluides">Un autre chemin vers la dynamique des fluides&lt;/h3>
&lt;p>La CFD classique discrétise directement les &lt;strong>équations de Navier–Stokes&lt;/strong> : vitesse et pression vivent sur un maillage, et chaque pas de temps exige la résolution de systèmes couplés &lt;em>globaux&lt;/em>, typiquement une équation de Poisson pour la pression, dont la solution relie chaque cellule du domaine à toutes les autres.&lt;/p>
&lt;p>La &lt;strong>méthode de Boltzmann sur réseau (LBM)&lt;/strong> travaille un niveau en dessous de la description macroscopique. Elle fait évoluer des &lt;strong>fonctions de distribution de particules&lt;/strong> $f_i(\mathbf{x}, t)$, la quantité de fluide au nœud $\mathbf{x}$ se déplaçant le long d&amp;rsquo;un petit ensemble de vitesses discrètes $\mathbf{c}_i$. Les champs macroscopiques sont simplement les moments de ces distributions :&lt;/p>
$$\rho = \sum_i f_i, \qquad \rho\,\mathbf{u} = \sum_i f_i\,\mathbf{c}_i$$
&lt;p>Un développement de Chapman–Enskog montre que ce système cinétique reproduit les équations de Navier–Stokes incompressibles dans la limite des faibles nombres de Mach. La viscosité du fluide est pilotée par un unique temps de relaxation $\tau$ :&lt;/p>
$$\nu = c_s^2\left(\tau - \tfrac{1}{2}\right)$$
&lt;p>Ce qui rend la LBM exceptionnelle pour ce projet, c&amp;rsquo;est sa &lt;strong>localité&lt;/strong> : chaque nœud ne se met à jour qu&amp;rsquo;à partir de ses voisins immédiats. Pas de résolution globale, pas d&amp;rsquo;algèbre linéaire, pas de boucle de convergence. Le coût par pas de temps est donc fixe et prévisible, l&amp;rsquo;algorithme se parallélise presque trivialement, et la simulation est &lt;em>naturellement instationnaire&lt;/em>. Le lâcher tourbillonnaire n&amp;rsquo;est pas une option que l&amp;rsquo;on active ; c&amp;rsquo;est ce que la méthode calcule par défaut. En bonus, la LBM est faiblement compressible : les ondes de pression se propagent physiquement, et la simulation fait de l&amp;rsquo;acoustique gratuitement.&lt;/p>
&lt;h3 id="collision-et-propagation">Collision et propagation&lt;/h3>
&lt;p>Chaque pas de temps se ramène à deux opérations conceptuellement simples. La &lt;strong>collision&lt;/strong> relaxe les distributions vers un équilibre local (approximation BGK) :&lt;/p>
$$f_i(\mathbf{x}, t^{+}) = f_i(\mathbf{x}, t) - \frac{1}{\tau}\left[f_i(\mathbf{x}, t) - f_i^{\mathrm{eq}}(\rho, \mathbf{u})\right]$$
&lt;p>où l&amp;rsquo;équilibre est un développement au second ordre de la distribution de Maxwell–Boltzmann :&lt;/p>
$$f_i^{\mathrm{eq}} = w_i\,\rho\left[1 + \frac{\mathbf{c}_i\cdot\mathbf{u}}{c_s^2} + \frac{(\mathbf{c}_i\cdot\mathbf{u})^2}{2c_s^4} - \frac{\mathbf{u}\cdot\mathbf{u}}{2c_s^2}\right]$$
&lt;p>La &lt;strong>propagation&lt;/strong> (&lt;em>streaming&lt;/em>) décale ensuite chaque distribution post-collision vers le nœud voisin dans sa direction de déplacement :&lt;/p>
$$f_i(\mathbf{x} + \mathbf{c}_i\,\Delta t,\; t + \Delta t) = f_i(\mathbf{x}, t^{+})$$
&lt;p>La collision est de l&amp;rsquo;arithmétique purement locale ; la propagation, un pur déplacement mémoire. Du calcul intensif sans communication, suivi de la communication sans calcul, est exactement la structure qu&amp;rsquo;adorent les unités SIMD et les processeurs multicœurs, et l&amp;rsquo;implémentation décrite plus bas l&amp;rsquo;exploite délibérément.&lt;/p>
&lt;h3 id="pourquoi-d2q9">Pourquoi D2Q9&lt;/h3>
&lt;p>Le moteur utilise le réseau &lt;strong>D2Q9&lt;/strong> : deux dimensions et neuf vitesses (repos, quatre axiales, quatre diagonales) avec les poids $w_0 = 4/9$, $w_{1\text{–}4} = 1/9$ et $w_{5\text{–}8} = 1/36$. C&amp;rsquo;est le plus petit réseau 2D dont les moments de vitesse sont suffisamment isotropes pour retrouver correctement Navier–Stokes. Moins de directions biaiseraient la physique le long des axes de la grille, et davantage coûteraient mémoire et bande passante sans gain à ce niveau de description. Neuf champs &lt;code>float&lt;/code> par nœud fixent aussi le budget mémoire : une grille 600 × 300 tient confortablement dans quelques dizaines de mégaoctets de tas wasm.&lt;/p>
&lt;h3 id="conditions-aux-limites">Conditions aux limites&lt;/h3>
&lt;p>Les frontières sont l&amp;rsquo;endroit où une implémentation LBM fait ses preuves, car après la propagation les distributions entrant dans le domaine depuis l&amp;rsquo;extérieur sont inconnues et doivent être reconstruites.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Entrée.&lt;/strong> Une condition en vitesse de &lt;strong>Zou–He&lt;/strong> impose le profil d&amp;rsquo;entrée (uniforme, couche cisaillée ou jet) en reconstruisant les distributions inconnues à partir des contraintes de masse et de quantité de mouvement. Un démarrage progressif sur 400 pas accompagne chaque (ré)initialisation, pour que le démarrage impulsif ne lance pas une onde de choc dans la veine.&lt;/li>
&lt;li>&lt;strong>Sortie.&lt;/strong> Une extrapolation à gradient nul, adossée à une &lt;strong>couche éponge absorbante&lt;/strong> qui augmente progressivement la dissipation près de la frontière, pour que tourbillons et ondes acoustiques quittent le domaine au lieu de s&amp;rsquo;y réfléchir.&lt;/li>
&lt;li>&lt;strong>Obstacles.&lt;/strong> Le &lt;strong>rebond (&lt;em>bounce-back&lt;/em>)&lt;/strong> renvoie d&amp;rsquo;où elles viennent les distributions qui frappent un nœud solide, produisant une paroi adhérente sans aucun maillage. Sa variante à &lt;strong>paroi mobile&lt;/strong> ajoute la quantité de mouvement de la paroi aux populations réfléchies, ce qui constitue toute l&amp;rsquo;implémentation du cylindre tournant, l&amp;rsquo;effet Magnus découlant alors de la physique. La somme des quantités de mouvement échangées dans ces réflexions donne l&amp;rsquo;effort aérodynamique sur chaque corps (les $C_l$ et $C_d$ affichés en direct) pour un coût quasi nul.&lt;/li>
&lt;li>&lt;strong>Parois de la veine.&lt;/strong> Au choix : glissement libre (réflexion spéculaire) ou adhérence (rebond).&lt;/li>
&lt;/ul>
&lt;h2 id="mise-en-œuvre">Mise en œuvre&lt;/h2>
&lt;h3 id="architecture">Architecture&lt;/h3>
&lt;p>Le projet se compose de deux parties proprement séparées, reliées par un unique tampon mémoire partagé :&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">Moteur C (lbm.c, C99) --emcc--&amp;gt; WebAssembly + tas wasm
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ vues Float32Array sans copie
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Frontend ES6 vanilla ── textures WebGL2 R32F ──&amp;gt; LUT de couleurs dans le shader
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;ul>
&lt;li>&lt;strong>Le moteur&lt;/strong> est un unique fichier C99 réunissant le solveur D2Q9, la LES, les conditions aux limites, les rastériseurs analytiques de formes (cylindre, plaque plane, NACA 0012 / 4412), l&amp;rsquo;évaluation des efforts et le calcul des champs dérivés (vitesse, pression, vorticité, schlieren, dilatation). Il expose une petite API C plate (&lt;code>lbm_init&lt;/code>, &lt;code>lbm_step&lt;/code>, &lt;code>lbm_set_params&lt;/code>, …) et ignore tout de JavaScript.&lt;/li>
&lt;li>&lt;strong>Le frontend&lt;/strong> est en modules ES6 vanilla, sans framework, sans bundler et sans aucune étape de build au-delà d&amp;rsquo;&lt;code>emcc&lt;/code> lui-même. &lt;code>main.js&lt;/code> pilote la boucle de simulation et l&amp;rsquo;interface, &lt;code>renderer.js&lt;/code> possède WebGL2, et &lt;code>obstacles.js&lt;/code> définit les formes analytiques.&lt;/li>
&lt;li>&lt;strong>Deux variantes du moteur&lt;/strong> sont produites à partir de la même source : une version mono-thread qui fonctionne partout, et une version &lt;code>-pthread&lt;/code> utilisant les threads WebAssembly. L&amp;rsquo;application détecte &lt;code>crossOriginIsolated&lt;/code> au démarrage, choisit la meilleure, et assure un repli transparent.&lt;/li>
&lt;/ul>
&lt;h3 id="le-chemin-de-données-sans-copie">Le chemin de données sans copie&lt;/h3>
&lt;p>La règle cardinale du pipeline de rendu : &lt;strong>les champs ne sont jamais copiés côté JavaScript&lt;/strong>. Le moteur C calcule par exemple la vorticité dans un tableau &lt;code>float&lt;/code> du tas wasm. JavaScript enveloppe cette mémoire dans une &lt;em>vue&lt;/em> &lt;code>Float32Array&lt;/code> (aucune allocation, aucune copie) et la passe directement à &lt;code>texSubImage2D&lt;/code>, qui la téléverse dans une texture flottante mono-canal (&lt;code>R32F&lt;/code>). Le fragment shader fait ensuite correspondre les valeurs aux couleurs via une petite texture de table de correspondance, si bien que tout l&amp;rsquo;habillage visuel coûte une lecture de texture par pixel et vit sur le GPU.&lt;/p>
&lt;p>Deux subtilités maintiennent cette promesse. Quand le tas wasm grandit (l&amp;rsquo;utilisateur choisit une grille plus fine), l&amp;rsquo;&lt;code>ArrayBuffer&lt;/code> sous-jacent se détache et chaque vue doit être reconstruite, ce que l&amp;rsquo;application fait paresseusement, à la demande. Et dans la version multithread, le tas est un &lt;code>SharedArrayBuffer&lt;/code>, que certains navigateurs refusent de téléverser directement ; un unique petit tampon de transit constitue la seule exception sanctionnée à la règle du zéro copie.&lt;/p>
&lt;h3 id="du-multithreading-dans-un-navigateur">Du multithreading dans un navigateur&lt;/h3>
&lt;p>Le balayage intérieur est &lt;strong>partitionné par lignes&lt;/strong> sur un pool de pthreads wasm, avec des barrières séparant les phases de chaque pas de temps. Le partitionnement garantit que chaque case du tableau de destination a &lt;em>exactement un&lt;/em> producteur. Les threads ne sont jamais en concurrence, donc ni verrous ni atomiques dans le chemin chaud. Les contributions aux efforts sont réduites dans un ordre de threads fixe, ce qui rend les résultats &lt;strong>déterministes au bit près à nombre de threads donné&lt;/strong>, une exigence empruntée aux bonnes pratiques du HPC, où « rapide mais légèrement différent à chaque exécution » est la cachette préférée des bugs.&lt;/p>
&lt;p>Le threading en navigateur a un piège : &lt;code>SharedArrayBuffer&lt;/code> exige que la page soit &lt;strong>isolée cross-origin&lt;/strong>, ce qui requiert des en-têtes HTTP COOP/COEP qu&amp;rsquo;un hébergeur statique comme GitHub Pages ne peut pas envoyer. Web-LBM résout cela avec un &lt;strong>service worker&lt;/strong> de portée racine qui injecte les en-têtes côté client (un rechargement automatique à la première visite). Si quoi que ce soit échoue dans cette chaîne (navigateur ancien, isolation partielle), l&amp;rsquo;application démarre silencieusement le moteur mono-thread. C&amp;rsquo;est l&amp;rsquo;amélioration progressive appliquée au HPC.&lt;/p>
&lt;h3 id="interaction">Interaction&lt;/h3>
&lt;p>Tout, dans la soufflerie, se manipule pendant que la simulation tourne. Les obstacles se placent au clic, pivotent, tournent sur eux-mêmes (cylindres en rotation) ou se &lt;strong>peignent à main levée&lt;/strong> à la souris, directement dans le masque d&amp;rsquo;obstacles. Les cellules peintes sont rééchantillonnées quand la résolution de grille change, tandis que les formes prédéfinies sont re-rastérisées &lt;em>analytiquement&lt;/em> depuis leur registre, si bien qu&amp;rsquo;un profil NACA reste un profil NACA net à n&amp;rsquo;importe quelle résolution. L&amp;rsquo;écoulement se visualise en vitesse, pression, vorticité, schlieren ou dilatation, avec des surcouches de lignes de courant et de particules. Des &lt;strong>microphones virtuels&lt;/strong> se déposent n&amp;rsquo;importe où dans le champ pour tracer la FFT en direct du signal de pression local ; en placer un derrière un cylindre révèle le pic spectral net de la fréquence de lâcher, la même physique que le sifflement du vent dans les fils.&lt;/p>
&lt;h2 id="défis-dingénierie">Défis d&amp;rsquo;ingénierie&lt;/h2>
&lt;h3 id="la-stabilité-numérique-sans-arbitre">La stabilité numérique sans arbitre&lt;/h3>
&lt;p>Une simulation interactive ne peut pas refuser les entrées de l&amp;rsquo;utilisateur : quels que soient le nombre de Reynolds, la forme d&amp;rsquo;obstacle ou la résolution choisis, le solveur ne doit pas diverger. Le BGK brut devient instable quand $\tau \to 1/2$ (hauts nombres de Reynolds) ; le moteur superpose donc plusieurs défenses, chacune visant un mode de défaillance distinct.&lt;/p>
&lt;ul>
&lt;li>Un &lt;strong>modèle LES de Smagorinsky&lt;/strong> ($C_s = 0{,}18$) calcule une viscosité turbulente locale à partir du taux de déformation (obtenu en LBM directement depuis les distributions hors équilibre, sans différences finies). Il modélise à la fois les échelles turbulentes non résolues et éloigne le $\tau$ effectif de la limite instable précisément là où l&amp;rsquo;écoulement est le plus cisaillé.&lt;/li>
&lt;li>La &lt;strong>régularisation de Hermite&lt;/strong> projette la partie hors équilibre des distributions sur sa composante physiquement signifiante (Hermite d&amp;rsquo;ordre deux) avant la collision, filtrant les modes parasites d&amp;rsquo;ordre supérieur qui, sinon, s&amp;rsquo;accumulent et déstabilisent les grilles grossières.&lt;/li>
&lt;li>Un &lt;strong>amortissement de viscosité de volume&lt;/strong> dissipe sélectivement la partie acoustique du tenseur des contraintes, calmant les oscillations de pression sans toucher à la physique du cisaillement qui crée les tourbillons.&lt;/li>
&lt;li>Les &lt;strong>couches éponges et le démarrage progressif de l&amp;rsquo;entrée&lt;/strong> éliminent les deux transitoires classiques : les ondes réfléchies en sortie et l&amp;rsquo;impulsion initiale.&lt;/li>
&lt;/ul>
&lt;p>Le résultat est une soufflerie qui survit aux mauvais traitements, ce qui fait la différence entre une démo et un produit.&lt;/p>
&lt;h2 id="ce-que-vous-pouvez-explorer">Ce que vous pouvez explorer&lt;/h2>
&lt;p>Quelques expériences d&amp;rsquo;une minute chacune dans la &lt;a href="https://vcaries.github.io/web_lbm/" target="_blank" rel="noopener">soufflerie en ligne&lt;/a> :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Le lâcher tourbillonnaire.&lt;/strong> Gardez le cylindre par défaut, passez en vue vorticité et regardez l&amp;rsquo;allée de von Kármán s&amp;rsquo;établir ; le HUD montre $C_l$ oscillant à la fréquence de lâcher.&lt;/li>
&lt;li>&lt;strong>Le décrochage.&lt;/strong> Placez un profil NACA 4412 et augmentez l&amp;rsquo;angle d&amp;rsquo;attaque : le coefficient de portance grimpe, puis l&amp;rsquo;écoulement décolle à l&amp;rsquo;extrados.&lt;/li>
&lt;li>&lt;strong>L&amp;rsquo;effet Magnus.&lt;/strong> Faites tourner un cylindre et observez le sillage dévier et une portance stationnaire apparaître, la physique des coups francs enroulés.&lt;/li>
&lt;li>&lt;strong>L&amp;rsquo;aéroacoustique.&lt;/strong> Passez en vue schlieren ou dilatation pour voir les ondes de pression rayonner depuis le sillage, puis déposez un microphone derrière le cylindre et retrouvez le ton de lâcher dans le spectre en direct.&lt;/li>
&lt;li>&lt;strong>Votre propre géométrie.&lt;/strong> Peignez un obstacle arbitraire à la souris et regardez l&amp;rsquo;écoulement composer avec.&lt;/li>
&lt;/ol>
&lt;h2 id="compétences-démontrées">Compétences démontrées&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Mécanique des fluides numérique :&lt;/strong> la méthode de Boltzmann sur réseau de bout en bout, incluant le choix du réseau, les modèles de collision (BGK, MRT, régularisation), les conditions aux limites, la modélisation de la turbulence (LES de Smagorinsky), l&amp;rsquo;évaluation des efforts et l&amp;rsquo;aéroacoustique.&lt;/li>
&lt;li>&lt;strong>Méthodes numériques et calcul scientifique :&lt;/strong> l&amp;rsquo;analyse de stabilité en pratique, c&amp;rsquo;est-à-dire identifier les modes de défaillance et superposer des remèdes ciblés, dans un moteur physique en C99 portable avec tests de validation embarqués.&lt;/li>
&lt;li>&lt;strong>Ingénierie de la performance :&lt;/strong> des noyaux sans branchement adaptés au SIMD, une organisation mémoire en structure de tableaux, un multithreading déterministe sans verrou et une séparation des chemins chauds et froids guidée par le profilage.&lt;/li>
&lt;li>&lt;strong>Architecture logicielle :&lt;/strong> une frontière stricte moteur/frontend avec un contrat de données zéro copie à travers la frontière C/JavaScript, et une détection de capacités à l&amp;rsquo;exécution avec dégradation élégante.&lt;/li>
&lt;li>&lt;strong>Technologies web :&lt;/strong> WebAssembly (Emscripten, threads wasm, mémoire partagée), WebGL2 (textures flottantes, colorisation dans le shader), service workers et déploiement entièrement statique.&lt;/li>
&lt;li>&lt;strong>Visualisation scientifique interactive et conception d&amp;rsquo;interface :&lt;/strong> rendu de champs en temps réel, vues multiples physiquement signifiantes, et une interface qui invite à l&amp;rsquo;expérimentation sans mode d&amp;rsquo;emploi.&lt;/li>
&lt;li>&lt;strong>Communication scientifique :&lt;/strong> rendre tangible, et ludique, une mécanique des fluides de niveau master pour un public technique généraliste.&lt;/li>
&lt;/ul>
&lt;h2 id="dépôt">Dépôt&lt;/h2>
&lt;p>Tout le code est ouvert : le moteur C (abondamment commenté, jusqu&amp;rsquo;à chaque drapeau de compilation et sa justification), le moteur de rendu WebGL2, les scripts de build et les tests physiques de validation.&lt;/p>
&lt;p>Le code vit sur &lt;strong>&lt;a href="https://github.com/vcaries/web_lbm" target="_blank" rel="noopener">github.com/vcaries/web_lbm&lt;/a>&lt;/strong>, et la soufflerie elle-même tourne sur &lt;strong>&lt;a href="https://vcaries.github.io/web_lbm/" target="_blank" rel="noopener">vcaries.github.io/web_lbm&lt;/a>&lt;/strong>.&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>Web-LBM condense tout l&amp;rsquo;éventail de l&amp;rsquo;ingénierie de simulation dans une seule page que chacun peut ouvrir : une méthode numérique cinétique, la modélisation de la turbulence, l&amp;rsquo;optimisation SIMD et multithread, le rendu GPU et une interaction de qualité produit. La méthode de Boltzmann sur réseau est le choix qui rend tout possible, car elle est locale, parallèle, naturellement instationnaire et discrètement capable d&amp;rsquo;acoustique. Le navigateur est la contrainte qui structure tout, puisque chacune de ses limites a dû être contournée par l&amp;rsquo;ingénierie plutôt qu&amp;rsquo;éludée. Le résultat : une soufflerie dans un onglet, et la démonstration que le &lt;em>vrai&lt;/em> calcul scientifique n&amp;rsquo;est pas condamné à vivre derrière une file d&amp;rsquo;attente sur un cluster.&lt;/p></description></item><item><title>Optimisation multipoint de profils d’aile pour l’ensemble de l’enveloppe de vol</title><link>https://vcaries.github.io/project/airfoil-optimization/</link><pubDate>Mon, 01 Jun 2026 00:00:00 +0000</pubDate><guid>https://vcaries.github.io/project/airfoil-optimization/</guid><description>&lt;h2 id="le-probleme">Le défi : optimiser un profil d’aile sur l’ensemble d’une mission&lt;/h2>
&lt;p>Un profil d’aile n’est jamais conçu pour une seule condition de fonctionnement. Au cours d’une mission, il doit évoluer dans des régimes aérodynamiques très différents : phases à faible vitesse nécessitant une forte portance au décollage et à l’atterrissage, puis croisière à vitesse élevée où la réduction de la traînée devient le principal levier de performance énergétique.&lt;/p>
&lt;p>Ces exigences sont souvent contradictoires. Les géométries favorisant la production de portance aux faibles vitesses tendent à pénaliser les performances en croisière, tandis que les profils optimisés pour minimiser la traînée à haute vitesse peuvent présenter des caractéristiques moins favorables lors des phases lentes du vol. La conception d&amp;rsquo;un profil d’aile relève donc d’un problème d’optimisation multi-objectifs dans lequel il s&amp;rsquo;agit de trouver le meilleur compromis entre plusieurs conditions de fonctionnement concurrentes.&lt;/p>
&lt;p>Explorer cet espace de conception constitue un défi à part entière. Les simulations haute fidélité offrent une excellente précision mais restent trop coûteuses pour évaluer systématiquement des milliers de géométries candidates. À l’inverse, les approches fondées sur des itérations manuelles ne permettent d’explorer qu’une fraction limitée des solutions possibles.&lt;/p>
&lt;p>Ce projet propose une approche automatisée basée sur l’optimisation évolutionnaire. Des milliers de profils sont générés, évalués par un solveur aérodynamique et sélectionnés au fil des générations afin d’identifier les géométries offrant les meilleurs compromis de performance sur l’ensemble de l’enveloppe de vol.&lt;/p>
&lt;h2 id="en-60-secondes">Ce que fait ce projet en 60 secondes&lt;/h2>
&lt;p>J’ai développé une boîte à outils Python, &lt;code>aeroforge&lt;/code>, qui automatise la conception de profils d’aile pour une mission de vol réaliste composée de trois phases : décollage, croisière et atterrissage.&lt;/p>
&lt;p>Chaque géométrie est décrite de manière compacte à l’aide de trois paramètres (cambrure, position de cambrure et épaisseur). Ses performances aérodynamiques sont ensuite évaluées via un solveur validé. Un algorithme d’optimisation évolutionnaire, inspiré de la sélection naturelle, fait évoluer une population de formes afin d’améliorer progressivement les compromis entre portance et traînée sur l’ensemble du domaine de vol.&lt;/p>
&lt;p>Plutôt que de fournir une solution unique, la méthode génère un ensemble de compromis optimaux. En ingénierie, cet ensemble est appelé front de Pareto : chaque solution qui s’y trouve correspond à un équilibre tel qu’améliorer la portance implique nécessairement de dégrader la traînée, et inversement. Parmi ces solutions, la boîte à outils identifie également une configuration de référence représentant un compromis globalement équilibré.&lt;/p>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/champion-geometries.svg" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/champion-geometries.svg" alt="Profils d'aile issus de quatre stratégies d'optimisation superposés" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 1.&lt;/strong> Les quatre profils gagnants, chacun étant le profil recommandé d'une optimisation distincte : une réglée uniquement pour le décollage, une pour la croisière, une pour l'atterrissage, et une équilibrée sur les trois. Les phases à forte portance privilégient des formes épaisses et très cambrées, tandis que la croisière privilégie une forme fine, presque plate.&lt;em>(Cliquez sur une figure pour l'ouvrir en grand.)&lt;/em>&lt;/figcaption>
&lt;/figure>
&lt;h3 id="resultats-cles">Résultats clés&lt;/h3>
&lt;p>Le pipeline exécute quatre optimisations complètes de manière séquentielle : trois sont spécialisées chacune sur une phase de vol distincte, et une quatrième vise un compromis global entre décollage, croisière et atterrissage. Au total, environ trois mille géométries candidates sont évaluées et comparées de façon automatisée.&lt;/p>
&lt;p>Chaque exécution ne produit pas une solution unique, mais un front de Pareto, c’est-à-dire un ensemble de compromis optimaux entre portance et traînée. À partir de ce front, un profil de référence est également sélectionné comme point d’équilibre le plus représentatif. Chaque candidat est évalué via un solveur aérodynamique visqueux, &lt;code>XFOIL&lt;/code>.&lt;/p>
&lt;p>La spécialisation des solutions est clairement observable. Le profil optimal pour la croisière est fin et faiblement cambré, celui optimisé pour l’atterrissage est plus épais et fortement cambré, tandis que le profil équilibré se positionne volontairement entre ces deux extrêmes, traduisant un compromis multi-mission.&lt;/p>
&lt;h3 id="technologies">Technologies utilisées&lt;/h3>
&lt;p>&lt;code>Python 3.10+&lt;/code> · solveur aérodynamique &lt;code>XFOIL&lt;/code> · algorithme génétique &lt;code>NSGA-II&lt;/code> via &lt;code>pymoo&lt;/code> · &lt;code>NumPy&lt;/code> · &lt;code>Matplotlib&lt;/code> · &lt;code>imageio&lt;/code> pour les animations, le tout dans une base de code orientée objet, testée et documentée.&lt;/p>
&lt;h3 id="points-forts">Points forts du projet&lt;/h3>
&lt;p>La boîte à outils est construite en cinq couches indépendantes (géométrie, solveur, convergence, optimisation et visualisation) qui peuvent chacune être testées et remplacées séparément. Elle prend en compte à la fois des limites de fabrication et de structure sur la forme, et des limites aérodynamiques sur ses performances. Elle gère les formes candidates que le solveur ne parvient pas à évaluer en les détectant et en les écartant, de sorte que la recherche ne se bloque jamais. Et elle transforme tout l&amp;rsquo;historique de l&amp;rsquo;optimisation en un ensemble de figures et d&amp;rsquo;animations claires qui expliquent non seulement ce que l&amp;rsquo;optimiseur a choisi, mais pourquoi.&lt;/p>
&lt;h2 id="resume-visuel">Résumé visuel&lt;/h2>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/multipoint-pareto-evolution.gif" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/multipoint-pareto-evolution.gif" alt="Optimisation animée montrant la formation de la courbe de compromis" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 2.&lt;/strong> Cette figure illustre l’évolution du processus d’optimisation multi-point.
À gauche, l’espace des performances est représenté, où un déplacement vers la droite correspond à une augmentation de la traînée (dégradation des performances) et un déplacement vers le haut à une augmentation de la portance (amélioration des performances). La courbe ambre représente le front de Pareto courant, c’est-à-dire l’ensemble des meilleurs compromis identifiés à un instant donné. L’étoile bleu marine indique le profil recommandé, tandis que les points gris correspondent aux géométries évaluées précédemment. Les croix rouges représentent les candidats ayant échoué à au moins une contrainte.
À droite, la même population est visualisée dans l’espace des paramètres géométriques. On observe clairement la dynamique d’évolution : la population converge progressivement vers la zone de forte portance et faible traînée, puis se structure le long d’une courbe de compromis bien définie.&lt;/figcaption>
&lt;/figure>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/champion-mission-performance.svg" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/champion-mission-performance.svg" alt="Comparaison de la portance, de la traînée et de l'efficacité de chaque gagnant sur les trois phases" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 3.&lt;/strong> Pourquoi un seul profil d’aile ne suffit pas ?
Chaque groupe de barres représente un profil optimisé, et chaque ensemble correspond à une phase de vol distincte. Le profil optimisé pour la croisière est le plus efficace dans cette condition, mais fournit une portance insuffisante à l’atterrissage. Le profil optimisé pour l’atterrissage atteint la portance la plus élevée, au prix d’une traînée pénalisante en croisière. Le profil équilibré évite les faiblesses marquées sur une phase donnée, ce qui en fait une solution plus adaptée à une mission complète où la robustesse sur l’ensemble du domaine de vol est essentielle.&lt;/figcaption>
&lt;/figure>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/pareto-overlay.svg" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/pareto-overlay.svg" alt="Superposition des courbes de compromis de chaque exécution avec les profils recommandés" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 4.&lt;/strong> Comparaison des fronts de Pareto entre stratégies d’optimisation.
Cette figure superpose les fronts de Pareto finaux obtenus pour l’ensemble des campagnes d’optimisation dans une seule représentation, chaque profil recommandé étant identifié par une étoile.
Comme chaque optimisation mono-phase cible une condition de vol spécifique, les fronts de Pareto associés occupent des régions distinctes de l’espace portance–traînée. L’optimisation multi-point forme une structure de liaison entre ces régions, en reliant les compromis de performance sur l’ensemble de l’enveloppe de vol.&lt;/figcaption>
&lt;/figure>
&lt;p>En une phrase : l’optimiseur retrouve de manière autonome un résultat classique de conception aérodynamique selon lequel la portance élevée favorise une forte cambrure et une épaisseur importante tandis que la réduction de la traînée impose des géométries plus fines et moins cambrées puis il quantifie précisément les compromis nécessaires pour obtenir de bonnes performances sur l’ensemble d’une mission de vol.&lt;/p>
&lt;h2 id="table-des-matieres">Table des matières&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="#vue-densemble">Vue d&amp;rsquo;ensemble du projet&lt;/a>&lt;/li>
&lt;li>&lt;a href="#le-defi">Le défi d&amp;rsquo;ingénierie&lt;/a>&lt;/li>
&lt;li>&lt;a href="#aerodynamique">Notions d&amp;rsquo;aérodynamique&lt;/a>
&lt;ul>
&lt;li>&lt;a href="#geometrie">Géométrie du profil : cambrure, position de cambrure, épaisseur&lt;/a>&lt;/li>
&lt;li>&lt;a href="#coefficients">Les coefficients aérodynamiques&lt;/a>&lt;/li>
&lt;li>&lt;a href="#reynolds">Nombre de Reynolds&lt;/a>&lt;/li>
&lt;li>&lt;a href="#mach">Nombre de Mach&lt;/a>&lt;/li>
&lt;li>&lt;a href="#mission">Tout assembler : la mission&lt;/a>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;a href="#fonctionnement">Comment fonctionne l&amp;rsquo;optimisation&lt;/a>&lt;/li>
&lt;li>&lt;a href="#espace-de-conception">L&amp;rsquo;espace de conception&lt;/a>&lt;/li>
&lt;li>&lt;a href="#objectifs-contraintes">Objectifs et contraintes&lt;/a>&lt;/li>
&lt;li>&lt;a href="#front-de-pareto">Les compromis et le front de Pareto&lt;/a>&lt;/li>
&lt;li>&lt;a href="#algorithme">L&amp;rsquo;algorithme d&amp;rsquo;optimisation&lt;/a>&lt;/li>
&lt;li>&lt;a href="#solveur">Exécuter le solveur aérodynamique&lt;/a>&lt;/li>
&lt;li>&lt;a href="#optimiser-mission">Optimiser sur toute la mission&lt;/a>&lt;/li>
&lt;li>&lt;a href="#resultats">Résultats&lt;/a>&lt;/li>
&lt;li>&lt;a href="#enseignements">Ce que les résultats nous apprennent&lt;/a>&lt;/li>
&lt;li>&lt;a href="#architecture">Architecture logicielle&lt;/a>&lt;/li>
&lt;li>&lt;a href="#competences">Compétences techniques démontrées&lt;/a>&lt;/li>
&lt;li>&lt;a href="#pour-aller-plus-loin">Pour aller plus loin&lt;/a>&lt;/li>
&lt;li>&lt;a href="#depot">Dépôt&lt;/a>&lt;/li>
&lt;li>&lt;a href="#conclusion">Conclusion&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="vue-densemble">Vue d&amp;rsquo;ensemble du projet&lt;/h2>
&lt;p>Tôt dans la conception d&amp;rsquo;un avion, les ingénieurs doivent balayer rapidement une vaste région de l&amp;rsquo;espace des formes d&amp;rsquo;aile. Les outils haute fidélité, les simulations Navier–Stokes moyennées (RANS) utilisées plus tard dans un programme, résolvent l&amp;rsquo;écoulement dans son intégralité mais sont bien trop coûteux pour évaluer des milliers de candidats. Ce qu&amp;rsquo;exige l&amp;rsquo;étape de conception préliminaire, c&amp;rsquo;est un solveur assez rapide pour balayer l&amp;rsquo;espace de conception et assez fidèle physiquement pour que les classements qu&amp;rsquo;il produit soient dignes de confiance.&lt;/p>
&lt;p>Ce projet construit cette capacité autour de XFOIL, un solveur visqueux pour les profils d&amp;rsquo;aile 2D. XFOIL couple un modèle d&amp;rsquo;écoulement potentiel pour l&amp;rsquo;écoulement extérieur à une formulation intégrale de la couche limite, de sorte qu&amp;rsquo;il capture la physique visqueuse qui fixe l&amp;rsquo;essentiel de la traînée, y compris la transition et l&amp;rsquo;apparition du décollement, tout en renvoyant une polaire convergée en bien moins d&amp;rsquo;une seconde. C&amp;rsquo;est cette rapidité qui le rend viable à l&amp;rsquo;intérieur d&amp;rsquo;une boucle d&amp;rsquo;optimisation. La contribution d&amp;rsquo;ingénierie consiste à le piloter automatiquement et de façon fiable sur des milliers d&amp;rsquo;évaluations, et à transformer sa sortie brute en quantités qu&amp;rsquo;un concepteur peut interpréter.&lt;/p>
&lt;p>&lt;code>aeroforge&lt;/code> est la boîte à outils que j&amp;rsquo;ai construite pour cela. Elle est organisée en cinq couches découplées : génération de la géométrie, exécution du solveur, gestion de la convergence, optimisation et visualisation. L&amp;rsquo;étude de cas de cette page est un pipeline complet de bout en bout qui sollicite chaque couche, depuis trois variables de conception jusqu&amp;rsquo;à un front de Pareto convergé et un enregistrement animé de sa formation.&lt;/p>
&lt;p>Les objectifs étaient concrets : coupler un optimiseur à un véritable solveur externe sans corrompre ni l&amp;rsquo;un ni l&amp;rsquo;autre, encoder une mission représentative à plusieurs phases plutôt qu&amp;rsquo;un point de conception unique, produire un front de Pareto et un profil recommandé défendable sous de véritables contraintes géométriques et aérodynamiques, et générer des figures reproductibles qui exposent le raisonnement derrière les choix de l&amp;rsquo;optimiseur.&lt;/p>
&lt;h2 id="le-defi">Le défi d&amp;rsquo;ingénierie&lt;/h2>
&lt;p>Une aile développe de la portance en accélérant l&amp;rsquo;écoulement sur sa surface supérieure et en le ralentissant en dessous, établissant une différence de pression dont l&amp;rsquo;intégrale donne une force ascendante nette. Elle paie cette portance par de la traînée, qui se décompose en trois contributions : la traînée de frottement, due au cisaillement visqueux dans la couche limite, la traînée de pression (ou de forme), due à la façon dont la couche limite modifie la forme effective que voit l&amp;rsquo;écoulement extérieur, et, dès que l&amp;rsquo;écoulement local approche la vitesse du son, la traînée d&amp;rsquo;onde, due à la compressibilité et aux chocs.&lt;/p>
&lt;p>Le conflit entre portance et traînée est intrinsèque à la physique. Ajouter de la cambrure et de l&amp;rsquo;épaisseur augmente la portance qu&amp;rsquo;une section produit, mais charge aussi la couche limite d&amp;rsquo;un gradient de pression adverse plus fort, l&amp;rsquo;épaississant et augmentant la traînée. Une section fine et faiblement cambrée est efficace en croisière mais ne peut pas atteindre les coefficients de portance dont une aile a besoin à basse vitesse. Poussez la charge trop loin à une vitesse donnée et la couche limite se décolle, la section décroche, et la portance comme le contrôle se perdent ensemble.&lt;/p>
&lt;p>Aucun avion ne fonctionne à une seule condition. Il décolle à basse vitesse et forte incidence, où maximiser la portance compte et où la traînée est tolérable ; il croise vite et faiblement chargé pendant des heures, où la traînée gouverne directement la consommation ; puis il atterrit lentement à forte portance, où la traînée est en fait utile à la décélération. Une section optimisée pour la seule croisière ne peut pas décoller ; une optimisée pour le seul décollage gaspille du carburant en croisière. C&amp;rsquo;est pourquoi le problème est irréductiblement multi-objectif, et pourquoi sa sortie naturelle est une famille de compromis plutôt qu&amp;rsquo;un optimum unique.&lt;/p>
&lt;h2 id="aerodynamique">Notions d&amp;rsquo;aérodynamique&lt;/h2>
&lt;p>Chaque quantité de cette section correspond à quelque chose de concret dans le code : une variable de conception, un objectif, une contrainte ou une condition de vol. Rien n&amp;rsquo;est de la théorie générique ajoutée après coup.&lt;/p>
&lt;h3 id="geometrie">Géométrie du profil : cambrure, position de cambrure, épaisseur&lt;/h3>
&lt;p>Le projet paramètre les sections à l&amp;rsquo;aide de la famille classique NACA à 4 chiffres, une description analytique standard qui ne requiert que trois nombres. Ces trois nombres sont les variables de conception que l&amp;rsquo;optimiseur est libre de faire varier.&lt;/p>
&lt;p>Le premier est la &lt;strong>cambrure maximale&lt;/strong> $m$, la hauteur maximale de la ligne moyenne de cambrure rapportée à la corde. La cambrure permet à une section de produire de la portance à incidence nulle et translate vers le haut toute sa courbe de portance ; l&amp;rsquo;augmenter accroît la portance mais tend aussi à ajouter de la traînée et un moment de tangage à piquer plus marqué.&lt;/p>
&lt;p>Le deuxième est la &lt;strong>position de cambrure maximale&lt;/strong> $p$, la station le long de la corde où ce maximum se produit. Elle redistribue la charge le long de la corde et influence l&amp;rsquo;endroit où le gradient de pression adverse devient critique, et donc où le décollement et le décrochage commencent.&lt;/p>
&lt;p>Le troisième est l&amp;rsquo;&lt;strong>épaisseur maximale&lt;/strong> $t$, exprimée en fraction de la corde. L&amp;rsquo;épaisseur fournit le volume interne dont une aile réelle a besoin pour sa structure et son carburant, et elle conditionne le caractère du décrochage : les sections fines décrochent brutalement, lorsque le pic d&amp;rsquo;aspiration s&amp;rsquo;effondre, les plus épaisses plus progressivement, au prix d&amp;rsquo;un peu de traînée supplémentaire.&lt;/p>
&lt;p>Ces trois nombres sont développés en la surface analytique NACA puis discrétisés en une géométrie lisse en panneaux. Ils constituent l&amp;rsquo;intégralité de l&amp;rsquo;espace de conception exploré par l&amp;rsquo;optimiseur.&lt;/p>
&lt;h3 id="coefficients">Les coefficients aérodynamiques&lt;/h3>
&lt;p>Le solveur exprime les performances à l&amp;rsquo;aide de coefficients sans dimension, obtenus en normalisant les forces et les moments par la pression dynamique et la corde, de sorte que les sections se comparent indépendamment de la taille et de la vitesse.&lt;/p>
&lt;p>Le &lt;strong>coefficient de portance&lt;/strong> $C_l$ quantifie la portance et c&amp;rsquo;est l&amp;rsquo;objectif que l&amp;rsquo;optimiseur maximise. Le &lt;strong>coefficient de traînée&lt;/strong> $C_d$ quantifie la traînée et c&amp;rsquo;est l&amp;rsquo;objectif qu&amp;rsquo;il minimise. Le &lt;strong>coefficient de moment de tangage&lt;/strong> $C_m$ mesure le moment à cabrer ou à piquer autour du quart de corde ; il n&amp;rsquo;est pas optimisé mais borné, car une section au moment trop marqué oblige l&amp;rsquo;empennage horizontal à porter une forte charge d&amp;rsquo;équilibrage. Leur rapport, la &lt;strong>finesse&lt;/strong> $L/D = C_l/C_d$, est la mesure la plus compacte de l&amp;rsquo;efficacité aérodynamique : en croisière stabilisée, le rayon d&amp;rsquo;action lui est directement proportionnel par la relation de Breguet.&lt;/p>
&lt;h3 id="reynolds">Nombre de Reynolds&lt;/h3>
$$Re = \frac{\rho \ U \ c}{\mu}$$
&lt;p>Le nombre de Reynolds est le rapport des forces d&amp;rsquo;inertie aux forces visqueuses dans l&amp;rsquo;écoulement, et il gouverne l&amp;rsquo;état de la couche limite, la fine région visqueuse adjacente à la surface. Aux faibles valeurs typiques du décollage et de l&amp;rsquo;atterrissage, la couche limite reste laminaire sur une plus grande part de la corde, transite plus tard et se décolle plus facilement, de sorte que la section se comporte très différemment qu&amp;rsquo;aux valeurs plus élevées de la croisière. Comme XFOIL résout la couche limite et sa transition explicitement, la même géométrie produit une portance et une traînée différentes à chaque phase, ce qui constitue l&amp;rsquo;essentiel de ce qui rend une formulation à plusieurs phases physiquement significative plutôt qu&amp;rsquo;un simple renommage d&amp;rsquo;une seule condition.&lt;/p>
&lt;h3 id="mach">Nombre de Mach&lt;/h3>
$$M = \frac{U}{a}$$
&lt;p>Le nombre de Mach est le rapport de la vitesse de vol $U$ à la vitesse locale du son $a$, et il fixe l&amp;rsquo;importance de la compressibilité. À faible Mach, l&amp;rsquo;écoulement est effectivement incompressible ; à mesure que le Mach de croisière est approché, la compressibilité amplifie le pic d&amp;rsquo;aspiration et raidit les gradients de pression, et au-delà du Mach critique des poches supersoniques locales terminées par des chocs ajoutent de la traînée d&amp;rsquo;onde. Le solveur applique une correction de compressibilité, de sorte que la croisière est évaluée à son vrai nombre de Mach tandis que les phases lentes le sont au leur. C&amp;rsquo;est une autre raison pour laquelle la section optimale en croisière diffère de l&amp;rsquo;optimum à basse vitesse.&lt;/p>
&lt;h3 id="mission">Tout assembler : la mission&lt;/h3>
&lt;p>Les trois phases convertissent le conflit portance-traînée en conditions de vol concrètes. Chaque phase est spécifiée par un angle d&amp;rsquo;incidence, un nombre de Reynolds, un nombre de Mach et un poids qui encode à quel point elle compte dans l&amp;rsquo;objectif global.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Phase de vol&lt;/th>
&lt;th>Angle d&amp;rsquo;incidence $\alpha$&lt;/th>
&lt;th>Reynolds $Re$&lt;/th>
&lt;th>Mach $M$&lt;/th>
&lt;th>Poids d&amp;rsquo;importance&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Décollage&lt;/strong>&lt;/td>
&lt;td>8°&lt;/td>
&lt;td>$5\times10^5$&lt;/td>
&lt;td>0,15&lt;/td>
&lt;td>1,0&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Croisière&lt;/strong>&lt;/td>
&lt;td>2°&lt;/td>
&lt;td>$2\times10^6$&lt;/td>
&lt;td>0,60&lt;/td>
&lt;td>1,5&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Atterrissage&lt;/strong>&lt;/td>
&lt;td>10°&lt;/td>
&lt;td>$4\times10^5$&lt;/td>
&lt;td>0,15&lt;/td>
&lt;td>1,2&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Le décollage et l&amp;rsquo;atterrissage sont des conditions à forte incidence, basse vitesse et forte portance. La croisière est à faible incidence, haute vitesse et critique pour l&amp;rsquo;efficacité, ce qui explique son poids le plus élevé. Aucune géométrie unique ne peut être simultanément optimale pour une croisière à 2° et un atterrissage lent à 10°, et le projet le démontre directement en optimisant chaque phase isolément et en montrant que les sections obtenues sont réellement distinctes (Figure 1).&lt;/p>
&lt;h2 id="fonctionnement">Comment fonctionne l&amp;rsquo;optimisation&lt;/h2>
&lt;p>La boucle complète est représentée ci-dessous. Chaque bloc correspond à un véritable composant de la base de code.&lt;/p>
&lt;div class="mermaid">flowchart TD
A["Trois nombres de conception&lt;br/>cambrure, position, épaisseur"] --> B["Construire la forme de l'aile&lt;br/>profil NACA standard"]
B --> C["Vérifier les limites de forme&lt;br/>épaisseur, aire, bord de fuite, cambrure"]
C -->|acceptable| D["Analyse aérodynamique&lt;br/>solveur exécuté à chaque phase"]
C -->|rejetée| H["Pénalisée&lt;br/>candidate écartée"]
D --> E["Combiner les phases&lt;br/>portance pondérée, traînée de croisière"]
E --> F["Vérifier les limites de performance&lt;br/>portance min, traînée max, limite de tangage"]
F --> G["Deux objectifs&lt;br/>maximiser la portance, minimiser la traînée"]
G --> I["Algorithme génétique&lt;br/>classer selon la qualité du compromis"]
H --> I
I --> J["Engendrer la génération suivante&lt;br/>sélection, recombinaison, mutation"]
J -->|répéter| B
J --> K["Ensemble des meilleurs compromis"]
K --> L["Choisir le profil le plus équilibré"]
&lt;/div>
&lt;p>En séquence : trois variables de conception définissent une section ; la géométrie est filtrée face à des limites de fabrication et de structure ; les candidates réalisables sont analysées par le solveur à chaque condition de vol ; les résultats par phase sont agrégés en une portance de mission et une traînée de croisière ; ceux-ci alimentent deux objectifs concurrents et trois contraintes de performance ; NSGA-II classe la population par tri non dominé, engendre la génération suivante, et la boucle recommence. Après la dernière génération, un profil équilibré est extrait du front.&lt;/p>
&lt;h2 id="espace-de-conception">L&amp;rsquo;espace de conception&lt;/h2>
&lt;p>L&amp;rsquo;optimiseur explore un espace tridimensionnel volontairement compact, assez petit pour être visualisé en entier mais assez riche pour exprimer le conflit portance-traînée.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Variable&lt;/th>
&lt;th>Symbole&lt;/th>
&lt;th>Borne basse&lt;/th>
&lt;th>Borne haute&lt;/th>
&lt;th>Signification&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Cambrure maximale&lt;/td>
&lt;td>$m$&lt;/td>
&lt;td>0,00&lt;/td>
&lt;td>0,95&lt;/td>
&lt;td>à quel point la ligne médiane est courbée&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Position de cambrure&lt;/td>
&lt;td>$p$&lt;/td>
&lt;td>0,10&lt;/td>
&lt;td>0,80&lt;/td>
&lt;td>où la cambrure est maximale le long de la corde&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Épaisseur&lt;/td>
&lt;td>$t$&lt;/td>
&lt;td>0,01&lt;/td>
&lt;td>0,40&lt;/td>
&lt;td>épaisseur maximale relative à la longueur&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Ces trois variables continues se traduisent en une section NACA analytique, de sorte qu&amp;rsquo;une épaisseur proche du milieu de sa plage correspond à une section d&amp;rsquo;environ 12 % d&amp;rsquo;épaisseur rapportée à la corde, et ainsi de suite. La famille NACA a été choisie parce qu&amp;rsquo;elle est lisse, définie analytiquement et bien conditionnée pour l&amp;rsquo;optimisation : chaque point de la boîte est une section réalisable et fabricable, ce qui empêche la recherche de dériver vers des géométries dégénérées.&lt;/p>
&lt;h2 id="objectifs-contraintes">Objectifs et contraintes&lt;/h2>
&lt;p>L&amp;rsquo;optimiseur poursuit deux objectifs en même temps. Le premier maximise la &lt;strong>portance de mission&lt;/strong>, la somme pondérée par l&amp;rsquo;importance du coefficient de portance sur les phases,&lt;/p>
$$C_{L,\text{mission}} = \sum_i w_i\,C_{l,i},$$
&lt;p>de sorte que la croisière domine l&amp;rsquo;agrégat. Le second minimise la &lt;strong>traînée de croisière&lt;/strong>, évaluée à la phase principale. La traînée est jugée à une seule condition parce qu&amp;rsquo;elle n&amp;rsquo;a de sens physique qu&amp;rsquo;à une seule, tandis que la portance est l&amp;rsquo;agrégat que l&amp;rsquo;avion doit produire sur toute la mission. Les deux objectifs s&amp;rsquo;opposent, ce qui rend le problème véritablement multi-objectif.&lt;/p>
&lt;p>Au-delà des objectifs, chaque profil doit satisfaire un ensemble de contraintes. Le premier groupe concerne la géométrie elle-même et s&amp;rsquo;applique à toutes les phases, car une section doit être constructible et structurellement adéquate quelle que soit la condition de vol.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Limite de forme&lt;/th>
&lt;th>Exigence&lt;/th>
&lt;th>Pourquoi c&amp;rsquo;est important&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Épaisseur minimale&lt;/td>
&lt;td>assez épaisse globalement&lt;/td>
&lt;td>l&amp;rsquo;aile a besoin de volume interne et de rigidité&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Épaisseur locale près du nez&lt;/td>
&lt;td>assez épaisse à l&amp;rsquo;avant&lt;/td>
&lt;td>de la place pour un longeron près du bord d&amp;rsquo;attaque&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Aire minimale&lt;/td>
&lt;td>section assez grande&lt;/td>
&lt;td>une approximation du volume de carburant et de structure&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Bord de fuite peu ouvert&lt;/td>
&lt;td>presque fermé à l&amp;rsquo;arrière&lt;/td>
&lt;td>un bord de fuite fin doit rester fabricable&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Cambrure raisonnable&lt;/td>
&lt;td>dans une borne&lt;/td>
&lt;td>une limite de bon sens structurel et aéroélastique&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Le second groupe concerne la performance et dépend de la phase de vol, car chaque phase impose des exigences différentes.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Limite de performance&lt;/th>
&lt;th>Exigence&lt;/th>
&lt;th>Pourquoi c&amp;rsquo;est important&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Portance minimale&lt;/td>
&lt;td>assez de portance à cette phase&lt;/td>
&lt;td>l&amp;rsquo;avion doit réellement porter son poids ici&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Traînée maximale&lt;/td>
&lt;td>pas trop traînante&lt;/td>
&lt;td>écarte les valeurs aberrantes inefficaces&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Limite de tangage&lt;/td>
&lt;td>moment de tangage borné&lt;/td>
&lt;td>limite l&amp;rsquo;effort que l&amp;rsquo;empennage doit fournir pour équilibrer l&amp;rsquo;avion&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Les seuils sont fixés par phase. Le décollage et l&amp;rsquo;atterrissage exigent une forte portance et tolèrent la traînée, tandis que la croisière exige une faible traînée et une portance seulement modérée. Pour l&amp;rsquo;exécution équilibrée, l&amp;rsquo;exigence de portance est le total pondéré de la mission relâché d&amp;rsquo;une faible marge, assez strict pour avoir du sens mais assez souple pour conserver une région réalisable peuplée. Tout profil violant une contrainte est pénalisé et progressivement chassé de la population par le classement.&lt;/p>
&lt;h2 id="front-de-pareto">Les compromis et le front de Pareto&lt;/h2>
&lt;p>Avec deux objectifs concurrents, il n&amp;rsquo;existe pas un seul optimum, mais tout un ensemble. La notion organisatrice est la &lt;strong>dominance&lt;/strong> : un profil en domine un autre s&amp;rsquo;il est au moins aussi bon sur les deux objectifs et strictement meilleur sur l&amp;rsquo;un. Les profils réalisables qu&amp;rsquo;aucun autre profil réalisable ne domine forment le &lt;strong>front de Pareto&lt;/strong>, la frontière de la région portance-traînée atteignable. C&amp;rsquo;est la courbe ambre de la Figure 2.&lt;/p>
&lt;p>La forme du front est en elle-même le résultat d&amp;rsquo;ingénierie. Un segment abrupt signifie que la portance s&amp;rsquo;achète à bas prix en traînée ; un segment plat signifie que le dernier gain de portance coûte cher en traînée. Présenter tout le front, plutôt que de le réduire à un score pondéré unique choisi à l&amp;rsquo;avance, laisse la décision finale à l&amp;rsquo;ingénieur et rend explicite le coût réel de chaque compromis.&lt;/p>
&lt;p>Cela motive aussi le choix d&amp;rsquo;un algorithme génétique plutôt que les méthodes par gradient courantes en optimisation. Chaque évaluation provient d&amp;rsquo;un solveur externe sans dérivées analytiques, les réponses portent un léger bruit numérique, et certaines géométries ne peuvent pas être évaluées du tout. Les méthodes par gradient s&amp;rsquo;accommodent mal de ces trois aspects. Une méthode à population, sans dérivées, tolère le bruit, reconstitue tout le front en une seule exécution, et se dégrade gracieusement lorsque des évaluations individuelles échouent.&lt;/p>
&lt;h2 id="algorithme">L&amp;rsquo;algorithme d&amp;rsquo;optimisation&lt;/h2>
&lt;p>L&amp;rsquo;optimiseur est NSGA-II, un algorithme génétique multi-objectif éprouvé, accédé via la bibliothèque &lt;a href="https://pymoo.org/" target="_blank" rel="noopener">pymoo&lt;/a> derrière la couche d&amp;rsquo;optimisation propre au projet. Dans la démonstration, il fait évoluer une population de vingt-cinq profils sur trente générations avec une graine aléatoire fixe, de sorte que l&amp;rsquo;exécution est entièrement reproductible.&lt;/p>
&lt;p>Son mécanisme reproduit la sélection naturelle. Partant d&amp;rsquo;une population aléatoire et variée, chaque génération classe les individus par &lt;strong>tri non dominé&lt;/strong> : l&amp;rsquo;ensemble non dominé courant forme le premier front, l&amp;rsquo;ensemble suivant une fois celui-ci retiré forme le second, et ainsi de suite. Au sein d&amp;rsquo;un front, une mesure de &lt;strong>distance d&amp;rsquo;encombrement&lt;/strong> favorise les individus situés dans les régions peu peuplées, ce qui répartit les solutions uniformément le long du front au lieu de les laisser s&amp;rsquo;agglutiner. Une sélection par tournoi binaire choisit ensuite les parents, un croisement binaire simulé et une mutation polynomiale perturbent leurs trois variables pour produire une descendance, et parents et descendants concourent ensemble dans une étape élitiste de sorte que la population ne régresse jamais. Chacune de ces étapes est visible dans les animations de cette page.&lt;/p>
&lt;p>Les profils non réalisables sont toujours classés derrière les réalisables, et parmi les non réalisables, les moins violants viennent d&amp;rsquo;abord, de sorte que les points rouges non réalisables de la Figure 2 sont progressivement évincés de la population.&lt;/p>
&lt;p>Après la dernière génération, la boîte à outils recommande un profil du front : le point le plus proche du coin idéal, et inatteignable, qui aurait à la fois la meilleure portance et la meilleure traînée. Ce compromis, le coude du front, est marqué d&amp;rsquo;une étoile bleu marine dans toutes les figures.&lt;/p>
&lt;h2 id="solveur">Exécuter le solveur aérodynamique&lt;/h2>
&lt;p>XFOIL est au cœur de chaque évaluation. Il couple une solution non visqueuse par panneaux de l&amp;rsquo;écoulement extérieur à un modèle intégral de couche limite, et de leur interaction il déduit non seulement la portance et la traînée mais l&amp;rsquo;état complet de la couche limite, y compris la position de transition et le décollement. Ce détail est précieux, car il explique &lt;em>pourquoi&lt;/em> une section en surpasse une autre, et pas seulement de combien. Rapide et largement validé, il convient bien à une exécution à l&amp;rsquo;intérieur d&amp;rsquo;une boucle d&amp;rsquo;optimisation.&lt;/p>
&lt;p>La difficulté pratique est que certaines géométries proposées par l&amp;rsquo;optimiseur sont trop agressives pour que le solveur converge, par exemple des sections très épaisses ou fortement cambrées fonctionnant près du décrochage. Le pipeline traite ces cas de façon déterministe : lorsque le solveur ne peut pas renvoyer de résultat fiable, le cas est détecté et écarté, doté de valeurs de pénalité qui le classent en dessous des vrais candidats afin que la recherche se poursuive sans interruption. Le pipeline enregistre aussi combien de fois cela se produit et pourquoi, qu&amp;rsquo;une géométrie ait échoué au filtre géométrique, n&amp;rsquo;ait pas convergé, ou ait violé une contrainte de performance, transformant un échec autrement opaque en une statistique de diagnostic.&lt;/p>
&lt;p>Plusieurs détails d&amp;rsquo;ingénierie rendent cela fiable. Les géométries générées par l&amp;rsquo;optimiseur portent parfois des répartitions de panneaux peu commodes, aussi chaque section est re-panneautée avant l&amp;rsquo;analyse et les cas difficiles sont réessayés avec une succession de stratégies de continuation progressivement plus douces avant d&amp;rsquo;être abandonnés. Comme le solveur est un programme externe piloté par une interface textuelle, la boîte à outils gère cette interaction, isole chaque exécution et analyse la sortie de façon robuste sur toutes les plateformes. Un solveur de remplacement intégré et rapide est livré en parallèle, de sorte que l&amp;rsquo;ensemble du flux peut être exercé et testé même sans XFOIL installé.&lt;/p>
&lt;p>L&amp;rsquo;intérêt de résoudre la couche limite se voit dans les diagnostics de pression que le solveur renvoie pour chaque profil gagnant.&lt;/p>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/champion-cp.svg" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/champion-cp.svg" alt="Distributions de pression de chaque gagnant à chaque phase de vol" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 5.&lt;/strong> La pression le long de la surface de chaque profil gagnant à chaque phase de vol (traits pleins pour la surface supérieure, pointillés pour l'inférieure). Les gagnants à forte portance présentent un pic d'aspiration plus marqué près du nez, ce qui signifie plus de portance mais aussi une remontée de pression plus raide que l'écoulement de surface doit franchir sans se décoller. C'est la physique sous-jacente contre laquelle l'optimiseur arbitre implicitement.&lt;/figcaption>
&lt;/figure>
&lt;h2 id="optimiser-mission">Optimiser sur toute la mission&lt;/h2>
&lt;p>Une seule condition de vol ne peut pas représenter un avion, aussi le pipeline procède par étapes. Il optimise d&amp;rsquo;abord chaque phase isolément, décollage, croisière et atterrissage, chacune sous ses propres contraintes ; ces exécutions établissent les extrêmes, la meilleure section atteignable si seule cette phase comptait. Il lance ensuite une unique optimisation équilibrée dont l&amp;rsquo;objectif de portance est le total de mission pondéré par l&amp;rsquo;importance, la croisière étant la phase où la traînée est jugée. C&amp;rsquo;est le profil tenu de performer partout. Enfin, il génère des figures qui superposent les quatre gagnants afin que le compromis du profil équilibré face à chaque spécialiste soit immédiatement lisible.&lt;/p>
&lt;p>L&amp;rsquo;agrégation des phases est le cœur d&amp;rsquo;ingénierie du projet. Plutôt que de concevoir quatre sections distinctes, on pondère les phases par importance, la croisière dominante, et on optimise le mélange. Cela reflète la façon dont les avions sont réellement conçus, autour d&amp;rsquo;une mission représentative, avec des poids qui encodent le fait que les heures passées en croisière l&amp;rsquo;emportent sur les secondes de rotation au décollage. Comme la mission est déclarée en un seul endroit du code, modifier un poids ou ajouter une phase est une modification minime, et chaque figure, animation et contrainte se met à jour avec elle.&lt;/p>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/multipoint-polars.svg" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/multipoint-polars.svg" alt="Courbes de performance de trois profils à chaque phase de vol" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 6.&lt;/strong> Courbes de performance, portance en fonction de l'angle et portance en fonction de la traînée, réévaluées par le solveur à chaque phase de vol pour trois profils de l'exécution équilibrée : l'extrême à plus forte portance, l'extrême à plus faible traînée, et le profil recommandé équilibré. Le profil recommandé reste dans la région efficace à faible traînée en croisière tout en conservant une portance utilisable aux phases lentes.&lt;/figcaption>
&lt;/figure>
&lt;h2 id="resultats">Résultats&lt;/h2>
&lt;p>Les figures ci-dessous sont sélectionnées dans l&amp;rsquo;exécution plutôt que déversées, chacune parce qu&amp;rsquo;elle établit un point précis.&lt;/p>
&lt;h3 id="optimisation-animee">L&amp;rsquo;optimisation, animée&lt;/h3>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/multipoint-geometry-evolution.gif" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/multipoint-geometry-evolution.gif" alt="Évolution animée des meilleures formes d'aile au fil des générations" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 7.&lt;/strong> Les formes qui évoluent. Chaque image dessine les meilleures formes de compromis actuelles en ambre, l'historique récent estompé en gris, et le profil recommandé en bleu marine. La population converge visiblement d'une dispersion aléatoire de sections vers une famille resserrée de profils efficaces, la conception prenant forme génération après génération.&lt;/figcaption>
&lt;/figure>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/multipoint-parallel-evolution.gif" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/multipoint-parallel-evolution.gif" alt="Vue animée en coordonnées parallèles de la population" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 8.&lt;/strong> Une autre vue de la même exécution, reliant les cinq quantités à la fois : les trois nombres de forme, la portance pondérée et la traînée de croisière. Chaque ligne est un profil. Au fil des générations, les meilleurs profils en ambre et le profil recommandé en bleu marine se fixent en un motif cohérent, révélant quelles plages des paramètres de forme produisent le meilleur équilibre.&lt;/figcaption>
&lt;/figure>
&lt;h3 id="convergence">Convergence et fronts finaux&lt;/h3>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/multipoint-convergence.svg" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/multipoint-convergence.svg" alt="Diagnostics de convergence en quatre panneaux" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 9.&lt;/strong> Diagnostics de convergence, de gauche à droite : la meilleure portance atteignable, la meilleure traînée atteignable, le nombre de profils sur la courbe de compromis, et l'hypervolume, une mesure scalaire unique de la qualité du front qui croît à mesure que l'ensemble des compromis s'améliore. Le fait que l'hypervolume continue de monter confirme que l'exécution progresse réellement plutôt que de stagner.&lt;/figcaption>
&lt;/figure>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/multipoint-pareto-geometries.svg" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/multipoint-pareto-geometries.svg" alt="Ensemble final des meilleures formes d'aile de l'exécution équilibrée" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 10.&lt;/strong> La famille finale des meilleures formes de compromis de l'exécution équilibrée, le profil recommandé étant mis en évidence. Parcourir la courbe revient à passer de sections fines à faible traînée vers des sections épaisses à forte portance, le compromis rendu tangible sous forme de vraies formes.&lt;/figcaption>
&lt;/figure>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/multipoint-mission-breakdown.svg" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/multipoint-mission-breakdown.svg" alt="Portance, traînée et efficacité par phase de chaque forme de la courbe de compromis" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 11.&lt;/strong> Portance, traînée et efficacité à chaque phase de vol pour chaque forme de la courbe de compromis, le profil recommandé étant mis en évidence. Cela montre toute l'étendue des comportements disponibles et confirme que le profil recommandé est équilibré plutôt qu'extrême.&lt;/figcaption>
&lt;/figure>
&lt;h3 id="specialistes">En quoi les spécialistes diffèrent&lt;/h3>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/champion-design-parameters.svg" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/champion-design-parameters.svg" alt="Les trois nombres de forme de chaque gagnant par stratégie" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 12.&lt;/strong> Les nombres de forme réels de chaque gagnant. Le schéma est sans ambiguïté : les gagnants à basse vitesse choisissent une forte cambrure et épaisseur, le gagnant de croisière choisit la section la plus fine et la moins cambrée, et le gagnant équilibré se place délibérément entre les deux.&lt;/figcaption>
&lt;/figure>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/takeoff-geometry-evolution.gif" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/takeoff-geometry-evolution.gif" alt="Évolution des formes de l'optimisation dédiée au décollage" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 13.&lt;/strong> L'optimisation dédiée au décollage convergeant vers des sections épaisses, fortement cambrées et à forte portance, le coin opposé de l'espace de conception par rapport à l'optimum de croisière, ce qui est précisément l'intérêt.&lt;/figcaption>
&lt;/figure>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/cruise-pareto-final.svg" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/cruise-pareto-final.svg" alt="État final de la courbe de compromis et de l'espace de conception pour la croisière seule" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 14a.&lt;/strong> État final pour la croisière seule, la courbe se situant dans la région à faible traînée et portance modérée.&lt;/figcaption>
&lt;/figure>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/landing-pareto-final.svg" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/landing-pareto-final.svg" alt="État final de la courbe de compromis et de l'espace de conception pour l'atterrissage seul" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 14b.&lt;/strong> État final pour l'atterrissage seul, la courbe se décalant vers une forte portance en acceptant une traînée bien plus élevée.&lt;/figcaption>
&lt;/figure>
&lt;p>L&amp;rsquo;animation ci-dessous boucle le lien entre la forme et la physique.&lt;/p>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/airfoil-optimization/multipoint-cp-cruise.gif" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/airfoil-optimization/multipoint-cp-cruise.gif" alt="Distribution de pression de croisière animée du profil recommandé" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 15.&lt;/strong> La distribution de pression en croisière du profil recommandé évoluant au fil des générations. À mesure que l'optimiseur affine la forme, le pic d'aspiration et la remontée de pression se lissent en un motif de croisière efficace, la signature d'une section à faible traînée.&lt;/figcaption>
&lt;/figure>
&lt;h2 id="enseignements">Ce que les résultats nous apprennent&lt;/h2>
&lt;p>Le résultat le plus frappant est que l&amp;rsquo;optimiseur retrouve l&amp;rsquo;aérodynamique connue sans qu&amp;rsquo;on la lui dise. Rien dans la formulation n&amp;rsquo;énonce que la forte portance exige cambrure et épaisseur ni que la faible traînée n&amp;rsquo;exige aucune des deux, et pourtant les gagnants se séparent précisément selon ces lignes (Figures 1 et 12). Lorsqu&amp;rsquo;une recherche qui traite le solveur comme une boîte noire reproduit de façon indépendante les tendances des manuels, c&amp;rsquo;est un indice solide que le couplage au solveur et l&amp;rsquo;ensemble de contraintes sont sains.&lt;/p>
&lt;p>Les résultats identifient aussi l&amp;rsquo;épaisseur et la cambrure comme les leviers de conception dominants, la position de cambrure maximale agissant comme un réglage plus fin. À travers les vues en coordonnées parallèles et par paramètre, ces deux variables rendent compte de l&amp;rsquo;essentiel de la variation de portance et de traînée, ce qui indique à un concepteur où concentrer au mieux ses efforts.&lt;/p>
&lt;p>La pondération oriente clairement le compromis. Comme la croisière porte le poids le plus élevé et qu&amp;rsquo;elle est l&amp;rsquo;endroit où la traînée est jugée, le profil équilibré penche vers l&amp;rsquo;efficacité de croisière tout en conservant assez de portance pour les phases lentes (Figures 3 et 6). Repondérer la mission déplacerait visiblement le profil recommandé, et le cadre rend cette sensibilité simple à explorer.&lt;/p>
&lt;p>Enfin, le projet rappelle qu&amp;rsquo;une grande partie du vrai logiciel d&amp;rsquo;ingénierie tient à la robustesse, et non à l&amp;rsquo;algorithme vedette. La difficulté substantielle ici n&amp;rsquo;était pas NSGA-II mais le maintien de résultats exploitables sur des géométries agressives. La machinerie qui détecte, écarte et signale les cas non convergés est ce qui sépare une exécution qui se termine sur un front propre d&amp;rsquo;une exécution qui s&amp;rsquo;enlise en cours de route.&lt;/p>
&lt;h2 id="architecture">Architecture logicielle&lt;/h2>
&lt;p>&lt;code>aeroforge&lt;/code> est structuré en cinq couches découplées. La couche d&amp;rsquo;optimisation ignore l&amp;rsquo;existence du solveur, et la couche du solveur ignore ce qu&amp;rsquo;est un objectif. Cette séparation est ce qui permet à la même démonstration de tourner soit sur le vrai solveur, soit sur le solveur de remplacement intégré, en un seul changement.&lt;/p>
&lt;div class="mermaid">flowchart TD
G["1 · Géométrie&lt;br/>construire la forme, mesurer ses propriétés"]
S["2 · Solveur&lt;br/>exécuter le solveur aérodynamique, lire ses résultats"]
C["3 · Convergence&lt;br/>réessayer les cas difficiles, écarter les insolubles"]
O["4 · Optimisation&lt;br/>espace de conception, objectifs, contraintes, algorithme génétique"]
V["5 · Visualisation&lt;br/>figures, animations et galeries"]
G --> S
S --> C
C --> O
O --> V
&lt;/div>
&lt;p>Quelques propriétés méritent d&amp;rsquo;être soulignées pour un lecteur attentif au logiciel. La mission et ses libellés vivent en un seul endroit qui pilote chaque figure. Les conditions de vol, les résultats et les contraintes sont représentés par des structures de données typées. Le solveur se tient derrière une interface commune, de sorte que le vrai backend et celui de remplacement sont interchangeables. Les cas non convergés sont traités par une gestion d&amp;rsquo;erreurs explicite et typée plutôt que par des échecs silencieux. Toute l&amp;rsquo;exécution est reproductible à partir d&amp;rsquo;une graine fixe et d&amp;rsquo;une seule commande. Le paquet est livré avec des tests unitaires, une configuration de linting et de vérification de types, de l&amp;rsquo;intégration continue et une documentation complète, de sorte qu&amp;rsquo;il est organisé comme une bibliothèque entretenue plutôt que comme un script jetable.&lt;/p>
&lt;div class="mermaid">flowchart TD
M["Définition de la mission&lt;br/>(source unique de vérité)"] --> S1["Étape 1&lt;br/>une exécution par phase"]
M --> S2["Étape 2&lt;br/>exécution équilibrée"]
S1 --> Cc["Étape 3&lt;br/>comparaison croisée"]
S2 --> Cc
Cc --> OUT["Galerie de figures et d'animations sélectionnées"]
&lt;/div>
&lt;h2 id="competences">Compétences techniques démontrées&lt;/h2>
&lt;p>Ce projet réunit plusieurs disciplines. Du &lt;strong>côté aérodynamique&lt;/strong> : la théorie des profils, le raisonnement sur la couche limite, le rôle des nombres de Reynolds et de Mach, l&amp;rsquo;analyse de mission et l&amp;rsquo;usage maîtrisé d&amp;rsquo;un solveur validé comme instrument d&amp;rsquo;ingénierie. Du &lt;strong>côté optimisation&lt;/strong> : la formulation d&amp;rsquo;un problème multi-objectif, l&amp;rsquo;analyse des compromis de Pareto, la configuration d&amp;rsquo;un algorithme génétique, la gestion des contraintes et la sélection d&amp;rsquo;un profil à partir d&amp;rsquo;un continuum. Du &lt;strong>côté calcul scientifique&lt;/strong> : du code numérique vectorisé, le pilotage fiable d&amp;rsquo;un programme externe à grande échelle, la modélisation par structures de données typées et un traitement rigoureux des échecs, ainsi qu&amp;rsquo;un ensemble cohérent de figures et d&amp;rsquo;animations générées entièrement à partir de l&amp;rsquo;historique d&amp;rsquo;exécution. Et du &lt;strong>côté génie logiciel&lt;/strong> : une base de code en couches, orientée objet, avec des interfaces propres, des tests, la vérification de types, l&amp;rsquo;intégration continue, la documentation et la reproductibilité traitées comme des préoccupations de premier ordre.&lt;/p>
&lt;h2 id="pour-aller-plus-loin">Pour aller plus loin&lt;/h2>
&lt;p>Cette étude de cas se veut aussi une carte d&amp;rsquo;apprentissage. Chaque référence ci-dessous est choisie pour ce qu&amp;rsquo;elle enseigne et pour son lien avec le projet.&lt;/p>
&lt;p>Pour la théorie des profils et l&amp;rsquo;aérodynamique, &lt;em>Theory of Wing Sections&lt;/em> d&amp;rsquo;Abbott et von Doenhoff est la référence classique sur les familles NACA et leur comportement mesuré, et c&amp;rsquo;est l&amp;rsquo;endroit où comprendre exactement ce que signifient les trois nombres de forme. &lt;em>Fundamentals of Aerodynamics&lt;/em> de John D. Anderson est l&amp;rsquo;introduction de référence à la naissance de la portance et de la traînée, au sens des coefficients et à l&amp;rsquo;intervention des nombres de Reynolds et de Mach, c&amp;rsquo;est-à-dire le vocabulaire utilisé tout au long de cette page. Les rapports techniques de la NASA sur la série NACA et les cours d&amp;rsquo;aérodynamique en libre accès sont de bonnes sources de données primaires et de démonstrations.&lt;/p>
&lt;p>Pour le solveur, l&amp;rsquo;article original de Mark Drela sur XFOIL et la &lt;a href="https://web.mit.edu/drela/Public/web/xfoil/" target="_blank" rel="noopener">documentation officielle de XFOIL&lt;/a> expliquent le modèle qui produit chaque nombre de la boucle et le comportement de convergence que la boîte à outils doit gérer.&lt;/p>
&lt;p>Pour l&amp;rsquo;optimisation, l&amp;rsquo;article original sur NSGA-II de Deb et ses collègues introduit les deux idées au cœur de l&amp;rsquo;algorithme utilisé ici, et le livre de Deb &lt;em>Multi-Objective Optimization Using Evolutionary Algorithms&lt;/em> traite des fronts de Pareto et de la prise de décision comme un cadre cohérent. La &lt;a href="https://pymoo.org/" target="_blank" rel="noopener">documentation de pymoo&lt;/a> montre les outils concrets que ce projet configure.&lt;/p>
&lt;p>Pour le calcul scientifique, &lt;em>Numerical Optimization&lt;/em> de Nocedal et Wright explique pourquoi les méthodes par gradient peinent sur les problèmes bruités de type boîte noire et quand les méthodes sans dérivées sont le bon choix, tandis que les documentations &lt;a href="https://numpy.org/doc/" target="_blank" rel="noopener">NumPy&lt;/a> et &lt;a href="https://matplotlib.org/stable/" target="_blank" rel="noopener">Matplotlib&lt;/a> couvrent les schémas numériques et graphiques sur lesquels le code s&amp;rsquo;appuie.&lt;/p>
&lt;h2 id="depot">Dépôt&lt;/h2>
&lt;p>L&amp;rsquo;intégralité du code source, y compris le moteur de géométrie, l&amp;rsquo;enveloppe du solveur, la couche d&amp;rsquo;optimisation, le pipeline de visualisation et la démonstration qui a généré chaque figure de cette page, est open source sous licence MIT.&lt;/p>
&lt;p>Le code se trouve sur &lt;a href="https://github.com/vcaries/airfoil_optimization" target="_blank" rel="noopener">github.com/vcaries/airfoil_optimization&lt;/a>, avec un document d&amp;rsquo;architecture, un guide d&amp;rsquo;utilisation pas à pas et un site de documentation. Toute la galerie se régénère à partir d&amp;rsquo;une seule commande, et un solveur de remplacement intégré permet à quiconque de reproduire les résultats, qu&amp;rsquo;il dispose ou non de XFOIL.&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>Aucune section unique n&amp;rsquo;est optimale au décollage, en croisière et à l&amp;rsquo;atterrissage, car la portance et la traînée sont en conflit direct et chaque phase les pondère différemment. Ce projet répond à cela avec un espace de conception compact et interprétable, un solveur aérodynamique validé évaluant chaque candidat sur une mission pondérée à plusieurs phases, un algorithme génétique cherchant sous de véritables contraintes géométriques et de performance, et une règle explicite pour sélectionner un profil équilibré, le tout dans une boîte à outils Python propre, en couches et reproductible.&lt;/p>
&lt;p>Le résultat est un ensemble de compromis portance-traînée pour chaque phase et pour la mission combinée, des gagnants qui se séparent selon les lignes établies de l&amp;rsquo;aérodynamique, et un profil équilibré qui refuse d&amp;rsquo;être nettement battu où que ce soit, le tout livré sous forme d&amp;rsquo;un récit visuel cohérent. La partie difficile n&amp;rsquo;a jamais été l&amp;rsquo;optimiseur. C&amp;rsquo;était de coupler un vrai solveur externe à une recherche à population de façon que l&amp;rsquo;ensemble reste rapide, continue de tourner même lorsque certaines géométries ne peuvent pas converger, et demeure reproductible, puis de transformer l&amp;rsquo;historique d&amp;rsquo;optimisation en figures à partir desquelles un ingénieur peut raisonner.&lt;/p>
&lt;p>Il reste une large marge pour aller plus loin. La couche du solveur pourrait être remplacée par une simulation à plus haute fidélité ou par un substitut entraîné derrière la même interface ; la paramétrisation NACA pourrait céder la place à une description de forme plus riche, comme les CST ou les B-splines, pour un contrôle plus fin ; une boucle externe ou un modèle de substitution pourrait réduire le nombre d&amp;rsquo;évaluations coûteuses ; et la mission pourrait s&amp;rsquo;étendre pour inclure la robustesse aux conditions hors conception, aux rafales et aux manœuvres. L&amp;rsquo;architecture a été conçue pour que chacune de ces évolutions soit un changement contenu plutôt qu&amp;rsquo;une réécriture, ce qui est le véritable intérêt de traiter l&amp;rsquo;analyse d&amp;rsquo;ingénierie comme du logiciel.&lt;/p></description></item></channel></rss>