Aller au contenu principal

Gap Filling Modules (GFM)

Les Gap Filling Modules sont les éléments constitutifs du moteur de calcul EOS. Chaque module est une unité spécialisée et autonome qui gère un aspect spécifique du calcul d'incidence environnementale.

Que sont les Gap Filling Modules ?

Dans le monde réel, les données sur les produits alimentaires sont souvent incompletes. Un produit peut avoir :

  • Un nom mais pas de liste d'ingrédients
  • Des ingrédients mais pas d'informations sur l'origine
  • Une origine mais pas de détails sur le transport
  • Des données nutritionnelles partielles

Les GFM resolvent ce problème en comblant automatiquement les lacunes dans les données produit à l'aide de modèles scientifiques, de bases de données et de valeurs par défaut intelligentes.

Le concept GFM

4983b38890efe35bf9668dfb86dc7c0a

Chaque GFM se compose de :

  1. Logique de planification - Determine si le module est pertinent pour un noeud donné
  2. Vérification de disponibilité - Vérifie que toutes les dépendances sont satisfaites
  3. Exécution - La logique de calcul qui comble les lacunes et met à jour le graphe

Modules disponibles

EOS comprend 28 GFM spécialisés organisés par fonction :

Modules de correspondance

Font correspondre les noms de produits et ingrédients aux entrées de la base de données :

ModuleObjectif
match_product_name_gfmFait correspondre les noms de produits aux entrées de la base de données
attach_food_tags_gfmAttache les étiquettes de classification alimentaire
link_term_to_activity_node_gfmLie les termes aux activités ACV
link_food_categories_gfmAttribue les catégories alimentaires

Modules de localisation

Gèrent les données géographiques et d'origine :

ModuleObjectif
origin_gfmDetermine l'origine du produit
location_gfmGestion de la localisation géographique
transportation_decision_gfmDetermine les modes de transport
transportation_mode_distance_gfmCalcule les distances de transport

Modules de cycle de vie

Modelisent la transformation et la chaîne d'approvisionnement :

ModuleObjectif
processing_gfmIncidences de la transformation alimentaire
greenhouse_gfmCalculs des gaz à effet de serre
conservation_gfmStockage et conservation
perishability_gfmDurée de conservation et facteurs de perte

Modules d'évaluation de l'incidence

Calculent les métriques environnementales :

ModuleObjectif
impact_assessment_gfmAgrege les calculs d'incidence
water_scarcity_gfmCalcul de l'empreinte hydrique
rainforest_gfmIncidence sur la déforestation
vitascore_gfmScore nutritionnel

Modules d'agrégation

Combinent les résultats entre ingrédients :

ModuleObjectif
aggregation_gfmAgrege les incidences des ingrédients
ingredient_splitter_gfmDecompose les ingrédients composés
ingredient_amount_estimator_gfmEstime les quantités d'ingrédients

Architecture des modules

Chaque GFM suit le patron Factory/Worker :

# Factory - initialise une fois par service, gere les workers
class ExampleGapFillingFactory(AbstractGapFillingFactory):
def __init__(self, postgres_db, service_provider):
super().__init__(postgres_db, service_provider)
self.cache = {} # Cache persistant entre les calculs

async def init_cache(self):
# Charger les donnees requises en memoire
pass

def spawn_worker(self, node):
return ExampleGapFillingWorker(node)

# Worker - cree par noeud, execute le calcul
class ExampleGapFillingWorker(AbstractGapFillingWorker):
def should_be_scheduled(self) -> bool:
# Ce GFM est-il pertinent pour ce noeud ?
return self.node.needs_processing()

def can_run_now(self) -> GapFillingWorkerStatusEnum:
# Les dependances sont-elles satisfaites ?
if self.node.has_required_data():
return GapFillingWorkerStatusEnum.ready
return GapFillingWorkerStatusEnum.reschedule

async def run(self, calc_graph):
# Executer la logique de comblement des lacunes
result = await self.calculate()
self.node.set_property("result", result)

Pourquoi Factory/Worker ?

AvantageDescription
IsolationChaque calcul s'execute dans sa propre instance de worker
Mise en cacheFactory maintient les caches entre les calculs
ÉvolutivitéLes workers peuvent être distribues
TestsLes workers peuvent être testes indépendamment

Orchestration

L'orchestrateur coordonne l'exécution des GFM :

0843e52304130398589902f5d9f555c7

Boucle de planification

  1. Ajout de noeud - Lorsque des noeuds sont ajoutés au CalcGraph, l'orchestrateur crée des workers
  2. Vérification de planification - Le should_be_scheduled() de chaque worker est appele
  3. Vérification de disponibilité - can_run_now() vérifie les dépendances
  4. Exécution - Les workers prets s'executent de manière asynchrone
  5. Mises à jour du graphe - Les résultats sont ecrits dans les propriétés du noeud
  6. Propagation - De nouveaux noeuds peuvent declencher des GFM supplémentaires

Dépendances des modules

Les modules dépendent des sorties d'autres modules :

2e33ab327eeb195a73729de52783aa64

Les dépendances sont résolues automatiquement via la boucle de planification de l'orchestrateur.

Gestion de l'état

Les GFM suivent leur état d'exécution par noeud :

# Etat par noeud stocke dans GfmStateProp (worker_states)
# Les valeurs proviennent de NodeGfmStateEnum : "S" (planifie), "F" (termine), "C" (annule)
gfm_state = {
"MatchProductNameGapFillingWorker": "F", # termine
"OriginGapFillingWorker": "F", # termine
"GreenhouseGapFillingWorker": "S", # planifie (en cours)
"ImpactAssessmentGapFillingWorker": "S" # planifie (en attente)
}

Valeurs d'état

L'état du GFM est suivi à l'aide de NodeGfmStateEnum :

ÉtatCodeDescription
scheduledSLe GFM est planifié pour s'exécuter sur ce noeud
finishedFLe GFM s'est terminé avec succes
canceledCLe GFM a été annule (non applicable ou échec)

Gestion des erreurs

Les GFM implementent une gestion gracieuse des erreurs :

async def run(self, calc_graph):
try:
result = await self.calculate()
self.node.set_property("result", result)
except Exception as e:
# Journaliser l'erreur avec contexte
logger.error("Echec du GFM",
gfm=self.__class__.__name__,
node_uid=self.node.uid,
error=str(e))
# Creer une DataError pour le suivi
error = DataError(
node_uid=self.node.uid,
gfm_name=self.__class__.__name__,
message=str(e),
classification=ErrorClassification.calculation_error
)
self.node.add_error(error)

Stratégie de repli

Lorsqu'un module échoue :

  1. Journaliser l'erreur - Journalisation structurée avec contexte
  2. Créer une DataError - Suivi pour le rapport
  3. Continuer le traitement - Les autres modules peuvent toujours s'exécuter
  4. Signaler l'incertitude - Marquer le résultat avec une confiance réduite

Prochaines étapes