YAC 3.21.0
Yet Another Coupler
Loading...
Searching...
No Matches
ml_coupler.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2
3# Copyright (c) 2026 The YAC Authors
4#
5# SPDX-License-Identifier: BSD-3-Clause
6
7import numpy as np
8from yac import Action, ExchangeType, Field, Location, Reg2dGrid, TimeUnit, YAC
9
10
12 """
13 Encapsulates YAC setup and exchange for the ml_predictor component.
14 """
15
16 def __init__(self, component_name: str = "ml_predictor"):
17 """
18 Initialize the YAC coupler for the ml_predictor component.
19
20 @param[in] component_name Name of the component for registration in YAC
21 """
22 self.component_name = component_name
23 self.yac = YAC()
24 self.comp = self.yac.def_comp(self.component_name)
25 self.temp_field = None
26 self.heat_flux_field = None
27 if self.comp.comp_comm.size > 1:
28 raise RuntimeError("ml_predictor must run in a single process")
29
30 def setup(self, grid_name: str, x_vertices: np.ndarray, y_vertices: np.ndarray):
31 """
32 Define the 2D regular grid and fields for the ml_predictor component.
33
34 @param[in] grid_name Name of the grid for registration in YAC
35 @param[in] x_vertices X coordinates of the grid vertices
36 @param[in] y_vertices Y coordinates of the grid vertices
37 """
38 grid = Reg2dGrid(grid_name, x_vertices, y_vertices,
39 cyclic=[False, False])
40
41 # Compute the cell centers from the vertex coordinates
42 x_centers = 0.5 * (x_vertices[:-1] + x_vertices[1:])
43 y_centers = 0.5 * (y_vertices[:-1] + y_vertices[1:])
44
45 # Define the points for the grid cells where the fields will be defined
46 points = grid.def_points(Location.CELL, x_centers, y_centers)
47
48 # Define the fields for temperature input and heat flux prediction
49 self.temp_field = Field.create(
50 "temperature", self.comp, points,
51 collection_size=1, timestep="1", timeunit=TimeUnit.SECOND)
52
53 self.heat_flux_field = Field.create(
54 "heat_flux", self.comp, points,
55 collection_size=1, timestep="1", timeunit=TimeUnit.SECOND)
56
57 # Finalize the component definition
58 # This is a collective operation and must be called by all processes.
59 # It computes the interpolation weights and sets up communication
60 # patterns for the exchange of data between the coupled components.
61 self.yac.enddef()
62
63 def has_data(self) -> bool:
64 return self.temp_field.action != Action.OUT_OF_BOUND
65
66 @property
67 def heat_flux_is_coupled(self) -> bool:
68 """
69 Whether heat_flux is actually coupled back to the simulation
70 component. A one-way (training) configuration only couples
71 temperature, in which case heat_flux's role is
72 ExchangeType.NONE instead of ExchangeType.SOURCE.
73
74 @return True if heat_flux should be sent via `send_heat_flux`
75 """
76 return self.heat_flux_field.role == ExchangeType.SOURCE
77
78 @property
79 def datetime(self) -> str:
80 """
81 Return the current datetime of the next exchange
82 (temperature is used as a reference).
83
84 @return The current datetime of the next exchange as an ISO 8601
85 string (e.g., "2024-01-01T00:00:00Z")
86 """
87 return self.temp_field.datetime
88
89 def recv_temperature(self) -> np.ndarray | None:
90 """
91 Receive the temperature field from the Fortran component.
92
93 @return The temperature values, or None if no data was received.
94 """
95 temperature, info = self.temp_field.get()
96 assert info in (Action.COUPLING, Action.GET_FOR_RESTART, Action.NONE), (
97 f"Unexpected action: {info}"
98 )
99 if temperature is None:
100 return None
101 return temperature.ravel()
102
103 def send_heat_flux(self, heat_flux: np.ndarray):
104 """
105 Send the predicted heat flux back to the Fortran component.
106
107 Only call this if `heat_flux_is_coupled` is True; otherwise there is
108 no coupling configured for heat_flux to send data on (e.g. during a
109 one-way training run).
110
111 @param[in] heat_flux The predicted heat flux values to send back.
112 """
114 "heat_flux is not coupled in the current configuration; "
115 "check heat_flux_is_coupled before calling send_heat_flux"
116 )
117 # Send the predicted heat flux back to the Fortran component
118 self.heat_flux_field.put(heat_flux.reshape(1, -1))
119
120 def finalize(self):
121 """Finalize the YAC coupler and clean up resources."""
122 if self.yac is not None:
123 self.yac.cleanup()
124 self.yac = None
Encapsulates YAC setup and exchange for the ml_predictor component.
Definition ml_coupler.py:11
bool has_data(self)
Definition ml_coupler.py:63
bool heat_flux_is_coupled(self)
Whether heat_flux is actually coupled back to the simulation component.
Definition ml_coupler.py:67
send_heat_flux(self, np.ndarray heat_flux)
Send the predicted heat flux back to the Fortran component.
str datetime(self)
Return the current datetime of the next exchange (temperature is used as a reference).
Definition ml_coupler.py:79
setup(self, str grid_name, np.ndarray x_vertices, np.ndarray y_vertices)
Define the 2D regular grid and fields for the ml_predictor component.
Definition ml_coupler.py:30
__init__(self, str component_name="ml_predictor")
Initialize the YAC coupler for the ml_predictor component.
Definition ml_coupler.py:16
finalize(self)
Finalize the YAC coupler and clean up resources.
np.ndarray|None recv_temperature(self)
Receive the temperature field from the Fortran component.
Definition ml_coupler.py:89
A stuctured 2d Grid.
Definition yac.pyx:1510
Initializies a YAC instance and provides further functionality.
Definition yac.pyx:755
static void cleanup()
Definition yac.c:986