Reading Time: 9 minutes

TL; DR

Multiphysische Simulationen erfordern häufig die Kopplung mehrerer spezialisierter Löser. Precice ist eine ausgereifte Open-Source-Kopplungsbibliothek, die partitionierte Multiphysik-Simulationen in Python ermöglicht. Dieses Tutorial zeigt, wie man FIPY mit einem anderen Solver unter Verwendung von Precice koppelt und die Installation, die Implementierung von Adaptern, die Konfiguration und die üblichen Fallstricke abdeckt. Sie erfahren, wann Sie partitionierte Kopplung verwenden, wie Sie den Datenaustausch einrichten und wie Sie typische Probleme debuggen.

Einleitung: Wenn ein Solver nicht ausreicht

Viele wissenschaftliche Probleme beinhalten mehrere physikalische Prozesse, die interagieren. Zum Beispiel:

  • Wärmeübertragung gekoppelt mit Flüssigkeitsfluss (konjugierte Wärmeübertragung)
  • Strukturmechanik, die mit der Fluiddynamik interagiert (Flüssig-Struktur-Interaktion)
  • Elektrochemie in Verbindung mit Transportphänomenen (Batteriemodellierung)

FIPY zeichnet sich durch partielle Differentialgleichungen (PDES) für Transport-, Diffusions- und Phasenfeldprobleme aus. Einige Multiphysik-Szenarien erfordern jedoch die Kopplung von FIPY mit einem spezialisierten Solver für einen anderen Physikbereich – wie OpenFoam für die Strömungsdynamik oder einen benutzerdefinierten Strukturcode.

Codekopplung ist die Praxis, zwei oder mehr unabhängige Simulationscodes zu verbinden, damit sie während der Berechnung Daten austauschen. Hier kommt Precice (partitionierte Kopplungsinfrastruktur für Kontinuumsgleichungen) ins Spiel.

Warum Precice verwenden?

Precice bietet:

  • Sprach-Agnostische Kopplung: Verbinden Sie Solver in C++, Python, Fortran usw.
  • Flexibles Daten-Mapping: Behandeln Sie die Interpolation von Netz-zu-Mesh zwischen nicht übereinstimmenden Gittern
  • Zeitschritt-Koordination: Unterstützung expliziter, impliziter und Quasi-Newton-Kopplungsschemas
  • Parallele Skalierbarkeit: Entwickelt für Hochleistungs-Computing-Umgebungen
  • Aktive Community: Einsatz in Forschung und Industrie, mit guter Dokumentation

Für FIPY-Benutzer öffnet Precice die Tür zu robusten Multi-Physik-Workflows, ohne die Infrastruktur von Grund auf neu aufzubauen.

Partitionierte vs. monolithische Löser

Verstehen Sie vor dem Eintauchen die beiden Hauptansätze für die Multiphysik:

Aspekt partitioniert (Precice) Monolithisch
Struktur Separate Solver über Datenaustausch gekoppelt Einzelne Solver verarbeitet alle Physik zusammen
Wiederverwendung von Code Hoch – vorhandene spezialisierte Löser verwenden Niedrig – Benötigen Sie eine einheitliche Implementierung
Entwicklungsaufwand Moderate – Adapter schreiben, Kopplung konfigurieren Sehr hoch – Implementieren Sie alle Physik in einem Code
Leistung Gut, aber Kommunikationsaufwand Möglicherweise besser für eng gekoppelte Probleme
Flexibilität Einfaches Tauschen oder Upgrade einzelner Solver Rigid – Änderungen wirken sich auf die gesamte Codebasis aus
Use Case Reife Solver existieren für jede Physik Neue oder hochintegrierte Physikmodelle

Wann partitionierte Kopplung mit dem Precice wählen:

  • Sie haben zuverlässige, optimierte Löser für die individuelle Physik (z. B. FIPY für Diffusion, OpenFoam für Flow)
  • Die Physik ist lose oder mäßig gekoppelt
  • Sie möchten vorhandene Codebasen und Communities nutzen
  • Sie benötigen Flexibilität, um verschiedene Solver-Kombinationen auszuprobieren

Wenn monolithisch besser sein könnte:

  • Extrem enge Kopplung, die eine implizite Behandlung auf linearer Algebra-Ebene erfordert
  • Leistungskritische HPC-Simulationen, bei denen der Kommunikationsaufwand inakzeptabel ist
  • Sehr neue Physik, in der es noch keinen spezialisierten Solver gibt

Für viele Forschungsanwendungen ist die partitionierte Kopplung mit der Präzikation die pragmatische Wahl .

Konzeptioneller Überblick: Wie das Precice funktioniert

Precice folgt einer Client-Server-Architektur:

  1. Solver A (z. B. FIPY) läuft als Precice-Client
  2. Solver B (Ein weiterer Code) läuft als ein weiterer Precice Client
  3. Precice läuft als separater Prozess (der Kupplungsdienst), der die Kommunikation und die Datenzuordnung verwaltet
  4. An Kopplungsschnittstellen tauschen Solver Grenzdaten (z. B. Temperatur, Wärmefluss, Geschwindigkeit) durch
  5. Precice-Handles:
    • Mesh-Mapping, wenn Schnittstellennetze nicht übereinstimmen
    • Zeitschritt-Synchronisation
    • Datenrelaxation und Unterrelaxation zur Verbesserung der Konvergenz
    • Kopplungsschemas (explizit, implizit, quasi-newton)

Der Hauptvorteil: Jeder Solver ist sich der internen Details des anderen nicht bewusst. Sie müssen nur wissen, wie Daten an ihrer Grenze über die API von Precice gesendet / empfangen werden.

Voraussetzungen

Stellen Sie vor dem Start sicher, dass Sie Folgendes haben:

Schritt 1: Installieren Sie die Python-Bindungen von Precice

Precice bietet Python-Bindungen an, damit FIPY (oder ein beliebiger Python-Code) als Kopplungsclient fungieren kann.

# Using conda (recommended)
conda install -c conda-forge precice

# Or using pip
pip install precice

Überprüfen Sie die Installation:

python -c "import precice; print('preCICE Python version:', precice.__version__)"

Sie sollten die PRECICE-Version ohne Fehler sehen.

Schritt 2: Entwerfen Sie Ihre Kopplungsschnittstelle

Identifizieren Sie wo Die beiden Löser interagieren. Gemeinsame Szenarien:

  • Fipy-Domain → Temperaturfeld
  • Andere Solver-Domäne → Wärmefluss oder Temperatur

definieren:

  • Interface-Mesh auf jeder Seite (kann unterschiedlich sein)
  • Kupplungsdaten: Welche Mengen werden ausgetauscht (z. B. Temperature, Heat-Flux)
  • Mesh-Skalierung: Stellen Sie sicher, dass die Koordinatensysteme ausrichten

Für dieses Tutorial koppeln wir einen Fipy Heat Diffusion Solver mit einem Simple Python Convective Cooling Solver. Die Schnittstelle ist eine 1D-Linie, in der Temperatur und Wärmefluss ausgetauscht werden.

Schritt 3: Schreiben Sie den FIPY-Precice-Adapter

Der Adapter ist der Code, der Ihren Solver (FIPY) mit Precice verbindet. Es behandelt:

  • Initialisierung der Precice-Verbindung
  • Definieren der Kopplungsschnittstelle
  • Eingehende Daten vom anderen Solver lesen
  • Ausgehende Daten zum Senden schreiben
  • Vorwärtskopplungszeitschritt

Erstellen Sie eine Datei fipy_precice_adapter.py:

import numpy as np
from fipy import CellVariable, Grid1D, DiffusionTerm, TransientTerm
import precice

# --- Configuration ---
# These should match the preCICE configuration file
COUPLING_INTERFACE = "Fluid-Solid"  # Name of the coupling interface
COUPLING_MESH_ID = 0  # ID of the mesh on this solver side
COUPLING_DATA_TEMPERATURE_ID = 0
COUPLING_DATA_HEATFLUX_ID = 1

# Simulation parameters
nx = 50
dx = 1.0
total_time = 10.0
dt = 0.1

# --- FiPy setup ---
mesh = Grid1D(nx=nx, dx=dx)
T = CellVariable(name="Temperature", mesh=mesh, value=300.0)  # Initial temp in K
k = 1.0  # Thermal conductivity

# Boundary conditions
# Left boundary: fixed temperature (will be overwritten by coupling)
# Right boundary: fixed temperature (example)
T.constrain(300.0, mesh.facesRight)

# Equation: transient diffusion
eq = TransientTerm() == DiffusionTerm(coeff=k)

# --- preCICE setup ---
solver_name = "FiPy-Solver"
config_file = "precice-config.xml"  # Provided separately

precice_dll = precice.Participant(solver_name, config_file, 0, 0)

# Get the coupling mesh from preCICE
mesh_vertices = precice_dll.get_mesh_vertices(COUPLING_MESH_ID, COUPLING_INTERFACE)
# In 1D, mesh_vertices is an array of x-coordinates
# We'll map these to our FiPy mesh cells

# Main coupling loop
time = 0.0
while time < total_time:
    # 1. Advance FiPy one time step (without coupling first)
    eq.solve(var=T, dt=dt)
    
    # 2. Read incoming data from the other solver (e.g., heat flux)
    # preCICE expects data at the coupling interface vertices
    heat_flux_in = precice_dll.read_data(
        COUPLING_DATA_HEATFLUX_ID,
        COUPLING_INTERFACE,
        mesh_vertices
    )
    
    # 3. Apply received heat flux as Neumann boundary condition on FiPy
    # This is simplified: in practice you'd map heat_flux_in to FiPy faces
    # For 1D, we can directly apply to left boundary
    if len(heat_flux_in) > 0:
        # Neumann BC: -k * dT/dx = heat_flux
        # In FiPy, you can set flux via constrained faces
        # For simplicity, we'll adjust the left boundary value to mimic flux
        # A proper implementation would use a FluxBoundaryCondition
        pass  # Implementation depends on exact boundary treatment
    
    # 4. Write outgoing data (temperature) to send to the other solver
    # Extract temperature at coupling interface cells
    T_interface = T.value  # In practice, sample at interface mesh locations
    precice_dll.write_data(
        COUPLING_DATA_TEMPERATURE_ID,
        COUPLING_INTERFACE,
        T_interface[:len(mesh_vertices)]  # ensure matching size
    )
    
    # 5. Advance coupling
    precice_dll.advance(dt)
    
    time += dt
    print(f"Time: {time:.2f}, Max T: {T.max():.2f}, Min T: {T.min():.2f}")

precice_dll.finalize()

Wichtige Anmerkungen:

  • Dies ist ein Minimales Beispiel. Reale Implementierungen benötigen eine ordnungsgemäße Netzzuordnung und Randbedingungsanwendung.
  • Die Datei precice-config.xml definiert Kommunikationseinstellungen, Mesh-IDs und Daten-IDs. Siehe Schritt 4.
  • Das FIPY-Randbedingungs-Update wird vereinfacht; Implementieren Sie für den Produktionseinsatz den richtigen Neumann BC über FaceVariable oder eine benutzerdefinierte Einschränkung.

Schritt 4: Erstellen Sie die Konfigurationsdatei für die Präzision

Precice verwendet eine XML-Konfigurationsdatei (precice-config.xml), die definiert:

  • Teilnehmer (Solver)
  • Kopplungsschnittstellen
  • Netz- und Datendefinitionen
  • Kommunikationseinstellungen
  • Kopplungsschema (explizit, implizit, quasi-newton)

Eine minimale Konfiguration für die FIPY + Python Solver-Kopplung:

<?xml version="1.0" encoding="UTF-8"?>
<precice-configuration>
  <schema>https://precice.org/schemas/coupling-schema-2.2.xsd</schema>

  <!-- Parallel settings -->
  <parallel>
    <exchange comm-world="true" />
  </parallel>

  <!-- Coupling participants -->
  <participants>
    <participant name="FiPy-Solver">
      <use-mesh name="Fluid-Solid-Mesh-FiPy" provide="true" />
      <use-data name="Temperature" from="FiPy-Solver" />
      <use-data name="Heat-Flux" to="FiPy-Solver" />
    </participant>
    <participant name="SimpleSolver">
      <use-mesh name="Fluid-Solid-Mesh-Simple" provide="true" />
      <use-data name="Temperature" to="SimpleSolver" />
      <use-data name="Heat-Flux" from="SimpleSolver" />
    </participant>
  </participants>

  <!-- Coupling interfaces -->
  <coupling-scheme:serial-explicit>
    <participants first="FiPy-Solver" second="SimpleSolver" />
    <exchange>
      <data name="Temperature" mesh="Fluid-Solid-Mesh-FiPy" />
      <data name="Heat-Flux" mesh="Fluid-Solid-Mesh-Simple" />
    </exchange>
    <max-time>10.0</max-time>
    <max-iterations>10</max-iterations>
  </coupling-scheme:serial-explicit>

  <!-- Meshes -->
  <mesh name="Fluid-Solid-Mesh-FiPy" from="FiPy-Solver" />
  <mesh name="Fluid-Solid-Mesh-Simple" from="SimpleSolver" />

  <!-- Data -->
  <data name="Temperature" mesh="Fluid-Solid-Mesh-FiPy" />
  <data name="Heat-Flux" mesh="Fluid-Solid-Mesh-Simple" />

</precice-configuration>

Schlüsselelemente:

  • Zwei Teilnehmer: FiPy-Solver und SimpleSolver
  • Datenaustausch: Temperature (FIPY → SimpleSolver) und Heat-Flux (Simplesolver → FIPY)
  • serial-explicit Kopplung: einfaches explizites Zeitsteppen (gut zum Starten)
  • max-iterations steuert, wie viele Unteriterationen pro Zeitschritt (bei impliziten Schemata)

Für eine erweiterte Kopplung ist Folgendes zu beachten:

  • serial-implicit mit Quasi-Newton-Beschleunigung für engere Kopplung
  • Unter-Entspannungsfaktoren zur Verbesserung der Konvergenz
  • Netzverbindungsdefinitionen, wenn die Netze nicht ausrichten

Schritt 5: Implementieren Sie den zweiten Solver (einfaches Beispiel)

Um die Kupplung zu testen, benötigen Sie einen zweiten Solver. Hier ist ein minimaler Python-Solver, der Wärmefluss mit FIPY austauscht:

solver_simple.py:

import numpy as np
import precice

# Configuration
COUPLING_INTERFACE = "Fluid-Solid"
COUPLING_MESH_ID = 0
COUPLING_DATA_TEMPERATURE_ID = 0
COUPLING_DATA_HEATFLUX_ID = 1

solver_name = "SimpleSolver"
config_file = "precice-config.xml"

precice_dll = precice.Participant(solver_name, config_file, 0, 0)

# Simple 1D mesh (could be completely different from FiPy's mesh)
mesh_vertices = np.array([[0.0], [1.0]])  # Two points at interface
T_interface = np.array([300.0, 300.0])    # Initial guess

total_time = 10.0
dt = 0.1
time = 0.0

while time < total_time:
    # 1. Read incoming temperature from FiPy
    T_from_fipy = precice_dll.read_data(
        COUPLING_DATA_TEMPERATURE_ID,
        COUPLING_INTERFACE,
        mesh_vertices
    )
    
    # 2. Compute outgoing heat flux (simple Newton's law of cooling)
    # q = h * (T_fluid - T_solid)
    h = 10.0  # Heat transfer coefficient
    T_fluid = 350.0  # Ambient fluid temperature
    heat_flux = h * (T_fluid - T_from_fipy.mean())
    
    # Send same flux to all interface vertices (simplified)
    heat_flux_out = np.full_like(T_from_fipy, heat_flux)
    
    # 3. Write heat flux to send to FiPy
    precice_dll.write_data(
        COUPLING_DATA_HEATFLUX_ID,
        COUPLING_INTERFACE,
        heat_flux_out
    )
    
    # 4. Advance coupling
    precice_dll.advance(dt)
    
    time += dt
    print(f"[SimpleSolver] Time: {time:.2f}, T_fipy: {T_from_fipy.mean():.2f}, q: {heat_flux:.2f}")

precice_dll.finalize()

Dieser einfache Solver stellt eine konvektive Kühlumgebung dar, die einen Wärmefluss proportional zur Temperaturdifferenz des FIPY-Festkörpers anwendet.

Schritt 6: Führen Sie die gekoppelte Simulation aus

  1. Starten Sie beide Solver Simultaneously (Precice verwaltet ihre Kommunikation):
# Terminal 1
python fipy_precice_adapter.py &

# Terminal 2
python solver_simple.py &
  1. Beobachten Sie die Ausgabe. Sie sollten sowohl in den Solvern als auch in den Temperatur- / Wärmeflusswerten die Entwicklung der Zeit vornehmen.
  2. Die Simulation endet, wenn total_time erreicht ist oder das Kopplungsschema abgeschlossen ist.

Erwartetes Verhalten:

  • Die FIPY-Temperatur sollte von anfänglichen 300 K zur Kühlkurve allmählich abnehmen
  • Der Wärmefluss von SimpleSolver sollte positiv sein (Wärme hinterlässt FIPY)
  • Beide Solver sollten rechtzeitig synchronisiert bleiben

Schritt 7: Ergebnisse visualisieren

Nach dem Laufen können Sie das Temperaturprofil von FIPY zeichnen:

import matplotlib.pyplot as plt
from fipy import Grid1D, CellVariable, DiffusionTerm

# Re-run simulation while storing history
# (or modify the adapter to save snapshots to file)
# Then plot T vs x at final time

Fehlerbehebung: Häufige Probleme und Lösungen

Symptom wahrscheinlich Ursache Lösung
precice: error: XML file not found Konfigurationsdatei fehlt oder falscher Pfad Stellen Sie sicher, dass precice-config.xml im Arbeitsverzeichnis ist oder den vollständigen Pfad angibt
Mesh vertex count mismatch FIPY- und PRECICE-Schnittstellennetze haben unterschiedliche Anzahl von Scheitelpunkten check get_mesh_vertices() Gibt die erwartete Anzahl zurück; korrekt zuordnen
Data not found in configuration Datenname oder ID stimmt nicht mit XML überein Überprüfen Sie COUPLING_DATA_* Konstanten mit <data name="..."> Einträgen
Coupling diverges (temperatures explode) Unterentspannung erforderlich oder explizites Schema instabil Fügen Sie <relaxation value="0.5"/> in XML hinzu oder wechseln Sie zur impliziten Kopplung
Time step mismatch Solver verwenden unterschiedliche dt-Werte Achten Sie darauf, dass beide die gleiche dt verwenden oder die Präzisionskontrollzeit (precice_dll.advance(dt))
Segmentation fault in preCICE Nicht übereinstimmende Precice-Versionen zwischen den Teilnehmern Installieren Sie Precice neu, um sicherzustellen, dass alle Teilnehmer die gleiche Version verwenden
FiPy boundary not updating Adapter nicht richtig angelegt Implementieren Sie die richtige Neumann-Randbedingung mit FaceVariable oder ändern Sie den Gleichungsquellenbegriff
Communication timeout Ein Solver ist abgestürzt oder blockiert Überprüfen Sie, ob beide Löser ausgeführt werden. Stellen Sie sicher, dass sie advance() regelmäßig anrufen

Debugging-Tipps:

  • Führen Sie Solver mit der Umgebungsvariablen PRECICE_DEBUG=1 für ausführliche Protokolle aus
  • Beginnen Sie mit einem groben Netz und einer kurzen Gesamtzeit, um schnell zu testen
  • Verwenden Sie serial-explicit Kopplung zuerst (am meisten nachgeben), bevor Sie implizite Schemata ausprobieren
  • Validieren Sie zuerst jeden Solver ohne Kopplung, um sicherzustellen, dass er eigenständig funktioniert

Fortgeschrittene Themen

Sobald die Grundkopplung funktioniert, erkunden Sie:

Implizite Kopplung mit Quasi-Newton

Bei eng gekoppelten Problemen können explizite Schemata viele Subitationen erfordern oder instabil werden. Precice unterstützt Implizite Kopplung mit Quasi-Newton-Beschleunigung:

<coupling-scheme:serial-implicit>
  <participants first="FiPy-Solver" second="SimpleSolver" />
  <exchange>
    <data name="Temperature" mesh="Fluid-Solid-Mesh-FiPy" />
    <data name="Heat-Flux" mesh="Fluid-Solid-Mesh-Simple" />
  </exchange>
  <max-time>10.0</max-time>
  <max-iterations>10</max-iterations>
  <convergence-measure>
    <data name="Temperature" mesh="Fluid-Solid-Mesh-FiPy" />
  </convergence-measure>
  <relaxation value="0.5"/>
</coupling-scheme:serial-implicit>

Mesh-to-Mesh-Mapping

Wenn das Schnittstellennetz von FIPY nicht mit dem Mesh des anderen Solver übereinstimmt, führt Precice Mesh-Mapping durch (Interpolation). Sie können die Zuordnungsmethode in XML konfigurieren:

<mesh name="Fluid-Solid-Mesh-FiPy" from="FiPy-Solver">
  <use-data name="Temperature" />
  <mapping:nearest-neighbor />
</mesh>

Optionen: nearest-neighbor, linear, rbf (radiale Basisfunktionen). Wählen Sie basierend auf Netzqualität und Physik.

Umgang mit nicht übereinstimmenden Zeitschritten

Precice ermöglicht es jedem Solver, seinen eigenen Zeitschritt zu verwenden, während er an den Kopplungsschnittstellen koordiniert wird. Setzen Sie dt unabhängig in jedem Solver; Precice interpoliert Daten nach Bedarf. Große Unterschiede können jedoch die Genauigkeit verringern.

Leistungsüberlegungen

  • Kommunikations-Overhead kann bei kleinen Problemen dominieren. Profil, um sicherzustellen, dass die Kopplung nicht der Engpass ist.
  • Under-Relaxation (<relaxation> in XML) verbessert die Stabilität, verlangsamt aber die Konvergenz.
  • Mesh-Auflösung auf der Schnittstelle wirkt sich auf die Zuordnungsgenauigkeit aus. Verwenden Sie ausreichend raffinierte Schnittstellennetze.
  • Parallel-Skalierung: Precice arbeitet mit MPI-fähigen Lösern. Stellen Sie sicher, dass sowohl FIPY (mit PETSC) als auch der andere Solver parallel laufen.

Nächste Schritte

Nach dem Mastern der Grundkopplung:

  1. Versuchen Sie einen echten zweiten Solver (z.
  2. Entdecken Sie erweiterte Kopplungsschemata (serial-implicit, multi)
  3. Add more Physics (z. B. drei Solver: Thermisch, flüssig, strukturell)
  4. Implementieren Sie die richtigen Randbedingungen in FIPY unter Verwendung von FaceVariable oder benutzerdefinierten Begriffen
  5. Leistung optimieren mit paralleler Ausführung und Profilerstellung
  6. Studienfallstudien Wie thermische Flüssigkeitskupplung oder Fluid-Struktur-Wechselwirkung

Für tieferes FIPY-Wissen finden Sie Aus Gleichungen zu Simulationen: The Modeling Pipeline und Finite Volume-Methode einfach erklärt .

weiterlesen

Benötigen Sie Hilfe bei Ihrem Multiphysik-Projekt?

Die Erstellung robuster gekoppelter Simulationen erfordert ein umfassendes Fachwissen sowohl bei numerischen Methoden als auch bei der Softwareintegration. Wenn Sie ein komplexes Multiphysik-Problem angehen und eine Anleitung benötigen:

  • Entwerfen eines Kopplungs-Workflows mit PRECICE
  • Implementieren von FIPY-Adaptern für Ihre spezifische Physik
  • Debuggen von Konvergenzproblemen
  • Optimieren der Leistung für groß angelegte Simulationen

Matforge bietet Beratungsdienste für Forschungssoftware-Workflows an. Wir unterstützen Sie bei der Einrichtung zuverlässiger, reproduzierbarer Multi-Physik-Simulationen, die auf Ihr Projekt zugeschnitten sind. Besuchen Sie die Matforge-Homepage, um mehr zu erfahren und Ihre spezifischen Bedürfnisse zu besprechen.


Zusammenfassung

  • Precice Ermöglicht partitionierte Multi-Physik-Kopplung, so dass FIPY mit anderen Solvern zusammenarbeiten kann
  • Partitionierter Ansatz ist praktisch für die Forschung: Bestehende Codes wiederverwenden, Flexibilität beibehalten
  • Schlüsselschritte: Installieren Sie Precice, schreiben Sie Adapter, konfigurieren Sie XML, implementieren Sie den Grenzdatenaustausch
  • Simple starten: explizite Kopplung mit einem minimalen Beispiel, dann geht es zu impliziten Schemata
  • Validieren Zuerst jeder Solver eigenständig, dann zusammen
  • Monitor Konvergenz und ggf. Unterentspannung verwenden

Mit dieser Grundlage können Sie FIPY auf praktisch jedes Multi-Physik-Szenario erweitern.