This subsystem is driven by the forge application (
cstar forge run, or thepython -m cstar_forge.runmodule CLI it wraps), which callsForgeExecutor.generate_inputs()(cstar_forge/forge/executor.py), which constructs aRomsMarblInputDataand callsgenerate_all()on it. Direct construction, as shown in this document, is for developers debugging or extending input generation.
Overview¶
RomsMarblInputData is a dataclass (subclass of InputData, both defined in
cstar_forge/forge/input_data.py) that implements ROMS-MARBL specific input data generation. It
handles the creation of all input files required for a ROMS simulation, including grid, initial
conditions, and all types of forcing data.
Class Definition¶
@dataclass
class RomsMarblInputData(InputData):
"""ROMS-MARBL specific input data generation."""
# Inherited from InputData: domain_name, start_date, end_date, input_data_dir (kw_only)
grid: rt.Grid
boundaries: OpenBoundaries
source_data: source_data.SourceData
roms_marbl_blueprint_dir: Path
partitioning: cstar_models.PartitioningParameterSet
cdr_forcing: dict | None = None
forcing_override: dict[str, Any] | None = None
model_reference_date: datetime | None = None
grid_parent: rt.Grid | None = None
grid_child: rt.Grid | None = None
metadata_child: dict[str, Any] | None = None
settings_compile_time: dict[str, Any] | None = None # executor-owned, bound by reference
settings_run_time: dict[str, Any] | None = None # executor-owned, bound by reference
use_dask: bool = True
dask_num_workers: int = 8
use_pio: bool = False
subchunk: bool = True
verbose: bool = False
has_bgc: bool = False # mirrors ForgeExecutor._has_bgc (cppdefs.marbl)
roms_marbl_blueprint_elements: RomsMarblBlueprintInputData # Auto-initialized
_settings_compile_time: dict # bound to `settings_compile_time`, or {} if not given
_settings_run_time: dict # bound to `settings_run_time`, or {} if not given
include_coarse_dims: bool | None = None # Set during surface forcing generationThere is no model_spec field — the class is host-/model-spec-independent. forcing_override
(injected by the caller, typically built by sources_to_forcing_override() in
forge_blueprint_engine.py from a ForgeBlueprint) is what drives which inputs get generated;
grid is always generated from the injected grid object regardless of forcing_override. See
cstar_forge/forge/input_data.py for the full field list, including private bookkeeping fields
(_subchunk_refs, _clobber, _existing_planned_outputs, _planned_output_paths) not listed
above.
Initialization¶
Input List Derivation¶
During __post_init__(), the class builds input_list from forcing_override (not a model
spec):
Grid: Always appended as
("grid", {})— the grid handler ignores kwargs and uses the injectedgrid(and, if present,grid_child/metadata_child) object directly.Initial Conditions:
forcing_override["initial_conditions"], if present →("initial_conditions", kwargs)Forcing: Iterates over
forcing_override["forcing"]categories (surface, boundary, tidal, river) and items within each →("forcing.{category}", kwargs)for each itemCDR Forcing: If the
cdr_forcingconstructor kwarg is set →("cdr_forcing", {"cdr_kwargs": self.cdr_forcing})
A missing forcing_override raises ValueError — it is required whenever the blueprint path is
used (the resolver always fills it, from the model default or an authored selection).
Example Input List:
[
("grid", {}),
("initial_conditions", {"source": {"name": "GLORYS"}, "bgc_source": {...}}),
("forcing.surface", {"source": {"name": "ERA5"}, "type": "physics", ...}),
("forcing.surface", {"source": {"name": "UNIFIED"}, "type": "bgc", ...}),
("forcing.boundary", {"source": {"name": "GLORYS"}, "type": "physics", ...}),
("forcing.tidal", {"source": {"name": "TPXO"}, "ntides": 15}),
("forcing.river", {"source": {"name": "DAI"}, "include_bgc": True}),
]Registry Validation¶
The class validates that all keys in input_list have registered handlers in INPUT_REGISTRY. Missing handlers raise a ValueError.
ROMS-MARBL Blueprint Elements Initialization¶
Creates RomsMarblBlueprintInputData instance with empty datasets:
grid: Empty dataset if “grid” in input_listinitial_conditions: Empty dataset if “initial_conditions” in input_listforcing: ForcingConfiguration with datasets for each category (boundary, surface, tidal, river)cdr_forcing: Empty dataset if “cdr_forcing” in input_list
Validation:
Requires “boundary” forcing if any forcing is specified
Requires “surface” forcing if any forcing is specified
Settings Initialization¶
_settings_compile_time/_settings_run_time are bound directly to the settings_compile_time/
settings_run_time constructor args (no copy) -- in the normal ForgeExecutor path these ARE
the executor’s own live settings dicts, so generation steps mutate the executor’s dicts in
place and there is no merge-back step. When either arg is omitted (standalone/test use), a
fresh empty dict {} is created instead.
_settings_compile_time:cppdefsonly, populated by generation steps (open boundary flags,sal_restore,co2_tvarying,cdr_forcing)_settings_run_time: populated per-section (a flat dict of sections:grid,param,s_coord,initial,forcing,extract_data,bgc,blk_frc, ...)
Registry Framework¶
Input Registry¶
The INPUT_REGISTRY dictionary maps input keys to InputStep instances:
INPUT_REGISTRY: Dict[str, InputStep] = {
"grid": InputStep(name="grid", order=10, label="Writing ROMS grid", handler=_generate_grid),
"initial_conditions": InputStep(name="initial_conditions", order=20, label="Generating initial conditions", handler=_generate_initial_conditions),
"forcing.surface": InputStep(name="forcing.surface", order=30, label="Generating surface forcing", handler=_generate_surface_forcing),
"forcing.boundary": InputStep(name="forcing.boundary", order=40, label="Generating boundary forcing", handler=_generate_boundary_forcing),
"forcing.tidal": InputStep(name="forcing.tidal", order=50, label="Generating tidal forcing", handler=_generate_tidal_forcing),
"forcing.river": InputStep(name="forcing.river", order=60, label="Generating river forcing", handler=_generate_river_forcing),
"cdr_forcing": InputStep(name="cdr_forcing", order=80, label="Generating CDR forcing", handler=_generate_cdr_forcing),
"forcing.corrections": InputStep(name="forcing.corrections", order=90, label="Generating corrections forcing", handler=_generate_corrections),
}Registration Decorator¶
@register_input(name: str, order: int, label: str | None = None)Parameters:
name: Input key (e.g., “grid”, “forcing.surface”)order: Execution order (lower numbers run first)label: Human-readable label for progress messages
Example:
@register_input(name="forcing.surface", order=30, label="Generating surface forcing")
def _generate_surface_forcing(self, key: str = "forcing.surface", **kwargs):
"""Generate surface forcing input files."""
# Implementation...Input Generation Process¶
generate_all() Method¶
Main entry point for generating all input files:
def generate_all(
self,
clobber: bool = False,
partition_files: bool = False,
test: bool = False,
only: set[str] | None = None,
) -> RomsMarblBlueprintInputData | None:
"""
Generate all ROMS input files.
Returns
-------
RomsMarblBlueprintInputData | None
Blueprint subset with generated input file paths, or None if the input
directory is non-empty and clobber is False. Settings are NOT returned:
`_settings_compile_time`/`_settings_run_time` are the executor-owned dicts
passed in via the `settings_compile_time`/`settings_run_time` constructor
args and mutated in place by generation steps -- the caller already holds
the up-to-date dicts through its own reference.
"""only restricts generation to a subset of canonical INPUT_REGISTRY keys (see
resolve_input_selection(), which maps user-facing aliases like "ic"/"bry"/"tides" onto
them); the grid step always runs regardless, since every other step depends on the in-memory
grid object.
Process:
Clobber Check: With
clobber=False, existing.ncfiles ininput_data_dirare left in place (an informational count is printed) and reused per-step per the planned-output list; withclobber=True, all existing.ncfiles are deleted first (_ensure_empty_or_clobber())Build Step List: Creates list of
(step, kwargs)tuples frominput_list, sorted by orderPlan Outputs: Computes the planned NetCDF outputs for the run up front (
_planned_netcdf_outputs) and records which already exist on disk, so each step can decide whether to reuse an existing file instead of regenerating itDask/Thread Guards: When
use_daskis True, caps dask’s worker count (dask_num_workers) and pins BLAS/OpenMP to 1 thread for the duration of the loop, to avoid thread oversubscription on high-core HPC nodesExecute Handlers: For each step (skipping boundary forcing when all open boundaries are disabled, and skipping any step not in
onlywhenonlyis given), calls the handler withkeyandkwargsPartitioning: Optionally partitions files across tiles if
partition_files=TrueReturn: Returns
roms_marbl_blueprint_elements(settings dicts are mutated in place, not returned -- seegenerate_all()above)
Handler Function Signature¶
All registered handlers follow this pattern:
@register_input(name="input_key", order=ORDER, label="Label")
def _generate_input(self, key: str = "input_key", **kwargs):
"""
Generate input file(s) for this input type.
Parameters
----------
key : str
Input key (matches registered name)
**kwargs
Input-specific arguments from input_list
Side Effects
------------
- Creates NetCDF file(s) in input_data_dir
- Creates YAML metadata file in roms_marbl_blueprint_dir
- Appends Resource(s) to roms_marbl_blueprint_elements
- Updates _settings_compile_time and/or _settings_run_time
"""Registered Input Handlers¶
Grid (grid, order=10)¶
Handler: _generate_grid()
Generates:
Grid NetCDF file:
{domain_name}_grid.ncGrid YAML metadata:
_grid.yaml(inroms_marbl_blueprint_dir)If
grid_childis set (nesting): also a child grid NetCDF ({domain_name}_grid_child.nc+_grid_child.yaml) and a nesting-info NetCDF ({domain_name}_nesting.nc, built viart.make_nesting_info(), withinclude_bgc=Truepassed when the model has MARBL/BGC compiled in)
Updates ROMS-MARBL Blueprint:
Appends
Resourcetoroms_marbl_blueprint_elements.grid.dataWhen nesting is present, also sets
roms_marbl_blueprint_elements.nesting_info
Populates Settings:
Compile-time (
cppdefs): Open boundary flagsself._settings_compile_time["cppdefs"]["obc_west"] = self.boundaries.west self._settings_compile_time["cppdefs"]["obc_east"] = self.boundaries.east self._settings_compile_time["cppdefs"]["obc_north"] = self.boundaries.north self._settings_compile_time["cppdefs"]["obc_south"] = self.boundaries.southRun-time (
grid): Grid file pathself._settings_run_time["grid"] = {"grid_file": out_path}Run-time (
param): Grid dimensions and partitioning — note this is run-time, not compile-time, and the keys are lowercaseself._settings_run_time["param"]["llm"] = self.grid.nx self._settings_run_time["param"]["mmm"] = self.grid.ny self._settings_run_time["param"]["n"] = self.grid.N self._settings_run_time["param"]["np_xi"] = self.partitioning.n_procs_x self._settings_run_time["param"]["np_eta"] = self.partitioning.n_procs_yRun-time (
s_coord): Vertical stretching parametersself._settings_run_time["s_coord"] = dict( tcline=self.grid.hc, theta_b=self.grid.theta_b, theta_s=self.grid.theta_s, )Run-time (
extract_data): Only when a child grid is present (nesting)self._settings_run_time["extract_data"] = dict( do_extract=True, extract_file="nesting.nc", n_chd=self.grid_child.N, theta_s_chd=..., theta_b_chd=..., hc_chd=..., )
Initial Conditions (initial_conditions, order=20)¶
Handler: _generate_initial_conditions()
Generates:
Initial conditions NetCDF file(s):
{domain_name}_initial_conditions.ncInitial conditions YAML metadata:
_initial_conditions.yaml
Source Resolution:
Uses
sourceand optionalbgc_sourcefrom kwargsResolves paths via
_resolve_source_block()→SourceData.path_for_source()Per-day source file lists are trimmed to
[start_date, start_date + 1 day](roms-tools only needs the day-of and next-day files forini_time) — seefilter_paths_by_time_window()
Updates ROMS-MARBL Blueprint:
Appends
Resource(s)toroms_marbl_blueprint_elements.initial_conditions.data
Populates Settings:
Run-time (
initial): Initial conditions file path (there is nonrreckey here — that would be a template default, not something this handler sets)self._settings_run_time["initial"] = dict(initial_file=paths[0]) # First file in list
Surface Forcing (forcing.surface, order=30)¶
Handler: _generate_surface_forcing()
Generates:
Surface forcing NetCDF file(s):
{domain_name}_surface-{type}_YYYYMM.nc(bgc items sourced fromMBL_co2instead getsurface-{type}-co2in the stem)Surface forcing YAML metadata:
_forcing.surface-{type}.yaml(or-{type}-co2for MBL_co2)
Key Features:
Supports multiple surface forcing sources (physics, bgc, and restoring)
Each item in
forcing.surfacelist generates a separate fileRequires
typeparameter:"physics","bgc", or"restoring"
Source Resolution:
Uses
sourcefrom kwargsResolves path via
_resolve_source_block()
Updates ROMS-MARBL Blueprint:
Appends
Resource(s)toroms_marbl_blueprint_elements.forcing.surface.data
Populates Settings:
Compile-time (
cppdefs):sal_restore = Truewhentype == "restoring"and"sss"is inrestoring_forcesco2_tvarying = Truewhentype == "bgc"andsource.name == "MBL_co2"
Run-time (
blk_frc/bgc):interp_frc(1 if the coarse grid was used, else 0) — set onblk_frcfor physics/restoring, onbgcfor bgc (only when the model has MARBL/BGC compiled in); a mismatch between forcing types raisesValueErrorRun-time (
forcing): Surface forcing file pathsif "bgc" in type: self._settings_run_time["forcing"]["surface_forcing_bgc_path"] = paths[0] else: # physics or restoring self._settings_run_time["forcing"]["surface_forcing_path"] = paths[0]
Boundary Forcing (forcing.boundary, order=40)¶
Handler: _generate_boundary_forcing()
Generates:
Boundary forcing NetCDF file(s):
{domain_name}_boundary-{type}_YYYYMM.ncBoundary forcing YAML metadata:
_forcing.boundary-{type}.yaml
Key Features:
Supports multiple boundary forcing sources (physics and bgc)
Each item in
forcing.boundarylist generates a separate fileRequires
typeparameter:"physics"or"bgc"Uses
boundariesconfiguration for open boundary specificationSkipped entirely for child/nested domains (
grid_parent is not None) — a child domain’s boundaries come from the parent’s data extraction (nesting.nc), not from reanalysisWhen
type == "bgc"andbgc_interpolation_methodis"density"/"density_mld", builds a companion physicsrt.BoundaryForcing(_build_physics_boundary_companion()) and passes it asphysics_forcing=so roms-tools can interpolate in density space instead of depth space; if no physics boundary item exists to anchor it, a warning is issued and roms-tools falls back to depth-space interpolation
Source Resolution:
Uses
sourcefrom kwargsResolves path via
_resolve_source_block()
Updates ROMS-MARBL Blueprint:
Appends
Resource(s)toroms_marbl_blueprint_elements.forcing.boundary.data
Populates Settings:
Run-time (
forcing): Boundary forcing file pathsif type == "bgc": self._settings_run_time["forcing"]["boundary_forcing_bgc_path"] = paths[0] else: # physics self._settings_run_time["forcing"]["boundary_forcing_path"] = paths[0]
Note: Compile-time settings are not populated by the boundary handler.
Tidal Forcing (forcing.tidal, order=50)¶
Handler: _generate_tidal_forcing()
Generates:
Tidal forcing NetCDF file(s):
{domain_name}_tidal.ncTidal forcing YAML metadata:
_forcing.tidal.yaml
Key Features:
Uses
ntidesand other parameters fromforcing_overridekwargsUses
model_reference_datewhen configuredOn reuse (existing NetCDF + YAML sidecar), reads
ntidesback out of the roms-tools multi-document YAML sidecar instead of reconstructingTidalForcing
Source Resolution:
Uses
sourcefrom kwargs (typically TPXO)Resolves path via
_resolve_source_block()
Updates ROMS-MARBL Blueprint:
Appends
Resource(s)toroms_marbl_blueprint_elements.forcing.tidal.data
Populates Settings:
Run-time (
tides): only the actually-generated tidal-constituent countself._settings_run_time.setdefault("tides", {})["ntides"] = tidal.ntidesbry_tides/pot_tides/ana_tidesare not set here — those are static booleans owned by the resolver/model settings (so a child grid’sbry_tides=Falseoverride isn’t clobbered by this handler)Run-time (
forcing): Tidal forcing file pathself._settings_run_time["forcing"]["tidal_forcing_path"] = paths[0]
River Forcing (forcing.river, order=60)¶
Handler: _generate_river_forcing()
Generates:
River forcing NetCDF file(s):
{domain_name}_river.ncRiver forcing YAML metadata:
_forcing.river.yaml
Key Features:
Passes
include_bgcand other kwargs through tort.RiverForcingExtracts number of rivers from the generated dataset
If
rt.RiverForcingraises the roms-toolsValueErrorwhose message contains no relevant rivers found (no river mouths survive the domain filters), the step logs at INFO, clearsroms_marbl_blueprint_elements.forcing.river, and returns; any otherValueErrorpropagatesIf the domain simply has no rivers (
river.ds.sizes["nriver"] == 0), also clearsroms_marbl_blueprint_elements.forcing.riverwithout treating it as an error
Source Resolution:
Uses
sourcefrom kwargs (typically DAI)Resolves path via
_resolve_source_block()
Updates ROMS-MARBL Blueprint:
Appends
Resource(s)toroms_marbl_blueprint_elements.forcing.river.data
Populates Settings: note this is run-time, not compile-time, despite the river_frc
section name
Run-time (
river_frc): River forcing configurationself._settings_run_time["river_frc"] = { "river_source": True, "analytical": False, "nriv": river.ds.sizes["nriver"], # From generated dataset "rvol_vname": "river_volume", "rvol_tname": "river_time", "rtrc_vname": "river_tracer", "rtrc_tname": "river_time", }Run-time (
forcing): River forcing file pathself._settings_run_time["forcing"]["river_path"] = paths[0]
CDR Forcing (cdr_forcing, order=80)¶
Handler: _generate_cdr_forcing()
Generates:
CDR forcing NetCDF file(s):
{domain_name}_cdr.nc(the basename must contain the literal substringcdr.ncso C-Star’s ROMS build check oncdr_frc.optpasses — seeCDR_FORCING_NETCDF_STEM)CDR forcing YAML metadata:
_cdr_forcing.yaml
Key Features:
Optional input: only appears in
input_list(as("cdr_forcing", {"cdr_kwargs": ...})) when thecdr_forcingconstructor kwarg is set; the handler itself also no-ops ifcdr_kwargsis emptycdr_kwargsis merged via_build_input_args()and passed tort.CDRForcing(**input_args)Output paths are normalized to absolute strings
Updates ROMS-MARBL Blueprint:
Appends
Resource(s)toroms_marbl_blueprint_elements.cdr_forcing.data
Populates Settings:
Compile-time (
cppdefs):cdr_forcing = TrueRun-time (
cdr_frc):cdr_file="cdr.nc"(the executor/blueprint symlinks to the real path),cdr_source=True,ncdr_parm=len(cdr.releases),forcing_parameterized=True,cdr_volume=(cdr.releases.release_type == "volume")Run-time (
cdr_output):do_cdr_output = True
Corrections Forcing (forcing.corrections, order=90)¶
Handler: _generate_corrections()
Status: Registered but unwired — the resolver never emits a corrections category, so the step never enters input_list in production; the handler raises NotImplementedError
Source Resolution¶
_resolve_source_block() Method¶
Normalizes source blocks and injects file paths:
def _resolve_source_block(
self,
block: str | dict[str, Any],
time_window: tuple[datetime, datetime] | None = None,
) -> dict[str, Any]:
"""
Normalize a "source"/"bgc_source" block and inject a 'path' based on SourceData.
Parameters
----------
block : str or dict
Source specification (e.g., "GLORYS" or {"name": "GLORYS", "climatology": True})
time_window : tuple[datetime, datetime], optional
When given and the resolved path is a per-day file list, trims it to the files
covering that window (e.g. initial conditions only need `ini_time`'s day).
Returns
-------
dict
Source block with 'name' and optional 'path' fields
"""Process:
Normalize to dict: If string, convert to
{"name": str}Extract name: Get
namefield from dict (raises if a dict block has noname)Check streamability:
SourceData.streamable_for_source(name, glorys_layout=...)— if streamable (e.g. ERA5), don’t add a path unless one was explicitly providedGet path:
SourceData.path_for_source(name, glorys_layout=...)for non-streamable sourcesEither time-window trim (when
time_windowis given and the path is a multi-file list, viafilter_paths_by_time_window()) or subchunking (whensubchunkis on and the source is a multi-file GLORYS path: the path is replaced with a memoized kerchunk-subchunked reference,_subchunked_glorys_path()) — never both. A trimmed list deliberately skips the subchunk branch so the memoized reference is only ever built from the full file listReturn: Dict with
nameand optionalpath
SourceData.dataset_key_for_source() is used elsewhere (subchunk-reference memoization), not
inside this method.
Examples:
# String input
"GLORYS" → {"name": "GLORYS", "path": Path("/path/to/GLORYS_REGIONAL_file.nc")}
# Dict input
{"name": "UNIFIED", "climatology": True} → {"name": "UNIFIED", "climatology": True, "path": Path("/path/to/UNIFIED_BGC_file.nc")}
# Streamable source
"ERA5" → {"name": "ERA5"} # No path (streamable)_build_input_args() Method¶
Merges default arguments with runtime overrides:
def _build_input_args(
self,
key: str,
extra: dict[str, Any] | None = None,
base_kwargs: dict[str, Any] | None = None,
time_window: tuple[datetime, datetime] | None = None,
) -> dict[str, Any]:
"""
Merge per-input defaults with runtime arguments.
Uses base_kwargs (always provided from input_list).
Resolves "source" and "bgc_source" through SourceData.
Merges with extra, where extra overrides defaults.
"""Process:
Get base config:
base_kwargs, always supplied from aninput_listentry (there is no model-spec fallback)Resolve source blocks: Convert
sourceandbgc_sourcePydantic models to dicts with paths via_resolve_source_block()Unpack
options: an optionaloptionspassthrough dict in the item config is popped out and forwarded verbatim to the roms-tools constructorMerge:
cfg(base kwargs) <item_options<extra(extra always wins — it carries runtime injections like dates)If subchunking swapped a source path for a kerchunk reference and the merged args don’t already specify
chunks, setschunks={}so xarray/dask honors the reference’s native layout
Settings Population for Forcing¶
Compile-Time Settings¶
Surface Forcing:
cppdefs.sal_restore: set whentype == "restoring"and"sss"is inrestoring_forcescppdefs.co2_tvarying: set whentype == "bgc"andsource.name == "MBL_co2"
CDR Forcing:
cppdefs.cdr_forcing:Truewhen CDR forcing is generated
Boundary Forcing:
Compile-time settings are not populated by the boundary handler.
Tidal/River Forcing:
tidesandriver_frcare run-time sections, not compile-time — see below.
Run-Time Settings¶
Surface Forcing:
forcing.surface_forcing_path: Path to physics/restoring surface forcing fileforcing.surface_forcing_bgc_path: Path to bgc surface forcing fileblk_frc.interp_frc/bgc.interp_frc: 1 if the coarse grid was used, else 0
Boundary Forcing:
forcing.boundary_forcing_path: Path to physics boundary forcing fileforcing.boundary_forcing_bgc_path: Path to bgc boundary forcing file
Tidal Forcing:
tides.ntides: Number of tidal constituents actually generated (bry_tides/pot_tides/ana_tidesare owned by the resolver/model settings, not this handler)forcing.tidal_forcing_path: Path to tidal forcing file
River Forcing:
river_frc.river_source: Enable river source flagriver_frc.analytical: Analytical river flagriver_frc.nriv: Number of rivers (from generated dataset)river_frc.rvol_vname,river_frc.rvol_tname: River volume variable/time namesriver_frc.rtrc_vname,river_frc.rtrc_tname: River tracer variable/time namesforcing.river_path: Path to river forcing file
CDR Forcing:
cdr_frc.cdr_file,cdr_frc.cdr_source,cdr_frc.ncdr_parm,cdr_frc.forcing_parameterized,cdr_frc.cdr_volumecdr_output.do_cdr_output: forcedTruewhen CDR forcing is generated; also independently user-controllable (CDR output does not require CDR forcing)
ROMS-MARBL Blueprint Element Updates¶
Each handler appends Resource objects to the appropriate roms_marbl_blueprint element:
Resource Creation:
resource = Resource( # from cstar.orchestration.models
location=str(out_path), # path to generated NetCDF file
partitioned=False, # set to True after partitioning
)Blueprint Updates:
Grid:
roms_marbl_blueprint_elements.grid.data.append(resource)Initial Conditions:
roms_marbl_blueprint_elements.initial_conditions.data.append(resource)Forcing Categories:
roms_marbl_blueprint_elements.forcing.{category}.data.append(resource)forcing.surface→forcing.surface.dataforcing.boundary→forcing.boundary.dataforcing.tidal→forcing.tidal.dataforcing.river→forcing.river.data
CDR Forcing:
roms_marbl_blueprint_elements.cdr_forcing.data.append(resource)
File Partitioning¶
_partition_files() Method¶
Partitions whole-field input files across tiles:
def _partition_files(self, **kwargs):
"""
Partition whole input files across tiles using roms_tools.partition_netcdf.
Uses the paths stored in roms_marbl_blueprint_elements to build the list of whole-field files,
and records the partitioned paths in the Resource objects.
"""Process:
Iterate over input_list: For each input key, get corresponding dataset from
roms_marbl_blueprint_elementsPartition each Resource: Call
rt.partition_netcdf()for eachResource.locationCreate partitioned Resources: Replace original resources with partitioned ones
Update partitioned flag: Set
partitioned=Trueon new resources
Partitioning Arguments:
input_args = dict(
np_eta=self.partitioning.n_procs_y,
np_xi=self.partitioning.n_procs_x,
output_dir=self.input_data_dir,
include_coarse_dims=self.include_coarse_dims, # set during surface forcing generation
)Result:
Original whole-field files remain unchanged
Partitioned files created in
input_data_dirroms_marbl_blueprint_elementsupdated with partitionedResourceobjectspartitionedflag set toTrue
Return Value¶
generate_all() returns just roms_marbl_blueprint_elements: RomsMarblBlueprintInputData
(or None; see generate_all() above). The settings dicts are not returned -- they are the
executor-owned _settings_compile_time/_settings_run_time, mutated in place by generation:
Usage:
roms_marbl_blueprint_elements: Merged into the in-memoryRomsMarblBlueprintbygenerate_inputs(); persisted inconfigure_build()_settings_compile_time: Merged with template defaults, used to rendercppdefs.opt_settings_run_time: Merged with template defaults, used to writenamelist.nml(viawrite_roms_namelist)
ForgeExecutor.generate_inputs() (cstar_forge/forge/executor.py) passes its own
self._settings_compile_time/self._settings_run_time in by reference, so it already holds
the up-to-date settings after generate_all() returns -- no merge-back step.