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
- Modular Microservices: Independently deployable, scalable
- Flexible Kommunikation: REST (extern), gRPC (intern), Message Broker (async)
- Simulator-Agnostic: Abstraction layer for OPM Flow, MRST, (later: commercial)
- 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