core.CCModel

core.CCModel(
    variable_name,
    state_variables=None,
    non_integrated_state_vars=None,
    diagnostic_variables=None,
)

The overarching model structure for ClimateCritters.

CCModel serves as the archetype/parent class for models within the model_critters directory. It is not meant to be instantiated directly.

Parameter handling

Models may define a param_values dict that maps parameter names to constants, callables, or Forcing objects. Use get_param_value(name, t, state) inside dydt to resolve any of these uniformly.

To make a parameter state- or time-dependent after construction, assign a callable via set_param_value::

model.set_param_value('rho', lambda t, state: 28.0 + 0.1 * state[0])

To replace a computation method (e.g. calc_albedo) on a single instance without subclassing, use set_function.

External forcings

Use register_forcing to attach a time-varying external driver to any named parameter or state variable after construction::

model.register_forcing('S0', forcing_obj)                         # parameter
model.register_forcing('x', forcing_obj, 'additive', timing='pre')  # state

See register_forcing for the full contract and default timing rules.

Methods

Name Description
clear_forcings Remove registered forcings.
doc Pretty-print documentation for the requested category.
dydt Define the system of differential equations.
get_forcings Return registered forcings, optionally filtered by variable name.
get_param_value Resolve a named parameter to its value at the current time and state.
get_param_vector Resolve a parameter and broadcast it to a fixed-length vector.
integrate Integrate the model over a time span and return a :class:CCOutput.
list Return a list of names for the requested category.
populate_diagnostics_from_history Compute diagnostic variables from the full solved trajectory.
post_integrate Orchestrate post-solve output construction for uses_post_history models.
register_forcing Attach an external forcing to a named parameter or state variable.
set_function Swap out a model calculation function on a single instance.
set_param_value Add or update a parameter and keep the attribute and param_values in sync.
validate_initial_state Validate and normalize the initial state vector.

clear_forcings

core.CCModel.clear_forcings(var_name=None)

Remove registered forcings.

Parameters

var_name : str = None

If given, clear only the forcings for that variable. If omitted, clear all forcings on the model.

doc

core.CCModel.doc(print_target)

Pretty-print documentation for the requested category.

Descriptions are parsed from the NumPy-style docstrings of the class and its base classes. For parameters the current value is also shown.

Parameters

print_target : (state_variables, parameters, diagnostic_variables) = 'state_variables'

The category to document.

dydt

core.CCModel.dydt(t, y)

Define the system of differential equations.

Must be overridden by every subclass. The solver calls this at each timestep with the current time t and state vector y, and expects a list of derivatives of the same length as y. Use get_param inside the implementation to access parameters.

get_forcings

core.CCModel.get_forcings(var_name=None)

Return registered forcings, optionally filtered by variable name.

Parameters

var_name : str = None

If given, return the list of ForcingSpec objects for that variable. If omitted, return the full _forcings dict.

get_param_value

core.CCModel.get_param_value(name, t, state)

Resolve a named parameter to its value at the current time and state.

This is the standard way to access parameters inside dydt. It looks up the value from param_values by name and delegates resolution to _resolve_param, so callers in dydt don’t need to know whether a parameter is stored as a constant, a callable, or a Forcing object.

get_param_vector

core.CCModel.get_param_vector(name, t, state, size)

Resolve a parameter and broadcast it to a fixed-length vector.

Spatial models often allow parameters to be either a single scalar (applied uniformly) or a full grid-length array. This method resolves the parameter via get_param and then either broadcasts a scalar or validates that an array has the expected size, eliminating that boilerplate from every dydt that works on a spatial grid.

integrate

core.CCModel.integrate(
    t_span=None,
    y0=None,
    method='RK45',
    dt=None,
    output_time=None,
    run_name=None,
    kwargs=None,
)

Integrate the model over a time span and return a :class:CCOutput.

Parameters

t_span : tuple of float = None

(t0, tf) integration bounds for the solver.

y0 : array - like = None

Initial conditions. Length must match the number of integrated state variables.

method : str = 'RK45'

Solver to use: 'RK45' (default), 'euler', 'euler_maruyama', 'heun_maruyama', 'milstein', 'rk4', or any method accepted by scipy.integrate.solve_ivp. SDE solver guidance: * 'euler_maruyama' — strong order 0.5; baseline stochastic. * 'heun_maruyama' — strong order 1.0 for additive noise (diffusion independent of state); preferred for models like Melcher et al. (2025). * 'milstein' — strong order 1.0 for multiplicative noise (diffusion depends on state); uses a finite-difference approximation of ∂g/∂y, so no analytical Jacobian is required.

dt : float = None

Fixed timestep for euler, euler_maruyama, and rk4. Required for those methods.

output_time : array - like = None

If provided, the returned CCOutput is immediately reframed onto this time axis (e.g. to exclude a spin-up period). output.model_time always retains the raw solver grid.

run_name : str = None

Label stored on the output. Defaults to '<method>, dt=<dt>'.

kwargs : dict = None

Additional solver options. For solve_ivp methods these are forwarded directly (e.g. rtol, atol, t_eval). For euler_maruyama, random_seed is extracted here. For rk4, si (sampling interval) is extracted here. .. deprecated:: Passing dt inside kwargs is deprecated. Use the explicit dt parameter instead.

list

core.CCModel.list(list_target)

Return a list of names for the requested category.

Parameters

list_target : (state_variables, parameters, diagnostic_variables) = 'state_variables'

The category to enumerate.

Returns

names : list of str

populate_diagnostics_from_history

core.CCModel.populate_diagnostics_from_history(time, history)

Compute diagnostic variables from the full solved trajectory.

Called by post_integrate for models where uses_post_history = True. The base implementation does nothing because diagnostics are model-specific; subclasses override this to derive any quantities that can only be computed once the complete trajectory is available (e.g. derived fields, fluxes).

post_integrate

core.CCModel.post_integrate(time, history)

Orchestrate post-solve output construction for uses_post_history models.

Some models (e.g. spatial PDEs) cannot accumulate state during the solve without side effects; instead they store the full trajectory and derive all outputs here. This method sequences the required steps in the correct order: build the structured state array, set the time axis, populate diagnostics, and convert diagnostic lists to arrays. It is called automatically by integrate when uses_post_history = True.

register_forcing

core.CCModel.register_forcing(
    var_name,
    forcing_object,
    attachment_style=None,
    timing=None,
)

Attach an external forcing to a named parameter or state variable.

Parameters

var_name : str

Name of the target. Must exist in param_values (parameter namespace) or state_variables_names (state namespace). If the name appears in both, a ValueError is raised — this is a model design issue worth resolving explicitly.

forcing_object :

A Forcing instance, a callable f(t) → scalar/array, or any object with a get_forcing(t) method.

attachment_style : (replacement, additive) = "replacement"

How the forcing value is applied. * Parameters default to "replacement". "additive" is also supported and adds the forcing value to the nominal parameter at each step (e.g. k = k_0 + ε(t)). * State variables have no defaultattachment_style is required. This is intentional: injecting into a live state variable is a significant physical choice that should be explicit.

timing : (pre, post) = "pre"

When the forcing is applied relative to the integration step. Derived automatically in most cases: * parameter + any style → "pre" (always; no override) * state + replacement → "post" (always; warns if "pre" passed) * state + additive → required; raise if not provided

Raises

: ValueError

If var_name is not found, if attachment_style is missing for a state variable, if timing is missing for state + additive, or if a second "replacement" is registered on the same variable.

set_function

core.CCModel.set_function(name, function, bind=None)

Swap out a model calculation function on a single instance.

Subclassing is the right approach when a different formulation should apply everywhere, but for one-off experiments (e.g. testing an alternative albedo scheme without writing a new class) it is useful to replace a single method on one instance. The bind parameter handles whether the replacement expects self as its first argument.

Parameters

name : str

Name of an existing callable attribute (e.g., calc_k).

function : callable

Replacement callable.

bind : bool or None = None

True: bind as instance method (expects self as first arg). False: assign as a plain callable. None: infer from whether the first argument is named self or model.

set_param_value

core.CCModel.set_param_value(name, value)

Add or update a parameter and keep the attribute and param_values in sync.

__setattr__ syncs the direction model.alpha = v → param_values, but only for names already in param_values. This method handles the reverse and covers inserting new parameters that weren’t declared at initialization.

validate_initial_state

core.CCModel.validate_initial_state(y0)

Validate and normalize the initial state vector.

Exists as a method so that subclasses with non-standard initial state requirements (e.g. a spatially discretised model that accepts a scalar and broadcasts it to the grid) can override it. The base implementation delegates to the utility in utils/solver.