Projet

a marqué ce sujet comme résolu.

Au fait l’objet du projet est de simuler un gaz parfait constitué de molécules. Ces molécules seront introduites dans une enceinte de dimension 3 grâce à un piston. Chaque molécule est une position une vitesse et une énergie et les chocs entre les molécules sont considérés comme élastiques. Le but serait de tester la loi des gaz parfait, d’évaluer la pression et la température.De plus, le programme doit reproduire l’évolution du système avec une animation à 3D. Le programme utilise des objets orientés et des class (pour le piton, pour l’enceinte..) J’ai essayé d’écrire un programme mais j’arrive pas

Bonjour,

Tu peux réaliser ça en simplifiant le problème dans un premier temps. Oublie le piston, si tu veux tester la loi des gaz parfaits en introduisant des particules, contente-toi de les faire apparaitre à un endroit où il y a un trou. Je dis particule, parce qu’une molécule est potentiellement non ronde, ce qui complique énormément le calcul des collisions. Reste sur des boules. Ensuite, reste en 2D dans un premier temps si ça peut t’aider.

Il faut alors faire ta méthode d’intégration du mouvement préférée (Verlet, Leapfrog, etc), pour calculer le déplacement des particules. En cas de rencontre, collision, donc changement de vitesse. Là il y a un piège : tu vas devoir vérifier pour chaque particule si elle est en contact avec toutes les autres. Pour 100 particules, ça marche, pour 100 000, non (calculs à réaliser au carré du nombre de particule). Mais c’est à voir dans un second temps, donc je laisse de côté.

Il faut aussi gérer les collisions aux murs.

Là, tu as une simu en 2D. Pour l’afficher, tu peux exporter la position de toutes tes particules et le donner à un logiciel comme ovito (libre et gratuit). Il marche aussi en 3D, ce qui te permettra d’avoir un affichage 3D sans rien avoir à coder toit-même.

Pour retrouver la loi des gaz parfait, il va falloir appliquer la théorie cinétique des gaz (autopromo), ce qui devrait permettre de retrouver la loi.

Voilà un cadre qui te permettra de savoir où tu vas. N’hésite pas si tu as des questions. ;)

+1 -0

Salut,
Je ne sais pas d’où vient cette contrainte de "faire en C++", mais beaucoup de ces problématiques sont des problématiques communes :

Il faut alors faire ta méthode d’intégration du mouvement préférée (Verlet, Leapfrog, etc), pour calculer le déplacement des particules. En cas de rencontre, collision, donc changement de vitesse. Là il y a un piège : tu vas devoir vérifier pour chaque particule si elle est en contact avec toutes les autres. Pour 100 particules, ça marche, pour 100 000, non (calculs à réaliser au carré du nombre de particule). Mais c’est à voir dans un second temps, donc je laisse de côté.

Il faut aussi gérer les collisions aux murs.

Gabbro

Ce sont des problématiques que l’on retrouve notamment dans les jeux vidéos. Si les jeux vidéos ne requièrent pas le niveau de précision que demande une simulation, avec l’effervescence du marché et la popularité de ces projets, on a déjà quelque chose de plutôt performant dans les moteurs de jeux, probablement plus que ce qu’on pourrait coder dans son coin. À voir si ça te suffit, mais dans tous les cas, pour monter une maquette très rapidement ça pourrait déjà être utile.
Ensuite, si tu veux de la précision plus fine, il faudra regarder la composante qui gère justement cet aspect de simulation de la physique : on appelle ça des moteurs physiques. Leur but est d’être le plus fidèle à la simulation de la physique selon des contraintes de performance. Et certains d’être eux sont destinés aux logiciels de simulation.
Et seulement là, si ça ne suffit toujours pas à être fidèle à ce que tu cherches à simuler, tu pourras te demander ce qui est particulier à ton projet qui fait que ça ne marche pas et tu pourras y apporter des optimisations spécifiques à ta problématique.

tu vas devoir vérifier pour chaque particule si elle est en contact avec toutes les autres. Pour 100 particules, ça marche, pour 100 000, non (calculs à réaliser au carré du nombre de particule).

Gabbro

C’est une première approche naïve, mais il existe probablement des tonnes d’optimisation, à commencer par ne tester que les collisions avec les particules proches, et l’optimisation du calcul spatial qui défini ce que veut dire "proche". Et toutes ces optimisations justement, c’est ce que va t’apporter un moteur physique qui a maturé sur différents projets et besoin, et sur lequel plusieurs cerveaux ont réfléchi, plutôt que refaire de la base et se casser les dents sur chaque étape.


Bref, un post un peu trop long pour simplement dire de ne pas réinventer la roue et utiliser des libs. Mais avec un topic aussi imprécis sur la technique, je crains que ce ne soit pas la voie que tu aies empruntée.

+1 -1

Merci beaucoup pour le message. Comme je l’ai précédemment mentionné, l’objectif de de simuler un gaz parfait en C++ et surtout de suivre l’évolution du système avec le temps. Pourquoi C++? c’est par ce qu’on nous l’enseigne comme UE et il faut donc un projet de fin de semestre

C’est une première approche naïve, mais il existe probablement des tonnes d’optimisation, à commencer par ne tester que les collisions avec les particules proches, et l’optimisation du calcul spatial qui défini ce que veut dire "proche". Et toutes ces optimisations justement, c’est ce que va t’apporter un moteur physique qui a maturé sur différents projets et besoin, et sur lequel plusieurs cerveaux ont réfléchi, plutôt que refaire de la base et se casser les dents sur chaque étape.

J’ai explicitement dis que ce serait à voir dans un second temps. Pour ce cas précis, les meilleurs optimisations sont connus et codables facilement. Pas sûr d’ailleurs qu’un moteur de jeux vidéos soit optimisé pour des simulations discrètes. Les approximations faites en sciences (boule de même taille, pour le cas du gaz) suffisent presque toujours et permettent très facilement une très bonne optimisation. Comme on est clairement dans le cadre d’un projet scolaire, ça se fait.

Au passage, si le but était de ne pas réinventer la roue, il faudrait partir sur Lammps, ou Liggghts, qui sont des logiciels de simulation prévus pour ça, et non pas sur un moteur de jeu vidéo.

+1 -0

J’ai explicitement dis que ce serait à voir dans un second temps.

Gabbro

Pas de soucis avec ça, les optis se font toujours dans un second temps, mais je ne considère pas le fait de choisir une lib adaptée à ce que l’on cherche à faire comme une opti, malgré qu’elle contienne ces optis. C’est juste choisir le bon outil.

Pas sûr d’ailleurs qu’un moteur de jeux vidéos soit optimisé pour des simulations discrètes.

Gabbro

Pas des masses, mais des jeux qui font tourner des milliers d’objets ça existe. C’est ce que je disais, on atteindra vite les limites du moteur de jeu si on veut une vraie simulation, mais ça reste mieux que coder son petit moteur physique et surtout bien plus rapide à mettre en oeuvre. C’est pour ça que je parlais d’une maquette.

Comme on est clairement dans le cadre d’un projet scolaire

Gabbro

Je ne sais pas comment tu l’as deviné, moi, je n’en savais rien lors de ma première réponse.

ça se fait.

Gabbro

ça se fait, mais hors intérêt pédagogique, pourquoi le faire plus mal que la pelletée de projets qui simulent la physique ?

Au passage, si le but était de ne pas réinventer la roue, il faudrait partir sur Lammps, ou Liggghts, qui sont des logiciels de simulation prévus pour ça, et non pas sur un moteur de jeu vidéo.

Gabbro

Cool effectivement, je ne connais pas et ce n’est pas sorti en top result en 2 petites recherches donc je suis passé à côté. (pas mis les bons mot-clefs)

+0 -0

Je ne sais pas comment tu l’as deviné, moi, je n’en savais rien lors de ma première réponse.

Mot clé « Le travail consiste x + langage imposé + simulation physique de base. C’était évident pour moi qu’on était dans le cadre scolaire ou pédagogique.

ça se fait, mais hors intérêt pédagogique, pourquoi le faire plus mal que la pelletée de projets qui simulent la physique ?

J’ai utilisé pour ma thèse des outils très proches. Entre la complexité de prise en charge de ces outils, et la complexité de codage, on est guère éloigné. Et comme pour utiliser correctement ce genre d’outils, il faut le comprendre réellement, on en codait tous un petit mal optimisé un jour ou l’autre. Le seul point compliqué de l’optimisation est la parallélisation.

Autant personne ne recode un logiciel d’éléments finis, autant on avait plusieurs logiciels d’élément discret utilisés en parallèle dans mon labo.

+1 -0

Tu peux poster ton code ou tes résultats ici. Pour le sens physique, il faut calculer la force appliquée sur les parois, en déduire une pression, et, normalement, tu retrouves PV=nRT.PV=nRT. Le volume étant connu, le nombre de particules aussi, et RT une constante (T est souvent considéré comme une constante de simulation dans ce genre de cas).

+0 -0

#include <iostream>
#include <vector>
#include <cmath>
#include <cstdlib>

using namespace std;

const double kb = 1.38e-23; // constante de Boltzmann en J.K^-1

// --------------------------------------------------------------------Classe représentant une molécule
class Molecule {
public:
    
    double x, y, z; // position
    double vx, vy, vz; // vitesse
    double mass ; // masse
    double energie() { // calcul de l'énergie cinétique
        return 0.5 * mass * (vx*vx + vy*vy + vz*vz);
    }
};

//----------------------------------------------------------------------- Classe représentant l'enceinte
class Enceinte {
public:
    double x_min, x_max, y_min, y_max, z_min, z_max; // dimensions
    bool interieur(Molecule m) { // vérifie si la molécule est à l'intérieur de l'enceinte
        return (m.x >= x_min && m.x <= x_max &&
                m.y >= y_min && m.y <= y_max &&
                m.z >= z_min && m.z <= z_max);
    }
};

class Piston {
public:
    double x_min, x_max, y_min, y_max, z_min, z_max; // dimensions
    double mass; // masse
    double vitesse; // vitesse
    double force(double x, double y, double z) { // calcule la force exercée sur le piston par une molécule
        if (x >= x_min && x <= x_max &&
            y >= y_min && y <= y_max &&
            z >= z_min && z <= z_max) {
            return 2 * mass * vitesse / kb;
        } else {
            return 0.0;
        }
    }
    double force_des_molecules(vector<Molecule>& molecules) {////calcule la force exercée sur le piston par l'ensemble des molécules
    double force_som = 0.0;
    for (long i = 0; i < molecules.size(); ++i) {
        force_som += force(molecules[i].x, molecules[i].y, molecules[i].z);
    }
        return force_som;
    }

    double energie_potentiel(Enceinte enceinte) {
        const double g = 9.8;
        const double kr= 10;
        double deplacement = x_max - x_min;
        //energie potentiel élastique  due à la compression ou l'extension (la force exercée par les molécules sur le piston): loi de HOOKE
        double energie_rap= 0.5 * kr * deplacement * deplacement;
        //energie potientiel du à la gravitation due à la position verticale du piston par rapport à la paroi supérieure de l'enceinte
        double energie_gravi = mass * g * (y_max - enceinte.y_max);
        return energie_rap + energie_gravi;
    }

};


int main() {
    const double dt = 1e-15; // pas de temps
    const int Nmolecules = 100; // nombre de molécules
    const double mass = 6.63e-26; // masse d'une molécule d'argon
    const double rayon = 0.5e-10; // rayon d'une molécule d'argon
    const double temperature = 300.0; // température initiale et représente une condition proche de la condition ambiante dans la vie courante.
    const double pression = 1e5; // pression initiale et représente une condition proche de la condition ambiante dans la vie courante.
    const double volume = Nmolecules * kb * temperature / pression; // volume initial
    const double taille = pow(volume, 1.0/3); // taille de l'enceinte
    
    // Initialisation des molécules avec des positions et des vitesses aléatoires
    vector<Molecule> molecules(Nmolecules);
    for (int i = 0; i < Nmolecules; i++) {
        molecules[i].mass = mass;
        molecules[i].x = (double)rand() / RAND_MAX * taille;
        molecules[i].y = (double)rand() / RAND_MAX * taille;
        molecules[i].z = (double)rand() / RAND_MAX * taille;
        //composante vitesse qui suit une distribution gaussienne centrée en 0 et dont l'écart-type est proportionnel à la vitesse quadratique moyenne.
        molecules[i].vx = (2.0 * rand() / RAND_MAX - 1.0) * sqrt(kb * temperature  / molecules[i].mass);
    }

    // Initialisation de l'enceinte
    Enceinte enceinte;
    enceinte.x_min = 0.0;
    enceinte.x_max = taille;
    enceinte.y_min = 0.0;
    enceinte.y_max = taille;
    enceinte.z_min = 0.0;
    enceinte.z_max = taille;

    // Initialisation du piston
    Piston piston;
    piston.x_min = taille / 2 - rayon;
    piston.x_max = taille / 2 + rayon;
    piston.y_min = 0.0;
    piston.y_max = taille;
    piston.z_min = 0.0;
    piston.z_max = taille;
    piston.mass = 10 * mass;
    piston.vitesse = 0.0;
    // Boucle principale de simulation
    const int Npas = 1000;
    for (int pas = 0; pas < Npas; pas++) {
        // Intégration des équations du mouvement en utilisant l'algorithme de Verlet
        for (int i = 0; i < Nmolecules; i++) {
            double ax = 0.0, ay = 0.0, az = 0.0;
            for (int j = 0; j < Nmolecules; j++) {
                if (i != j) {// permet d'éviter de calculer la force exercée par une molécule sur elle-même.
                    double dx = molecules[j].x - molecules[i].x;
                    double dy = molecules[j].y - molecules[i].y;
                    double dz = molecules[j].z - molecules[i].z;
                    double r = sqrt(dx*dx + dy*dy + dz*dz);
                    double f = 24 * (2 * pow(rayon, 12) / pow(r, 13) - pow(rayon, 6) / pow(r, 7));
                    ax += f * dx / molecules[i].mass;
                    ay += f * dy / molecules[i].mass;
                    az += f * dz / molecules[i].mass;
                }
            }
            ax += piston.force(molecules[i].x, molecules[i].y, molecules[i].z) / molecules[i].mass;
            molecules[i].vx += 0.5 * ax * dt;
            molecules[i].x += molecules[i].vx * dt;
            if (!enceinte.interieur(molecules[i])) {
                molecules[i].x = max(molecules[i].x, enceinte.x_min + rayon);
                molecules[i].x = min(molecules[i].x, enceinte.x_max - rayon);
                molecules[i].vx *= -1.0;
            }
            molecules[i].vy += 0.5 * ay * dt;
            molecules[i].y += molecules[i].vy * dt;
            if (!enceinte.interieur(molecules[i])) {
                molecules[i].y = max(molecules[i].y, enceinte.y_min + rayon);
                molecules[i].y = min(molecules[i].y, enceinte.y_max - rayon);
                molecules[i].vy *= -1.0;
            }
            molecules[i].vz += 0.5 * az * dt;
            molecules[i].z += molecules[i].vz * dt;
            if (!enceinte.interieur(molecules[i])) {
                molecules[i].z = max(molecules[i].z, enceinte.z_min + rayon);
                molecules[i].z = min(molecules[i].z, enceinte.z_max - rayon);
                molecules[i].vz *= -1.0;
            }
            ax = ay = az = 0.0;
            for (int j = 0; j < Nmolecules; j++) {
                if (i != j) {
                    double dx = molecules[j].x - molecules[i].x;
                    double dy = molecules[j].y - molecules[i].y;
                    double dz = molecules[j].z - molecules[i].z;
                    double r = sqrt(dx*dx + dy*dy + dz*dz);
                    double f = 24 * (2 * pow(rayon, 12) / pow(r, 13) - pow(rayon, 6) / pow(r, 7));
                    ax += f * dx / molecules[i].mass;
                    ay += f * dy / molecules[i].mass;
                    az += f * dz / molecules[i].mass;
                }
            }
            ax += piston.force(molecules[i].x, molecules[i].y, molecules[i].z) / molecules[i].mass;
            molecules[i].vx += 0.5 * ax * dt;
            molecules[i].vy += 0.5 * ay * dt;
            molecules[i].vz += 0.5 * az * dt;
        }
        // Intégration des équations du mouvement pour le piston
        double piston_ax = piston.force_des_molecules(molecules) / piston.mass;
        piston.vitesse += 0.5 * piston_ax * dt;
        piston.x_min += piston.vitesse * dt;
        piston.x_max += piston.vitesse * dt;
        if (piston.x_min < enceinte.x_min) {
            double penetration = enceinte.x_min - piston.x_min;
            piston.vitesse += 2 * piston_ax * penetration / piston.mass;
            piston.x_min = enceinte.x_min;
            piston.x_max = enceinte.x_min + 2 * rayon;
        }
        if (piston.x_max > enceinte.x_max) {
            double penetration = piston.x_max - enceinte.x_max;
            piston.vitesse += 2 * piston_ax * penetration / piston.mass;
            piston.x_max = enceinte.x_max;
            piston.x_min = enceinte.x_max - 2 * rayon;
        }
           // Calcul de la pression et de la température
        double energie_cinetique = 0.0;
        double moment_x = 0.0, moment_y = 0.0, moment_z = 0.0;
        for (int i = 0; i < Nmolecules; i++) {
            energie_cinetique += 0.5 * molecules[i].mass * (pow(molecules[i].vx, 2) + pow(molecules[i].vy, 2) + pow(molecules[i].vz, 2));
            moment_x += molecules[i].mass * molecules[i].vx;
            moment_y += molecules[i].mass * molecules[i].vy;
            moment_z += molecules[i].mass * molecules[i].vz;
        }
        double total_energy = energie_cinetique + piston.energie_potentiel(enceinte);
        double temperature = 2.0 / (3.0 * kb * Nmolecules) * energie_cinetique;
        double pression = Nmolecules / (volume * kb * temperature) * (moment_x / taille   + moment_y / taille+ moment_z / taille)+ piston.force_des_molecules(molecules) / (volume * kb* temperature);
         if (pas % 100 == 0) {
            
            cout<<energie_cinetique<<" "<<pression<<endl;

            
         }

    }
    return 0;
}




+0 -0

Je me suis permis de remettre en forme ton code pour qu’il soit lisible.

Sinon, que cherches-tu à calculer ? Tu ne peux pas calculer la pression en utilisant la loi des gaz parfait si tu veux la démontrer, je ne comprends pas pourquoi tu mets les quantités de mouvements (que tu appelles moment, mais je pense que tu as confondu deux trucs) dans la pression. Celle-ci devrait se calculer à partir des forces exercées sur la boite.

Et pour retrouver la loi, tu fais varier le nombre de particules, et tu dois retrouver une relation de proportionnalité. D’ailleurs, si tu simules un état stable, tes chiffres ne devraient pas varier au cours de la simu. Mais comme tu simules 1000 pas de temps de 10-15 secondes, va savoir si c’est stable ou pas…

Et je ne vois pas où tu calcules les collisions entre particules, mais je suis peut-être juste passé à côté.

PS : une solution courante pour vérifier si une simulation est bonne est de calculer l’énergie totale dans le système. Si tu n’injectes pas d’énergie, ce doit être une constante. Si ce n’est pas le cas, soit tu as des problèmes de simulation (mauvaise intégration, pas de temps trop grand…), soit tu calcules mal tes énergies. Mais quelque chose cloche.

PPS : quel niveau scolaire as-tu ?

+0 -0

je suis en licence physique.

je voulais vérifier la loi des gaz parfait en calculant dans un premier temps la température ainsi que la pression. Le problème pour le moment est que j’obtiens que des valeurs assez grandes pour ces paramètres.

voici ce que j’obtiens pour l’énergie cinétique, la pression et l’énergie totale par exemple : 7.74144e-016 -2.90053e+029 7.74194e-016 1.99773e-015 2.21363e+030 1.99778e-015 2.06923e-015 -3.68084e+030 2.06928e-015 2.04902e-015 -4.74552e+030 2.04907e-015 2.048e-015 -5.04441e+030 2.04805e-015 1.94367e-015 -2.77196e+030 1.94372e-015 2.03272e-015 5.92953e+029 2.03277e-015 2.03875e-015 3.6956e+030 2.0388e-015 2.08121e-015 1.72324e+030 2.08126e-015 2.06189e-015 9.80151e+029 2.06194e-015

Pour la pression, j’ai utilisé la formule de viriel

effectivement, j’ai pas effectuer le calcul pour les collisions. je vais l’ajouter

Salut,

effectivement, j’ai pas effectuer le calcul pour les collisions. je vais l’ajouter

Une considération physique en passant, parce que je vois beaucoup d’excitation sur les collisions dans cette discussion… Un gaz parfait considère des particules ponctuelles sans interactions. À moins que tu aies des instructions qui demandent explicitement de considérer les collisions entre particules, tu peux complètement ignorer cet aspect du problème ainsi que le rayon des particules.

+2 -0

La première chose à faire quand on a une simu est de vérifier qu’elle est juste. Deux grands principes : si tu cherches un état stable, il ne doit pas évoluer dans le temps. Donc, ton résultat doit converger. Ce n’est pas le cas. Tu as aussi la constance de l’énergie.

Pour ton calcul de la pression via le Viriel, tu as fait une erreur dans la formule. Tu dois avoir une formule en P=NkTV(1+X),P = \frac{N k T}{V} ( 1 + X), avec le développement dans le XX. Il te manque le terme proportionnel. Dans un premier temps, je te recommande de ne garder que l’équation des gaz parfait PV=NkT,PV = NkT, qui suffit tant que ton milieu est peu dense.

Mais si tu fais ça, tu n’es pas en train de simuler la loi des gaz parfait, mais de l’appliquer, puisque VV, nn, et TT sont des paramètres d’entrée ! Tu dois calculer la pression appliquée sur les parois par le choc des particules, et comparer à la formule.

+1 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte