Skip to content

ADR-024: CLARISSA Core System Architecture

Status Proposed
Date 2026-01-22
Authors Wolfram Laube, Claude (AI Assistant)
Supersedes -
Related ADR-021 (Portal System), ADR-011 (OPM Flow Integration)

Context

CLARISSA is a Conversational AI System for Reservoir Simulation. The previous ADRs (021-023) describe the Admin Portal. This ADR defines the Core System Architecture - the actual heart of the system.

Anforderungen

  1. Modular Microservices: Independently deployable, scalable
  2. Flexible Kommunikation: REST (extern), gRPC (intern), Message Broker (async)
  3. Simulator-Agnostic: Abstraction layer for OPM Flow, MRST, (later: commercial)
  4. Service Clustering: Related microservices grouped together

Decision

High-Level Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                              CLARISSA Core System                                โ”‚
โ”‚                                                                                  โ”‚
โ”‚  โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•    โ”‚
โ”‚                              External Interface                                  โ”‚
โ”‚  โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•    โ”‚
โ”‚                                                                                  โ”‚
โ”‚      Web UI          Voice API         REST API         gRPC API                โ”‚
โ”‚         โ”‚                โ”‚                 โ”‚                โ”‚                   โ”‚
โ”‚         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                   โ”‚
โ”‚                                   โ”‚                                              โ”‚
โ”‚                                   โ–ผ                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚                         API Gateway / BFF                                   โ”‚ โ”‚
โ”‚  โ”‚                                                                             โ”‚ โ”‚
โ”‚  โ”‚   โ€ข Routing & Load Balancing                                               โ”‚ โ”‚
โ”‚  โ”‚   โ€ข Authentication / Authorization                                          โ”‚ โ”‚
โ”‚  โ”‚   โ€ข Rate Limiting                                                          โ”‚ โ”‚
โ”‚  โ”‚   โ€ข Protocol Translation (REST โ†” gRPC)                                     โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚                                   โ”‚                                              โ”‚
โ”‚  โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•    โ”‚
โ”‚                              Service Clusters                                    โ”‚
โ”‚  โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•    โ”‚
โ”‚                                   โ”‚                                              โ”‚
โ”‚         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                   โ”‚
โ”‚         โ”‚                         โ”‚                         โ”‚                   โ”‚
โ”‚         โ–ผ                         โ–ผ                         โ–ผ                   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”             โ”‚
โ”‚  โ”‚ Conversationโ”‚          โ”‚ Simulation  โ”‚          โ”‚  Analysis   โ”‚             โ”‚
โ”‚  โ”‚   Cluster   โ”‚โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚   Cluster   โ”‚โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚   Cluster   โ”‚             โ”‚
โ”‚  โ”‚             โ”‚  gRPC /  โ”‚             โ”‚  gRPC /  โ”‚             โ”‚             โ”‚
โ”‚  โ”‚             โ”‚  Events  โ”‚             โ”‚  Events  โ”‚             โ”‚             โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜          โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜          โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜             โ”‚
โ”‚                                   โ”‚                                              โ”‚
โ”‚  โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•    โ”‚
โ”‚                         Simulator Abstraction Layer                              โ”‚
โ”‚  โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•    โ”‚
โ”‚                                   โ”‚                                              โ”‚
โ”‚                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                              โ”‚
โ”‚                    โ”‚              โ”‚              โ”‚                              โ”‚
โ”‚                    โ–ผ              โ–ผ              โ–ผ                              โ”‚
โ”‚             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                         โ”‚
โ”‚             โ”‚ OPM Flow โ”‚   โ”‚   MRST   โ”‚   โ”‚  Future  โ”‚                         โ”‚
โ”‚             โ”‚ Adapter  โ”‚   โ”‚ Adapter  โ”‚   โ”‚ Adapters โ”‚                         โ”‚
โ”‚             โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                         โ”‚
โ”‚                                                                                  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Service Clusters

Prinzip: Bounded Context

Microservices that belong together functionally are grouped into Clusters: - Innerhalb eines Clusters: Message Broker (Tight Coupling OK) - Between Clusters: gRPC or Events (Loose Coupling) - Externally: REST API via Gateway

Cluster 1: Conversation

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    Conversation Cluster                          โ”‚
โ”‚                                                                  โ”‚
โ”‚   Verantwortung: NLP, Dialog Management, User Intent             โ”‚
โ”‚                                                                  โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”‚
โ”‚   โ”‚ NLP Parser  โ”‚   โ”‚   Intent    โ”‚   โ”‚   Dialog    โ”‚          โ”‚
โ”‚   โ”‚             โ”‚โ”€โ”€โ–บโ”‚ Classifier  โ”‚โ”€โ”€โ–บโ”‚  Manager    โ”‚          โ”‚
โ”‚   โ”‚ โ€ข Tokenize  โ”‚   โ”‚             โ”‚   โ”‚             โ”‚          โ”‚
โ”‚   โ”‚ โ€ข NER       โ”‚   โ”‚ โ€ข Classify  โ”‚   โ”‚ โ€ข State     โ”‚          โ”‚
โ”‚   โ”‚ โ€ข Parse     โ”‚   โ”‚ โ€ข Params    โ”‚   โ”‚ โ€ข Response  โ”‚          โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜          โ”‚
โ”‚                                                                  โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                             โ”‚
โ”‚   โ”‚  Context    โ”‚   โ”‚   Session   โ”‚                             โ”‚
โ”‚   โ”‚   Store     โ”‚   โ”‚   Manager   โ”‚                             โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                             โ”‚
โ”‚                                                                  โ”‚
โ”‚   Exposed gRPC:                                                  โ”‚
โ”‚   โ€ข ProcessUtterance(text) โ†’ Intent + Entities                  โ”‚
โ”‚   โ€ข GetDialogState(session_id) โ†’ State                          โ”‚
โ”‚   โ€ข GenerateResponse(intent, context) โ†’ Response                โ”‚
โ”‚                                                                  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Cluster 2: Simulation

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                     Simulation Cluster                           โ”‚
โ”‚                                                                  โ”‚
โ”‚   Verantwortung: Deck-Generierung, Job-Management, Execution     โ”‚
โ”‚                                                                  โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”‚
โ”‚   โ”‚    Deck     โ”‚   โ”‚    Deck     โ”‚   โ”‚     Job     โ”‚          โ”‚
โ”‚   โ”‚  Generator  โ”‚โ”€โ”€โ–บโ”‚  Validator  โ”‚โ”€โ”€โ–บโ”‚ Orchestratorโ”‚          โ”‚
โ”‚   โ”‚             โ”‚   โ”‚             โ”‚   โ”‚             โ”‚          โ”‚
โ”‚   โ”‚ โ€ข NLโ†’Deck   โ”‚   โ”‚ โ€ข Syntax    โ”‚   โ”‚ โ€ข Queue     โ”‚          โ”‚
โ”‚   โ”‚ โ€ข Templates โ”‚   โ”‚ โ€ข Physics   โ”‚   โ”‚ โ€ข Schedule  โ”‚          โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜          โ”‚
โ”‚                                              โ”‚                   โ”‚
โ”‚                                              โ–ผ                   โ”‚
โ”‚                                 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”         โ”‚
โ”‚                                 โ”‚   Job Runner Pool   โ”‚         โ”‚
โ”‚                                 โ”‚  โ”Œโ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ” โ”‚         โ”‚
โ”‚                                 โ”‚  โ”‚ W โ”‚ โ”‚ W โ”‚ โ”‚ W โ”‚ โ”‚         โ”‚
โ”‚                                 โ”‚  โ””โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”˜ โ”‚         โ”‚
โ”‚                                 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜         โ”‚
โ”‚                                              โ”‚                   โ”‚
โ”‚                              Simulator Abstraction Layer         โ”‚
โ”‚                                                                  โ”‚
โ”‚   Events: job.submitted, job.started, job.completed, job.failed โ”‚
โ”‚                                                                  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Cluster 3: Analysis

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                      Analysis Cluster                            โ”‚
โ”‚                                                                  โ”‚
โ”‚   Verantwortung: Results Processing, Visualization, Reporting    โ”‚
โ”‚                                                                  โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”‚
โ”‚   โ”‚   Results   โ”‚   โ”‚ Comparison  โ”‚   โ”‚Visualizationโ”‚          โ”‚
โ”‚   โ”‚   Parser    โ”‚โ”€โ”€โ–บโ”‚   Engine    โ”‚โ”€โ”€โ–บโ”‚   Service   โ”‚          โ”‚
โ”‚   โ”‚             โ”‚   โ”‚             โ”‚   โ”‚             โ”‚          โ”‚
โ”‚   โ”‚ โ€ข SMSPEC    โ”‚   โ”‚ โ€ข Diff      โ”‚   โ”‚ โ€ข Charts    โ”‚          โ”‚
โ”‚   โ”‚ โ€ข UNSMRY    โ”‚   โ”‚ โ€ข History   โ”‚   โ”‚ โ€ข 3D Grid   โ”‚          โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜          โ”‚
โ”‚                                                                  โ”‚
โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                             โ”‚
โ”‚   โ”‚  Reporting  โ”‚   โ”‚   Export    โ”‚                             โ”‚
โ”‚   โ”‚   Engine    โ”‚   โ”‚   Service   โ”‚                             โ”‚
โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                             โ”‚
โ”‚                                                                  โ”‚
โ”‚   Events Consumed: job.completed โ†’ Trigger auto-parsing          โ”‚
โ”‚                                                                  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Communication Patterns

Wann welches Medium?

Medium Use Case Beispiel
REST External API, CRUD User โ†’ Gateway
gRPC Internal, High-Perf, Streaming Cluster โ†” Cluster
Message Broker Async, Events, Decoupled Job Events

Message Broker Topics

clarissa/
โ”œโ”€โ”€ jobs/
โ”‚   โ”œโ”€โ”€ submitted    # { job_id, deck_hash, user_id }
โ”‚   โ”œโ”€โ”€ started      # { job_id, worker_id, simulator }
โ”‚   โ”œโ”€โ”€ progress     # { job_id, step, total }
โ”‚   โ”œโ”€โ”€ completed    # { job_id, duration_s, result_path }
โ”‚   โ””โ”€โ”€ failed       # { job_id, error, retry_count }
โ”‚
โ”œโ”€โ”€ conversation/
โ”‚   โ”œโ”€โ”€ utterance    # { session_id, text }
โ”‚   โ””โ”€โ”€ response     # { session_id, text, actions }
โ”‚
โ””โ”€โ”€ analysis/
    โ”œโ”€โ”€ parsed       # { job_id, summary_stats }
    โ””โ”€โ”€ report       # { job_id, report_url }

Simulator Abstraction Layer (SAL)

Motivation

CLARISSA soll nicht an einen Simulator gebunden sein:

Simulator Strength Use Case
OPM Flow Production-ready, Eclipse-kompatibel Full-field, History Match
MRST Flexible, MATLAB, Rapid Prototyping Research, Sensitivities
Eclipse Industry Standard (proprietary) Client Validation
CMG Thermal, Heavy Oil (proprietary) Special Cases

Interface Definition

from abc import ABC, abstractmethod
from enum import Enum
from typing import AsyncIterator

class SimulatorBackend(Enum):
    OPM_FLOW = "opm_flow"
    MRST = "mrst"
    # Future: ECLIPSE, CMG

class SimulatorInterface(ABC):
    """Abstract interface for reservoir simulators."""

    @property
    @abstractmethod
    def backend(self) -> SimulatorBackend:
        """Which backend this adapter implements."""
        ...

    @abstractmethod
    async def submit_job(self, deck: str, config: dict) -> JobHandle:
        """Submit simulation job, return handle for tracking."""
        ...

    @abstractmethod
    async def get_status(self, job: JobHandle) -> JobStatus:
        """Get current job status."""
        ...

    @abstractmethod
    async def cancel_job(self, job: JobHandle) -> bool:
        """Cancel running job."""
        ...

    @abstractmethod
    async def get_results(self, job: JobHandle) -> AsyncIterator[bytes]:
        """Stream result files."""
        ...

    @abstractmethod
    async def validate_deck(self, deck: str) -> ValidationResult:
        """Validate deck syntax and semantics."""
        ...

    @abstractmethod
    def get_capabilities(self) -> SimulatorCapabilities:
        """What this simulator supports."""
        ...

OPM Flow Adapter

class OPMFlowAdapter(SimulatorInterface):
    """
    Adapter for OPM Flow simulator.
    - Eclipse-format decks (.DATA)
    - HPC capable, production-ready
    """

    @property
    def backend(self) -> SimulatorBackend:
        return SimulatorBackend.OPM_FLOW

    async def submit_job(self, deck: str, config: dict) -> JobHandle:
        job_id = generate_job_id()
        job_dir = self.work_dir / job_id

        # Write deck
        (job_dir / "MODEL.DATA").write_text(deck)

        # Start flow process
        process = await asyncio.create_subprocess_exec(
            "flow", str(job_dir / "MODEL.DATA"),
            f"--output-dir={job_dir}"
        )

        return JobHandle(job_id=job_id, backend=self.backend)

    def get_capabilities(self) -> SimulatorCapabilities:
        return SimulatorCapabilities(
            backend=self.backend,
            physics_models=["BLACK_OIL", "COMPOSITIONAL"],
            max_cells=10_000_000,
            supports_parallel=True
        )

MRST Adapter

class MRSTAdapter(SimulatorInterface):
    """
    Adapter for MRST (MATLAB Reservoir Simulation Toolbox).
    - MATLAB/Octave based
    - Flexible, good for prototyping
    """

    @property
    def backend(self) -> SimulatorBackend:
        return SimulatorBackend.MRST

    async def submit_job(self, deck: str, config: dict) -> JobHandle:
        job_id = generate_job_id()
        job_dir = self.work_dir / job_id

        # Write deck
        (job_dir / "MODEL.DATA").write_text(deck)

        # Generate MRST script
        script = self._generate_mrst_script(job_dir / "MODEL.DATA")
        (job_dir / "run.m").write_text(script)

        # Run via Octave
        process = await asyncio.create_subprocess_exec(
            "octave", "--no-gui", "--eval", f"run('{job_dir}/run.m')"
        )

        return JobHandle(job_id=job_id, backend=self.backend)

    def _generate_mrst_script(self, deck_path: Path) -> str:
        return f"""
        mrstModule add ad-core ad-blackoil deckformat
        deck = readEclipseDeck('{deck_path}');
        [G, rock, fluid] = initEclipseModel(deck);
        [wellSols, states] = simulateScheduleAD(state0, model, schedule);
        writeEclipseOutput(states, '{deck_path.parent}/RESULTS');
        """

    def get_capabilities(self) -> SimulatorCapabilities:
        return SimulatorCapabilities(
            backend=self.backend,
            physics_models=["BLACK_OIL", "COMPOSITIONAL", "THERMAL", "POLYMER"],
            max_cells=1_000_000,
            supports_parallel=False
        )

Simulator Factory

class SimulatorFactory:
    """Create simulator adapters based on requirements."""

    @classmethod
    def create(cls, backend: SimulatorBackend, **kwargs) -> SimulatorInterface:
        adapters = {
            SimulatorBackend.OPM_FLOW: OPMFlowAdapter,
            SimulatorBackend.MRST: MRSTAdapter,
        }
        return adapters[backend](**kwargs)

    @classmethod
    def get_best_backend(cls, requirements: SimRequirements) -> SimulatorBackend:
        """
        Select best backend based on requirements:
        - Quick sensitivity study โ†’ MRST (faster iteration)
        - Full-field forecast โ†’ OPM Flow (scalable)
        - Industry deliverable โ†’ OPM Flow (Eclipse-compatible)
        """
        if requirements.needs_eclipse_compatibility:
            return SimulatorBackend.OPM_FLOW
        if requirements.is_quick_study or requirements.model_type in ["thermal"]:
            return SimulatorBackend.MRST
        return SimulatorBackend.OPM_FLOW

REST API (External)

/api/v1/
โ”œโ”€โ”€ conversation/
โ”‚   โ”œโ”€โ”€ POST   /sessions                    # New session
โ”‚   โ”œโ”€โ”€ POST   /sessions/{id}/messages      # Send message
โ”‚   โ””โ”€โ”€ GET    /sessions/{id}/history       # Get history
โ”‚
โ”œโ”€โ”€ simulation/
โ”‚   โ”œโ”€โ”€ POST   /jobs                        # Submit job
โ”‚   โ”œโ”€โ”€ GET    /jobs/{id}                   # Get status
โ”‚   โ”œโ”€โ”€ DELETE /jobs/{id}                   # Cancel
โ”‚   โ””โ”€โ”€ GET    /jobs/{id}/results           # Get results
โ”‚
โ”œโ”€โ”€ analysis/
โ”‚   โ”œโ”€โ”€ GET    /jobs/{id}/summary           # Results summary
โ”‚   โ”œโ”€โ”€ POST   /compare                     # Compare runs
โ”‚   โ””โ”€โ”€ POST   /report                      # Generate report
โ”‚
โ””โ”€โ”€ decks/
    โ”œโ”€โ”€ POST   /generate                    # NL โ†’ Deck
    โ””โ”€โ”€ POST   /validate                    # Validate deck

Deployment

Development (Docker Compose)

services:
  gateway:     { image: clarissa/gateway }
  conversation: { image: clarissa/conversation }
  simulation:  { image: clarissa/simulation }
  analysis:    { image: clarissa/analysis }
  broker:      { image: redis:alpine }
  opm-flow:    { image: opm/flow:latest }
  octave:      { image: gnuoctave/octave:latest }

Production (Kubernetes)

clarissa-prod/
โ”œโ”€โ”€ gateway (3 replicas, HPA)
โ”œโ”€โ”€ conversation (2 replicas)
โ”œโ”€โ”€ simulation (2 replicas)
โ”œโ”€โ”€ analysis (2 replicas)
โ”œโ”€โ”€ simulator-workers/
โ”‚   โ”œโ”€โ”€ opm-flow (0-10 replicas, autoscale)
โ”‚   โ””โ”€โ”€ mrst (0-5 replicas, autoscale)
โ””โ”€โ”€ infra/
    โ”œโ”€โ”€ redis (3 replicas, Sentinel)
    โ””โ”€โ”€ postgres (3 replicas, HA)

Summary

Aspect Decision
Architecture Microservices in Bounded Context Clusters
External API REST via API Gateway
Internal Sync gRPC
Internal Async Message Broker (Redis/RabbitMQ)
Simulator Layer Abstract interface + pluggable adapters
Initial Backends OPM Flow + MRST

References