Spaces:
Sleeping
Sleeping
| import numpy as np | |
| from scipy.integrate import odeint | |
| import emcee | |
| import panel as pn | |
| import param | |
| import plotly.graph_objects as go | |
| from plotly.subplots import make_subplots | |
| import plotly.io as pio | |
| # Définition du thème sombre | |
| pio.templates.default = "plotly_dark" | |
| # Initialiser l'extension Panel | |
| pn.extension('katex', 'mathjax', 'plotly') | |
| # Informations personnelles | |
| photo_url = "PPFB.png" | |
| prenom = "Yaya" | |
| nom = "Toure" | |
| email = "yaya.toure@unchk.edu.sn" | |
| whatsapps_url = "https://wa.me/message/GW7RWRW3GR4WN1" | |
| linkedin_url = "https://www.linkedin.com/in/yaya-toure-8251a4280/" | |
| github_url = "https://github.com/CodingYayaToure" | |
| universite = "UNCHK" | |
| formation = "Licence Analyse Numerique et Modelisation | Master Calcul scientifique et Modelisation" | |
| certificat = "Collecte et Fouille de Donnees (UADB-CNAM Paris)" | |
| TP_Scilab = "https://codingyayatoure.github.io/Equation_de_Transport_en_1D_par_la_Methode_des_Differences_Finis/" | |
| # Créer le template du tableau de bord | |
| template = pn.template.ReactTemplate(title='Progiciel de Simulation des Interactions Microbiennes en Fermentation de Jus de Légumes. | Approche Modélisation mathématique ') | |
| # Classe pour la dynamique Consumer-Resource | |
| class ConsumerResourceApp(param.Parameterized): | |
| # Paramètres du modèle | |
| r = param.Number(10.0, bounds=(0.1, 20.0), step=0.1, doc="Taux d'approvisionnement en ressources") | |
| d = param.Number(0.1, bounds=(0.01, 1.0), step=0.01, doc="Taux de mortalité des consommateurs") | |
| c = param.Number(0.1, bounds=(0.01, 1.0), step=0.01, doc="Coefficient de consommation") | |
| K = param.Number(1.0, bounds=(0.1, 10.0), step=0.1, doc="Concentration à laquelle la croissance est à moitié maximale") | |
| X0 = param.Number(1.0, bounds=(0.1, 10.0), step=0.1, doc="Population initiale des consommateurs") | |
| S0 = param.Number(5.0, bounds=(0.1, 20.0), step=0.1, doc="Concentration initiale de la ressource") | |
| def view(self): | |
| # Fonction de croissance dépendante de la ressource (Monod) | |
| def mu(S): | |
| return S / (self.K + S) | |
| # Équations différentielles | |
| def model(y, t): | |
| X, S = y | |
| dXdt = mu(S) * X - self.d * X # Dynamique des consommateurs | |
| dSdt = self.r - self.c * mu(S) * X # Dynamique des ressources | |
| return [dXdt, dSdt] | |
| # Conditions initiales | |
| y0 = [self.X0, self.S0] | |
| # Temps pour la simulation (en heures) | |
| t_hours = np.linspace(0, 100, 500) | |
| # Résoudre le système d'équations différentielles | |
| solution = odeint(model, y0, t_hours) | |
| # Créer les graphiques avec Plotly en utilisant des sous-graphiques | |
| fig = make_subplots( | |
| rows=1, cols=3, | |
| specs=[[{'type': 'scatter'}, {'type': 'scatter'}, {'type': 'scatter'}]], | |
| subplot_titles=["Population des Consommateurs (X)", "Concentration de la Ressource (S)", "Population et Ressource sur le même repère"] | |
| ) | |
| # Ajouter la trace pour les consommateurs | |
| fig.add_trace(go.Scatter(x=t_hours, y=solution[:, 0], mode='lines', name='Population des Consommateurs (X)', line=dict(color='blue')), row=1, col=1) | |
| # Ajouter la trace pour les ressources | |
| fig.add_trace(go.Scatter(x=t_hours, y=solution[:, 1], mode='lines', name='Concentration de la Ressource (S)', line=dict(color='green')), row=1, col=2) | |
| # Ajouter la trace pour les consommateurs et les ressources sur le même graphique | |
| fig.add_trace(go.Scatter(x=t_hours, y=solution[:, 0], mode='lines', name='Population des Consommateurs (X)', line=dict(color='blue')), row=1, col=3) | |
| fig.add_trace(go.Scatter(x=t_hours, y=solution[:, 1], mode='lines', name='Concentration de la Ressource (S)', line=dict(color='green')), row=1, col=3) | |
| # Mettre à jour la mise en page du graphique | |
| fig.update_layout( | |
| title='Dynamique du Modèle Consumer-Resource', | |
| xaxis_title='Temps', | |
| yaxis_title='Population / Concentration', | |
| legend_title='Légende', | |
| height=400, | |
| width=1500, | |
| font_color="white", | |
| template='plotly_dark' | |
| ) | |
| return pn.pane.Plotly(fig) | |
| def panel_view(self): | |
| return pn.Column( | |
| pn.Row(pn.Param(self, width=400), self.formulas()), # Aligner les widgets et les formules sur la même ligne | |
| self.view # Appeler la vue pour qu'elle se mette à jour dynamiquement | |
| ) | |
| def formulas(self): | |
| return pn.Column( | |
| pn.pane.LaTeX(r""" | |
| $$ | |
| \text{Fonction de croissance : } \mu(S) = \frac{S}{K + S} | |
| $$ | |
| """, styles={'font-size': '16pt'}), | |
| pn.pane.LaTeX(r""" | |
| $$ | |
| \text{Dynamique des consommateurs : } \frac{dX}{dt} = \mu(S) \times X - d \times X | |
| $$ | |
| """, styles={'font-size': '16pt'}), | |
| pn.pane.LaTeX(r""" | |
| $$ | |
| \text{Dynamique des ressources : } \frac{dS}{dt} = r - c \times \mu(S) \times X | |
| $$ | |
| """, styles={'font-size': '16pt'}) | |
| ) | |
| # Classe pour la dynamique des populations microbiennes | |
| class MicrobialDynamicsApp(param.Parameterized): | |
| # Paramètres du modèle pour la dynamique des populations microbiennes | |
| r1 = param.Number(0.5, bounds=(0.1, 1.0), step=0.01, doc="Taux de croissance espèce 1") | |
| r2 = param.Number(0.3, bounds=(0.1, 1.0), step=0.01, doc="Taux de croissance espèce 2") | |
| K1 = param.Number(100, bounds=(10, 200), step=1, doc="Capacité de charge espèce 1") | |
| K2 = param.Number(80, bounds=(10, 200), step=1, doc="Capacité de charge espèce 2") | |
| alpha = param.Number(0.01, bounds=(0.001, 0.1), step=0.001, doc="Compétition espèce 2 sur espèce 1") | |
| beta = param.Number(0.01, bounds=(0.001, 0.1), step=0.001, doc="Compétition espèce 1 sur espèce 2") | |
| def view(self): | |
| # Équations différentielles pour les populations microbiennes | |
| def model(y, t): | |
| X1, X2 = y | |
| dX1dt = self.r1 * X1 * (1 - (X1 + self.alpha * X2) / self.K1) | |
| dX2dt = self.r2 * X2 * (1 - (X2 + self.beta * X1) / self.K2) | |
| return [dX1dt, dX2dt] | |
| # Conditions initiales | |
| y0 = [10, 5] # Population initiale des deux espèces | |
| # Temps pour la simulation | |
| t = np.linspace(0, 50, 500) | |
| # Résoudre le système d'équations différentielles | |
| solution = odeint(model, y0, t) | |
| # Créer le graphique avec Plotly | |
| fig = go.Figure() | |
| fig.add_trace(go.Scatter(x=t, y=solution[:, 0], mode='lines', name='Espèce 1', line=dict(color='red'))) | |
| fig.add_trace(go.Scatter(x=t, y=solution[:, 1], mode='lines', name='Espèce 2', line=dict(color='purple'))) | |
| # Mettre à jour la mise en page du graphique | |
| fig.update_layout( | |
| title='Dynamique des Populations Microbiennes', | |
| xaxis_title='Temps', | |
| yaxis_title='Population', | |
| legend_title='Légende', | |
| height=400, | |
| width=1500, | |
| font_color="white", | |
| template='plotly_dark' | |
| ) | |
| return pn.pane.Plotly(fig) | |
| def panel_view(self): | |
| return pn.Column( | |
| pn.Row(pn.Param(self, width=400), self.formulas()), # Aligner les widgets et les formules sur la même ligne | |
| self.view # Appeler la vue pour qu'elle se mette à jour dynamiquement | |
| ) | |
| def formulas(self): | |
| return pn.Column( | |
| pn.pane.LaTeX(r""" | |
| $$ | |
| \frac{{dX_1}}{{dt}} = r_1 X_1 \left( 1 - \frac{{X_1 + \alpha X_2}}{{K_1}} \right) | |
| $$ | |
| """, styles={'font-size': '16pt'}), | |
| pn.pane.LaTeX(r""" | |
| $$ | |
| \frac{{dX_2}}{{dt}} = r_2 X_2 \left( 1 - \frac{{X_2 + \beta X_1}}{{K_2}} \right) | |
| $$ | |
| """, styles={'font-size': '16pt'}) | |
| ) | |
| # Classe pour la modélisation de la fermentation | |
| class FermentationModelApp(param.Parameterized): | |
| # Paramètres du modèle de fermentation | |
| mu_max = param.Number(0.8, bounds=(0.1, 2.0), step=0.1, doc="Taux de croissance maximal") | |
| Ks = param.Number(10.0, bounds=(1.0, 50.0), step=1.0, doc="Constante de demi-saturation") | |
| Yxs = param.Number(0.5, bounds=(0.1, 1.0), step=0.1, doc="Rendement de croissance sur substrat") | |
| Sin = param.Number(20.0, bounds=(10.0, 100.0), step=1.0, doc="Concentration initiale en substrat") | |
| X0 = param.Number(0.1, bounds=(0.01, 5.0), step=0.01, doc="Concentration initiale en biomasse") | |
| P0 = param.Number(0.0, bounds=(0.0, 5.0), step=0.1, doc="Concentration initiale en produit") | |
| def view(self): | |
| # Équations différentielles pour la fermentation | |
| def model(y, t): | |
| X, S, P = y | |
| mu = self.mu_max * S / (self.Ks + S) | |
| dXdt = mu * X | |
| dSdt = -dXdt / self.Yxs | |
| dPdt = 0.1 * dXdt # Production de produit proportionnelle à la croissance | |
| return [dXdt, dSdt, dPdt] | |
| # Conditions initiales | |
| y0 = [self.X0, self.Sin, self.P0] | |
| # Temps pour la simulation | |
| t = np.linspace(0, 50, 500) | |
| # Résoudre le système d'équations différentielles | |
| solution = odeint(model, y0, t) | |
| # Créer le graphique avec Plotly | |
| fig = go.Figure() | |
| fig.add_trace(go.Scatter(x=t, y=solution[:, 0], mode='lines', name='Biomasse (X)', line=dict(color='blue'))) | |
| fig.add_trace(go.Scatter(x=t, y=solution[:, 1], mode='lines', name='Substrat (S)', line=dict(color='green'))) | |
| fig.add_trace(go.Scatter(x=t, y=solution[:, 2], mode='lines', name='Produit (P)', line=dict(color='orange'))) | |
| # Mettre à jour la mise en page du graphique | |
| fig.update_layout( | |
| title='Modélisation de la Fermentation', | |
| xaxis_title='Temps', | |
| yaxis_title='Concentration', | |
| legend_title='Légende', | |
| height=400, | |
| width=1500, | |
| font_color="white", | |
| template='plotly_dark' | |
| ) | |
| return pn.pane.Plotly(fig) | |
| def formulas(self): | |
| return pn.Column( | |
| pn.pane.LaTeX(r""" | |
| $$ | |
| \mu = \frac{{\mu_{{\text{{max}}}} \cdot S}}{{K_s + S}} | |
| $$ | |
| """, styles={'font-size': '16pt'}), | |
| pn.pane.LaTeX(r""" | |
| $$ | |
| \frac{{dX}}{{dt}} = \mu \cdot X | |
| $$ | |
| """, styles={'font-size': '16pt'}), | |
| pn.pane.LaTeX(r""" | |
| $$ | |
| \frac{{dS}}{{dt}} = -\frac{1}{{Y_{{xs}}}} \cdot \frac{{dX}}{{dt}} | |
| $$ | |
| """, styles={'font-size': '16pt'}), | |
| pn.pane.LaTeX(r""" | |
| $$ | |
| \frac{{dP}}{{dt}} = 0.1 \cdot \frac{{dX}}{{dt}} | |
| $$ | |
| """, styles={'font-size': '16pt'}) | |
| ) | |
| def panel_view(self): | |
| return pn.Column( | |
| pn.Row(pn.Param(self, width=400), self.formulas()), # Aligner les widgets et les formules sur la même ligne | |
| self.view # Appeler la vue pour qu'elle se mette à jour dynamiquement | |
| ) | |
| # Classe pour l'estimation des paramètres par MCMC | |
| class EstimationParametresFermentation(param.Parameterized): | |
| # Paramètres pour l'estimation MCMC | |
| n_marcheurs = param.Integer(32, bounds=(10, 100), doc="Nombre de marcheurs MCMC") | |
| n_etapes = param.Integer(1000, bounds=(100, 5000), doc="Nombre d'étapes MCMC") | |
| niveau_bruit = param.Number(0.1, bounds=(0.01, 0.5), doc="Niveau de bruit dans les données synthétiques") | |
| def __init__(self, **params): | |
| super().__init__(**params) | |
| self.parametres_reels = { | |
| 'mu_max': 0.8, | |
| 'Ks': 10.0, | |
| 'Yxs': 0.5 | |
| } | |
| def generer_donnees_synthetiques(self, t): | |
| def modele(y, t, mu_max, Ks, Yxs): | |
| X, S, P = y | |
| mu = mu_max * S / (Ks + S) | |
| dXdt = mu * X | |
| dSdt = -dXdt / Yxs | |
| dPdt = 0.1 * dXdt | |
| return [dXdt, dSdt, dPdt] | |
| y0 = [0.1, 20.0, 0.0] | |
| solution = odeint(modele, y0, t, args=(self.parametres_reels['mu_max'], self.parametres_reels['Ks'], self.parametres_reels['Yxs'])) | |
| bruit = np.random.normal(0, self.niveau_bruit, solution.shape) | |
| return solution + bruit | |
| def log_vraisemblance(self, theta, t, donnees): | |
| mu_max, Ks, Yxs = theta | |
| def modele(y, t, mu_max, Ks, Yxs): | |
| X, S, P = y | |
| mu = mu_max * S / (Ks + S) | |
| dXdt = mu * X | |
| dSdt = -dXdt / Yxs | |
| dPdt = 0.1 * dXdt | |
| return [dXdt, dSdt, dPdt] | |
| y0 = [0.1, 20.0, 0.0] | |
| try: | |
| solution = odeint(modele, y0, t, args=(mu_max, Ks, Yxs)) | |
| sigma2 = self.niveau_bruit ** 2 | |
| return -0.5 * np.sum((donnees - solution) ** 2 / sigma2 + np.log(2 * np.pi * sigma2)) | |
| except: | |
| return -np.inf | |
| def log_apriori(self, theta): | |
| mu_max, Ks, Yxs = theta | |
| if 0.1 < mu_max < 2.0 and 1.0 < Ks < 50.0 and 0.1 < Yxs < 1.0: | |
| return 0.0 | |
| return -np.inf | |
| def log_probabilite(self, theta, t, donnees): | |
| lp = self.log_apriori(theta) | |
| if not np.isfinite(lp): | |
| return -np.inf | |
| return lp + self.log_vraisemblance(theta, t, donnees) | |
| def lancer_mcmc(self): | |
| t = np.linspace(0, 50, 50) | |
| donnees = self.generer_donnees_synthetiques(t) | |
| ndim = 3 | |
| pos = [ | |
| [self.parametres_reels['mu_max'], self.parametres_reels['Ks'], self.parametres_reels['Yxs']] + 1e-4 * np.random.randn(ndim) | |
| for i in range(self.n_marcheurs) | |
| ] | |
| sampler = emcee.EnsembleSampler(self.n_marcheurs, ndim, self.log_probabilite, args=(t, donnees)) | |
| sampler.run_mcmc(pos, self.n_etapes, progress=True) | |
| return sampler, t, donnees | |
| def vue(self): | |
| sampler, t, donnees = self.lancer_mcmc() | |
| fig = make_subplots(rows=2, cols=2, | |
| subplot_titles=('Chaînes MCMC', 'Distribution postérieure', 'Ajustement du modèle', 'Corrélations des paramètres')) | |
| echantillons = sampler.get_chain() | |
| # Tracer les chaînes MCMC | |
| for i in range(3): | |
| fig.add_trace(go.Scatter(y=echantillons[:, 0, i], mode='lines', name=f'Paramètre {i+1}'), row=1, col=1) | |
| echantillons_plats = sampler.get_chain(discard=100, thin=15, flat=True) | |
| # Tracer les distributions postérieures | |
| for i in range(3): | |
| fig.add_trace(go.Histogram(x=echantillons_plats[:, i], name=f'Paramètre {i+1}', nbinsx=30), row=1, col=2) | |
| params_med = np.median(echantillons_plats, axis=0) | |
| y0 = [0.1, 20.0, 0.0] | |
| # Définir une fonction de modèle pour odeint | |
| def modele(y, t): | |
| mu_max, Ks, Yxs = params_med | |
| X, S, P = y | |
| mu = mu_max * S / (Ks + S) | |
| dXdt = mu * X | |
| dSdt = -dXdt / Yxs | |
| dPdt = 0.1 * dXdt | |
| return [dXdt, dSdt, dPdt] | |
| # Utiliser la fonction de modèle dans odeint | |
| solution = odeint(modele, y0, t) | |
| fig.add_trace(go.Scatter(x=t, y=donnees[:, 0], mode='markers', name='Données (X)', marker=dict(color='blue')), row=2, col=1) | |
| fig.add_trace(go.Scatter(x=t, y=solution[:, 0], mode='lines', name='Modèle (X)', line=dict(color='red')), row=2, col=1) | |
| # Tracer les corrélations des paramètres | |
| fig.add_trace(go.Scatter(x=echantillons_plats[:, 0], y=echantillons_plats[:, 1], | |
| mode='markers', marker=dict(size=2), | |
| name='mu_max vs Ks'), row=2, col=2) | |
| fig.update_layout(height=400, width=1200, | |
| showlegend=True, | |
| template='plotly_dark') | |
| return pn.pane.Plotly(fig) | |
| def vue_panneau(self): | |
| return pn.Column( | |
| pn.Row( | |
| pn.Param(self.param, | |
| widgets={ | |
| 'n_marcheurs': pn.widgets.IntSlider, | |
| 'n_etapes': pn.widgets.IntSlider, | |
| 'niveau_bruit': pn.widgets.FloatSlider}), | |
| self.description_mcmc() | |
| ), | |
| self.vue # Correction pour supprimer '()' et référencer dynamiquement | |
| ) | |
| def description_mcmc(self): | |
| return pn.pane.Markdown(""" | |
| # Estimation des paramètres par MCMC | |
| ## Cette section permet d'estimer les paramètres du modèle de fermentation en utilisant l'algorithme MCMC (Markov Chain Monte Carlo). | |
| - ## **n_marcheurs**: Nombre de chaînes MCMC parallèles. | |
| - ## **n_etapes**: Nombre d'itérations pour chaque chaîne. | |
| - ## **niveau_bruit**: Niveau de bruit dans les données synthétiques. | |
| ## Les graphiques montrent: | |
| ### 1. L'évolution des chaînes MCMC. | |
| ### 2. Les distributions postérieures des paramètres. | |
| ### 3. L'ajustement du modèle aux données. | |
| ### 4. Les corrélations entre les paramètres. | |
| """) | |
| # Informations personnelles et photo | |
| photo = pn.pane.PNG(photo_url, width=200, height=200) | |
| info = pn.Column( | |
| pn.pane.Markdown(f"<div style='font-size:16px'><strong>Prénom</strong>: {prenom}</div>"), | |
| pn.pane.Markdown(f"<div style='font-size:16px'><strong>Nom</strong>: {nom}</div>"), | |
| pn.pane.Markdown(f"<div style='font-size:16px'><strong>Email</strong>: <a href='mailto:{email}'>{email}</a></div>"), | |
| #pn.pane.Markdown(f"<div style='font-size:16px'><strong>WhatsApp</strong>: <a href='{whatsapps_url}'>WhatsApp</a></div>"), | |
| #pn.pane.Markdown(f"<div style='font-size:16px'><strong>LinkedIn</strong>: <a href='{linkedin_url}'>LinkedIn</a></div>"), | |
| # pn.pane.Markdown(f"<div style='font-size:16px'><strong>GitHub</strong>: <a href='{github_url}'>GitHub</a></div>"), | |
| pn.pane.Markdown(f"<div style='font-size:16px'><strong>Université</strong>: {universite}</div>"), | |
| pn.pane.Markdown(f"<div style='font-size:16px'><strong>Formation</strong>: {formation}</div>"), | |
| pn.pane.Markdown(f"<div style='font-size:16px'><strong>Certificat</strong>: {certificat}</div>"), | |
| pn.pane.Markdown(f"<div style='font-size:16px'><strong>Autre Projet </strong>: <a href='{TP_Scilab}'>Pour comprendre l'équation de Transport en 1D avec Scilab</a></div>"), | |
| sizing_mode='stretch_width' | |
| ) | |
| # Créer les applications | |
| consumer_app = ConsumerResourceApp() | |
| microbial_app = MicrobialDynamicsApp() | |
| ferm_app = FermentationModelApp() | |
| # Créer l'application | |
| application_estimation_parametres = EstimationParametresFermentation() | |
| # Afficher l'application Panel | |
| #template = pn.template.ReactTemplate(title='Estimation des paramètres par MCMC') | |
| #template.main[0, 0] = application_estimation_parametres.vue_panneau() | |
| # Créer la mise en page | |
| layout = pn.Row( | |
| pn.Column(photo, info, width=300), # Ajouter la photo et les informations personnelles à gauche | |
| pn.Column( | |
| pn.Tabs( | |
| ('Consumer-Resource Dynamics', consumer_app.panel_view()), | |
| ('Microbial Dynamics', microbial_app.panel_view()), | |
| (' Fermentation', ferm_app.panel_view()), | |
| ('Estimation Parametres', application_estimation_parametres.vue_panneau()) | |
| ) | |
| ) | |
| ) | |
| # Ajouter le layout au template principal | |
| template.main[0, 0] = layout | |
| # Exécuter l'application | |
| template.servable() | |