Model Management¶
Underworld3 Model Architecture
This module provides the Model class that serves as a central orchestrator for simulation components and object lifecycle management.
The Model object: - Eliminates circular references by becoming the central authority for mesh/swarms - Enables mesh swapping with automatic notification to dependent objects - Provides simple container for organizing simulation components - Supports serialization for model reuse and sharing
Design Philosophy: - Simple orchestration, not complex validation - Use existing sympy expressions, not separate parameter system - PETSc handles command-line options - Materials are just dictionaries of expressions/values
Model Class¶
- class underworld3.Model[source]¶
Bases:
PintNativeModelMixin,BaseModelCentral orchestrator for Underworld3 simulations.
Enhanced with Pydantic for validation, serialization, and configuration management while preserving the original design philosophy of simple orchestration.
The Model object manages: - Mesh and coordinate system lifecycle - Swarm registration and migration - Variable dependencies and updates - Parameter validation and propagation - Material definitions and assignments - Solver coordination
Benefits: - Eliminates circular references between components - Enables mesh swapping and dynamic reconfiguration - Provides single point for parameter management - Supports model composition and reuse - Enhanced serialization with YAML/JSON support - Optional validation with Pydantic
- Example:
>>> model = uw.Model() >>> model.set_mesh(mesh) >>> swarm = model.create_swarm() >>> temperature = model.add_variable("temperature", mesh, uw.VarType.SCALAR)
- model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'allow', 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- state: ModelState¶
- property mesh¶
The primary mesh for this model
- set_primary_mesh(mesh)[source]¶
Set a mesh as the primary mesh for this model.
Parameters:¶
- meshuw.discretisation.Mesh
Mesh to set as primary (must already be registered)
- set_mesh(mesh)[source]¶
Set or replace the primary mesh for this model.
This method handles: - Registering mesh if not already registered - Setting as primary mesh - Incrementing version for change tracking
Parameters:¶
- meshuw.discretisation.Mesh
The new mesh to use as primary for this model
- get_variable(name, mesh=None, swarm=None)[source]¶
Get a variable by name from the model registry.
Parameters:¶
- namestr
Variable name to look up
- meshMesh, optional
If provided, look for variable specifically on this mesh
- swarmSwarm, optional
If provided, look for variable specifically on this swarm
Returns:¶
Variable or None
- Parameters:
name (str)
- get_qualified_name(variable)[source]¶
Get the fully qualified name for a variable.
Returns the name that uniquely identifies this variable in the model registry, which may include mesh/swarm ID qualifiers to resolve namespace conflicts.
Parameters:¶
- variableMeshVariable or SwarmVariable
Variable to get qualified name for
Returns:¶
str or None : Qualified name if found, None otherwise
- transfer_variable_data(source_var, target_var)[source]¶
Transfer data from source variable to target variable using global_evaluate.
This enables persistent variable identity across mesh changes by transferring data from variables on old meshes to variables on new meshes.
Parameters:¶
- source_varMeshVariable or SwarmVariable
Source variable to transfer data from
- target_varMeshVariable or SwarmVariable
Target variable to transfer data to
Returns:¶
bool : True if transfer successful, False otherwise
- property tracker¶
Snapshot-managed record of where this run is.
Holds
time/step/dt(pre-seeded conventions) plus any quantity you assign —model.tracker.foo = .... Everything on the tracker is captured bysnapshot()and reverted byrestore(); loose Python variables are not. Solvers do not depend on it; using it is optional.
- save_state(*, file=None)[source]¶
Save the model’s current state — memory or disk, one entry point.
Without
file, captures an in-memorySnapshottoken suitable for in-run backtracking (“stash for timesteps”). The token is plain Python / numpy — fast to produce, fast to restore, does not survive the process.With
file=<path>, writes a persistent on-disk snapshot at that path (plus a sibling.bulk/directory holding the bulk PETSc + swarm sidecars). Survives the process; suitable for restart, postprocessing, transferring runs.Either way the captured state is the full model: all registered meshes and mesh-variables, all swarms with per-particle data, all solver-internal state-bearers (
ModelTracker,DDtinstances, anything else exposing theSnapshottablecontract).- Parameters:
file (str, optional) – Path to write a disk snapshot to. If omitted, an in-memory token is returned instead.
- Returns:
Snapshot – When called without
file— pass toload_state()to restore.str – When
fileis given — the path the snapshot was written to (same asfile).
- load_state(source)[source]¶
Restore the model from a previously saved state — memory or disk.
sourceis either:a
Snapshottoken returned by an earliersave_state()call (in-memory restore — bit-exact),a path string to a disk-snapshot file (disk restore — same-rank, same-model contract; mesh-rebuild on read is v1.2 scope).
- Raises:
TypeError –
sourceis neither aSnapshotnor a string.SnapshotInvalidatedError – The captured state no longer matches what is registered (mesh adapted, state-bearer missing, …).
- Return type:
None
- define_parameter(name, ptype=None, **kwargs)[source]¶
Define a new parameter with validation rules.
NOTE: Parameter system not yet implemented. Use model.materials dict directly.
- set_material(name, properties)[source]¶
Set material properties (simple dictionary).
Parameters:¶
- namestr
Material name (e.g., ‘mantle’, ‘crust’, ‘plume’)
- propertiesdict
Dictionary of property_name -> value/expression
Example:¶
>>> model.set_material('mantle', {'viscosity': 1e21, 'density': 3300})
- set_reference_quantities(verbose=False, nondimensional_scaling=True, **quantities)[source]¶
Set reference quantities for automatic units scaling.
This method enables the hybrid SymPy+Pint units workflow by allowing users to specify their problem in natural units, from which the system derives optimal scaling for numerical conditioning.
By default, this automatically enables non-dimensionalization for solvers, ensuring consistent behavior between user-facing units and solver internals.
- Parameters:
verbose (bool, optional) – If True, print diagnostic information about dimensional analysis and scale derivation. Default: False.
nondimensional_scaling (bool, optional) – Enable automatic non-dimensionalization for solvers (default: True). When True (recommended), solver operations work in non-dimensional [0-1] space while user-facing values remain in physical units. Set to False for expert mode (dimensional units only, no scaling). Disabling this may cause numerical conditioning issues.
**quantities (dict) – Named reference quantities using Pint units or UWQuantity objects, e.g.
domain_depth=uw.quantity(2900, "km").
- Raises:
RuntimeError – If called after a mesh has been created (units are locked)
Notes
This method creates a Pint-native registry with model-specific constants using the _constants pattern for optimal numerical conditioning.
The default behavior (nondimensional_scaling=True) ensures user-facing values in physical units, solver operations in well-conditioned non-dimensional [0-1] space, and automatic conversions.
- property fundamental_scales¶
Access the derived fundamental scales for dimensional analysis.
Returns the canonical fundamental scaling quantities [L], [M], [T], [θ] that were automatically derived from the reference quantities via dimensional analysis. These scales are used throughout the system for automatic non-dimensionalization.
The system extracts these fundamental scales from user-provided reference quantities (which can have any domain-specific names) through pure dimensional analysis. This provides a domain-agnostic API independent of parameter naming.
- Returns:
Dictionary mapping canonical dimension names to their scaling quantities: - ‘length’: Length scale [L] (e.g., 1000 m) - ‘time’: Time scale [T] (e.g., 1 Myr) - ‘mass’: Mass scale [M] (e.g., 1e24 kg) - ‘temperature’: Temperature scale [θ] (e.g., 1000 K) - Plus any additional dimensions (velocity, viscosity, pressure, etc.)
- Return type:
Example
>>> model = uw.get_default_model() >>> model.set_reference_quantities( ... domain_depth=uw.quantity(2900, "km"), ... plate_velocity=uw.quantity(5, "cm/year"), ... mantle_viscosity=uw.quantity(1e21, "Pa*s"), ... temperature_difference=uw.quantity(3000, "K") ... ) >>> # Access derived fundamental scales (NOT the user-provided reference quantities) >>> L0 = model.fundamental_scales['length'] # 2900 km >>> T0 = model.fundamental_scales['time'] # ~1.8 Myr >>> eta0 = model.fundamental_scales['viscosity'] # 1e21 Pa*s >>> DeltaT = model.fundamental_scales['temperature'] # 3000 K
Notes
These are the ROUNDED fundamental scales stored internally after dimensional analysis
The scales may have been rounded to nice values for O(1) numerical conditioning
Use these scales for physical interpretation of non-dimensional solutions
Do NOT use user-provided reference quantity names (domain-specific)
- validate_reference_quantities(raise_on_error=False)[source]¶
Validate that all registered variables with units have required reference quantities.
This method checks each variable and reports any missing reference quantities needed to properly derive scaling coefficients.
Parameters:¶
- raise_on_errorbool, optional
If True, raise ValueError on validation failure. If False (default), return validation results without raising.
Returns:¶
- dict
Validation results with keys: - ‘valid’: bool - Overall validation status - ‘warnings’: list of warning messages - ‘errors’: list of error messages
Example:¶
>>> model = uw.get_default_model() >>> model.set_reference_quantities(domain_depth=uw.quantity(1000, "km")) >>> mesh = uw.meshing.StructuredQuadBox(...) >>> v = uw.discretisation.MeshVariable('v', mesh, 2, degree=2, units='m/s') >>> result = model.validate_reference_quantities() >>> if not result['valid']: ... print("\n".join(result['errors']))
- get_coordinate_unit()[source]¶
Get the coordinate unit for this model.
Returns the length unit from reference quantities if set, otherwise returns None (dimensionless).
Returns:¶
- pint.Unit or None
Coordinate unit object (e.g., <Unit(‘kilometer’)>) or None if no units set
Example:¶
>>> model.set_reference_quantities(domain_depth=uw.quantity(500, "km")) >>> model.get_coordinate_unit() <Unit('kilometer')> # Or <Unit('megameter')> if using engineering rounding
Changed in 2025-10-16: Now returns pint.Unit objects instead of strings for consistency and to enable natural unit arithmetic (e.g., var.units / mesh.units).
- set_as_default()[source]¶
Explicitly set this model as the default model.
This is useful when working with multiple models (e.g., loading from disk) and you want to explicitly control which model is active.
Returns:¶
- Model
Returns self for method chaining
Example:¶
>>> model1 = uw.Model() >>> model2 = uw.Model() >>> model2.set_as_default() # Make model2 the active default >>> assert uw.get_default_model() is model2
- get_unit_aliases()[source]¶
Get all available unit aliases for user reference.
- Returns:
Dictionary mapping dimensions to their available aliases.
- Return type:
Examples
>>> model.get_unit_aliases() { 'length': { 'ascii': ['L_ref', 'L_scale', 'L_model', 'length_scale'], 'unicode': 'ℒ', 'display': 'ℒ', 'technical': '_1000km' }, ... }
- derive_fundamental_scalings()[source]¶
Derive fundamental scaling units (length, time, mass, temperature) from reference quantities.
This method analyzes the dimensional structure of reference quantities to automatically determine optimal fundamental scalings for the problem domain.
- Returns:
Dictionary of fundamental scalings with keys like ‘[length]’, ‘[time]’, ‘[mass]’, ‘[temperature]’
- Return type:
Examples
>>> model.set_reference_quantities( ... mantle_viscosity=1e21*uw.units.Pa*uw.units.s, ... plate_velocity=5*uw.units.cm/uw.units.year, ... mantle_temperature=1500*uw.units.K ... ) >>> scalings = model.derive_fundamental_scalings() >>> scalings['[length]'] # Derived from plate_velocity >>> scalings['[time]'] # Derived from plate_velocity >>> scalings['[temperature]'] # Direct from mantle_temperature
- get_fundamental_scales()[source]¶
Get fundamental scales in user-friendly format.
Returns the derived fundamental scaling quantities (length, time, mass, temperature) that the model uses for dimensional analysis. These are the base scales from which all other quantities are converted to model units.
IMPORTANT: Returns the ROUNDED scales stored in _fundamental_scales, not re-derived. The scales may have been rounded to nice values for O(1) numerical conditioning.
- Returns:
Dictionary mapping dimension names to their scaling quantities: - ‘length’: Length scale quantity (e.g., 1000 m, rounded from 500 m) - ‘time’: Time scale quantity (e.g., 1 Myr, rounded) - ‘mass’: Mass scale quantity (e.g., 1e11 kg, rounded) - ‘temperature’: Temperature scale quantity (e.g., 1000 K, rounded) - Plus any additional dimensions detected (current, substance, etc.)
- Return type:
Examples
>>> model.set_reference_quantities( ... domain_depth=500*uw.units.m, # Will round to 1000 m ... plate_velocity=5*uw.units.cm/uw.units.year, ... mantle_viscosity=1e21*uw.units.Pa*uw.units.s, ... mantle_temperature=1500*uw.units.K ... ) >>> scales = model.get_fundamental_scales() >>> scales['length'] # 1000 meter (rounded, not 500)
- get_scale_for_dimensionality(dimensionality)[source]¶
Get appropriate reference scale for given dimensionality.
First checks if user explicitly provided a reference quantity with this exact dimensionality (e.g., diffusivity=1e-6 m²/s). If found, uses that directly. Otherwise, computes from fundamental scales (length, time, mass, temperature).
This design ensures that explicit user-provided scales take precedence over derived scales, which is important for physical accuracy. For example, thermal diffusivity (~1e-6 m²/s) is orders of magnitude different from L²/t derived from mantle convection length and time scales.
- Parameters:
dimensionality (dict) – Pint dimensionality dictionary, e.g., {‘[length]’: 1, ‘[time]’: -1} for velocity, {‘[mass]’: 1, ‘[length]’: -1, ‘[time]’: -2} for pressure
- Returns:
Reference scale with appropriate dimensionality
- Return type:
pint.Quantity
- Raises:
ValueError – If dimensionality requires scales not available in fundamental scales
Examples
>>> model.set_reference_quantities(domain_depth=uw.quantity(2900, "km"), ...) >>> velocity_dim = {'[length]': 1, '[time]': -1} >>> v_scale = model.get_scale_for_dimensionality(velocity_dim) >>> # v_scale = 2900 km / (time_scale) in m/s
>>> pressure_dim = {'[mass]': 1, '[length]': -1, '[time]': -2} >>> p_scale = model.get_scale_for_dimensionality(pressure_dim) >>> # p_scale = M/(L·T²) in Pa
>>> # Explicit diffusivity takes precedence over L²/t >>> model.set_reference_quantities( ... length=uw.quantity(2900, "km"), ... time=uw.quantity(1e15, "s"), ... diffusivity=uw.quantity(1e-6, "m**2/s") # Explicit! ... ) >>> diff_dim = {'[length]': 2, '[time]': -1} >>> diff_scale = model.get_scale_for_dimensionality(diff_dim) >>> # diff_scale = 1e-6 m²/s (explicit), NOT L²/t = 8.41e-3 m²/s
- get_model_base_units()[source]¶
Get model base units in compact, parseable SI prefix form.
Returns a dictionary mapping dimension names to their compact SI unit representations. Uses Pint’s to_compact() to automatically select readable SI prefixes (e.g., ‘Mm’ for megameters, ‘Ps’ for petaseconds).
- Returns:
Dictionary with dimension names as keys and compact SI unit strings as values
- Return type:
Examples
>>> model.set_reference_quantities( ... mantle_depth=2900*uw.units.km, ... plate_velocity=5*uw.units.cm/uw.units.year, ... mantle_viscosity=1e21*uw.units.Pa*uw.units.s, ... mantle_temperature=1500*uw.units.K ... ) >>> base_units = model.get_model_base_units() >>> base_units['length'] # "2.9 megameter" (parseable) >>> base_units['time'] # "1.83 petasecond" (parseable)
- get_scale_summary()[source]¶
Get a human-readable summary of all fundamental scales.
Returns a formatted string showing the fundamental scales derived from reference quantities, including how each scale was derived and what reference quantities it makes close to unity.
- Returns:
Multi-line string with formatted scale summary
- Return type:
Examples
>>> model.set_reference_quantities( ... mantle_depth=2900*uw.units.km, ... plate_velocity=5*uw.units.cm/uw.units.year, ... mantle_viscosity=1e21*uw.units.Pa*uw.units.s, ... mantle_temperature=1500*uw.units.K ... ) >>> print(model.get_scale_summary()) Fundamental Scales Summary:
- Length Scale: 2900 kilometer
From: mantle_depth
Makes: mantle_depth ≈ 1.0 in model units
- Time Scale: 580 kilometer·year/centimeter
From: length_scale ÷ plate_velocity
Makes: plate_velocity ≈ 1.0 in model units
- Mass Scale: 1.68e+27 kg (equivalent)
From: mantle_viscosity × length_scale × time_scale
Makes: mantle_viscosity ≈ 1.0 in model units
- Temperature Scale: 1500 kelvin
From: mantle_temperature
Makes: mantle_temperature ≈ 1.0 in model units
- list_derived_scales()[source]¶
List which scales were derived vs. directly specified.
Returns a dictionary categorizing fundamental scales by how they were obtained: either directly from reference quantities or derived from compound quantities.
- Returns:
Dictionary with keys: - ‘direct’: List of (dimension, source) tuples for directly specified scales - ‘derived’: List of (dimension, derivation) tuples for derived scales - ‘missing’: List of standard dimensions that couldn’t be determined
- Return type:
Examples
>>> model.set_reference_quantities( ... mantle_depth=2900*uw.units.km, ... plate_velocity=5*uw.units.cm/uw.units.year, ... mantle_viscosity=1e21*uw.units.Pa*uw.units.s, ... mantle_temperature=1500*uw.units.K ... ) >>> derivation = model.list_derived_scales() >>> derivation['direct'] # [('length', 'mantle_depth'), ('temperature', 'mantle_temperature')] >>> derivation['derived'] # [('time', 'length_scale ÷ plate_velocity'), ('mass', 'mantle_viscosity × length_scale × time_scale')] >>> derivation['missing'] # []
- validate_dimensional_completeness(required_dimensions=None)[source]¶
Validate if reference quantities provide complete dimensional coverage.
Checks whether the current reference quantities span enough dimensions to derive fundamental scales for all required dimensions, and provides suggestions for completing under-determined systems.
- Parameters:
required_dimensions (list, optional) – List of dimensions required (e.g., [‘length’, ‘time’, ‘mass’, ‘temperature’]). If None, uses the standard 4-dimension set.
- Returns:
Validation result containing: - ‘status’: ‘complete’, ‘under_determined’, or ‘no_reference_quantities’ - ‘missing_dimensions’: List of missing dimensions (if any) - ‘suggestions’: List of suggested reference quantities to add - ‘derivable_dimensions’: List of dimensions that can be derived - ‘analysis’: Human-readable analysis string
- Return type:
Examples
>>> # Under-determined system >>> model.set_reference_quantities(mantle_depth=2900*uw.units.km) >>> result = model.validate_dimensional_completeness() >>> result['status'] # 'under_determined' >>> result['missing_dimensions'] # ['time', 'mass', 'temperature']
>>> # Complete system >>> model.set_reference_quantities( ... mantle_depth=2900*uw.units.km, ... plate_velocity=5*uw.units.cm/uw.units.year, ... mantle_viscosity=1e21*uw.units.Pa*uw.units.s, ... mantle_temperature=1500*uw.units.K ... ) >>> result = model.validate_dimensional_completeness() >>> result['status'] # 'complete'
- set_scaling_mode(mode='exact')[source]¶
Set the scaling mode for fundamental scales.
- Parameters:
mode ({'exact', 'readable'}) – Scaling mode to use: - ‘exact’: Reference quantities scale to exactly 1.0 (default) - ‘readable’: Reference quantities scale to O(1) with nice round numbers
Examples
>>> # Default exact mode: reference quantities become exactly 1.0 >>> model.set_scaling_mode('exact') >>> model.set_reference_quantities(mantle_depth=2900*uw.units.km) >>> model.to_model_units(2900*uw.units.km) # → UWQuantity(1.0, 'model_length_units')
>>> # Readable mode: reference quantities become O(1) with nice scales >>> model.set_scaling_mode('readable') >>> model.set_reference_quantities(mantle_depth=2900*uw.units.km) >>> model.to_model_units(2900*uw.units.km) # → UWQuantity(2.9, 'model_length_units') >>> # Internal scale becomes 1000 km instead of 2900 km
- get_scaling_mode()[source]¶
Get the current scaling mode.
- Returns:
Current scaling mode: ‘exact’ or ‘readable’
- Return type:
- show_optimal_units()[source]¶
Display the optimal units implied by this model’s reference quantities.
Shows fundamental scalings (length, time, mass, temperature) derived from reference quantities and suggests optimal units for various physical quantities.
- scale_to_physical(coordinates, dimension='length')[source]¶
Convert dimensionless model coordinates to physical units.
This method converts model-unit coordinate arrays (where the model domain is scaled to ~1.0) back to physical units using the model’s fundamental scales.
- Parameters:
coordinates (array-like) – Dimensionless coordinate array in model units
dimension (str, default 'length') – Fundamental dimension to use for scaling (‘length’, ‘time’, ‘mass’, ‘temperature’)
- Returns:
Coordinates in physical units with appropriate units
- Return type:
Examples
>>> model.set_reference_quantities(domain_length=1000*uw.units.km, ...) >>> mesh = uw.meshing.StructuredQuadBox(minCoords=(-3,-3), maxCoords=(3,3), ...) >>> # mesh.points are in model units (dimensionless, domain spans -3 to 3) >>> physical_coords = model.scale_to_physical(mesh.points) >>> # Result: coordinates in kilometers, spanning -3000 to 3000 km
- Raises:
ValueError – If no reference quantities set or dimension not available
- to_model_units(quantity)[source]¶
Safely coerce any quantity to model units using smart protocol pattern.
This method is designed to be safe to call repeatedly and handles edge cases: 1. Does nothing if model has no units (no reference quantities set) 2. Does nothing if the quantity is already in model units 3. Does nothing if the quantity is dimensionless 4. Uses protocol pattern for extensible conversion
- Parameters:
quantity (Any) – Quantity to convert (UWQuantity, Pint quantity, numeric, etc.)
- Returns:
Converted quantity in model units, or original if no conversion needed
- Return type:
UWQuantity or original quantity
- has_units_active()[source]¶
Check if the units system is active (reference quantities have been set).
- Returns:
True if reference quantities have been set, False otherwise.
- Return type:
- to_model_magnitude(quantity, expected_dimension=None)[source]¶
Convert quantity to model units and extract numerical magnitude.
Deprecated since version This: method is deprecated. Use
uw.scaling.non_dimensionalise()instead for consistent unit conversion across the codebase. The global scaling function ensures all conversions use the same COEFFICIENTS dictionary that is synchronized with model reference quantities.This is a convenience method that combines to_model_units() with magnitude extraction for internal use. It handles the common pattern of converting user inputs (which may have units) to raw numerical values in model units for internal computations.
- Parameters:
quantity (Any) – Quantity to convert (UWQuantity, Pint quantity, numeric, tuple, etc.)
expected_dimension (str, optional) – Expected dimension like ‘[length]’, ‘[time]’, etc. If provided and the quantity is a plain number when units are active, a warning is issued to alert the user that they may have forgotten units. Common values: ‘[length]’, ‘[time]’, ‘[temperature]’, ‘[mass]’
- Returns:
Raw numerical magnitude in model units (dimensionless)
- Return type:
Examples
>>> model.set_reference_quantities(length_scale=1000*uw.units.km) >>> coords_physical = [100*uw.units.km, 200*uw.units.km] >>> coords_model = model.to_model_magnitude(coords_physical) >>> coords_model [0.1, 0.2] # In model units (dimensionless)
>>> # Also works with plain numbers (pass-through) >>> model.to_model_magnitude([0.1, 0.2]) [0.1, 0.2]
>>> # With expected_dimension, warns on plain numbers when units active >>> model.to_model_magnitude(6370, expected_dimension='[length]') UserWarning: Plain number 6370 passed for [length] parameter when units are active. If you intended physical units, use uw.quantity(6370, 'km'). Value is being interpreted as 6370 model units.
>>> # Works with time >>> dt_physical = 1000 * uw.units.year >>> dt_model = model.to_model_magnitude(dt_physical)
Notes
This method is intended for internal use at API boundaries where user inputs need to be converted to model units for computations. The conversion respects dimensional analysis and reference quantities.
When expected_dimension is provided, this acts as a “gatekeeper” to catch potential bugs where users forget to attach units to their values.
- from_model_magnitude(magnitude, dimensions)[source]¶
Convert numerical magnitude in model units back to physical quantity.
Deprecated since version This: method is deprecated. Use
uw.scaling.dimensionalise()instead for consistent unit conversion across the codebase.This is the inverse of to_model_magnitude() - it takes a raw numerical value in model units and wraps it with appropriate physical units based on the dimensional specification.
- Parameters:
- Returns:
Physical quantity with appropriate units based on model reference scales
- Return type:
Examples
>>> model.set_reference_quantities(length_scale=1000*uw.units.km) >>> coords_model = np.array([0.1, 0.2]) # Model coordinates >>> coords_physical = model.from_model_magnitude(coords_model, '[length]') >>> coords_physical [100, 200] km # Back to physical units
>>> # Works with composite dimensions >>> velocity_model = 1.0 # Model velocity magnitude >>> velocity_physical = model.from_model_magnitude(velocity_model, '[length]/[time]')
>>> # If no reference quantities, returns SI base units >>> model_no_refs = uw.Model() >>> result = model_no_refs.from_model_magnitude(100, '[length]') >>> result 100 m # SI base units when no scaling defined
Notes
This method is intended for converting internal model-unit values back to physical quantities when returning results to users. It ensures consistent unit handling across API boundaries.
- to_dict()[source]¶
Export model configuration to dictionary for serialization.
Provides enhanced serialization with SymPy expression conversion and PETSc state capture for complete reproducibility.
- Returns:
Model configuration dictionary suitable for JSON/YAML export
- Return type:
- from_dict(config)[source]¶
Import model configuration from dictionary.
Handles enhanced serialization format with SymPy expression reconstruction. Note: Only imports materials and metadata for now. Mesh/variables/swarms must be recreated.
- Parameters:
config (dict) – Configuration dictionary from to_dict() or YAML export
- capture_petsc_state()[source]¶
Capture current PETSc options database state.
Returns all PETSc options currently set, enabling complete reproducibility of simulation parameters.
- Returns:
Dictionary of PETSc option names and values
- Return type:
- restore_petsc_state(petsc_options=None)[source]¶
Restore PETSc options database from captured state.
- Parameters:
petsc_options (dict, optional) – PETSc options to restore. If None, uses self.petsc_state
- view()[source]¶
Display comprehensive model information following the established view() pattern.
Shows model configuration, units setup, registered components, and provides guidance for setting up units if not configured.
- model_post_init(context, /)¶
This function is meant to behave like a BaseModel method to initialise private attributes.
It takes context as an argument since that’s what pydantic-core passes when calling it.
- Args:
self: The BaseModel instance. context: The context.
- Parameters:
self (BaseModel)
context (Any)
- Return type:
None
Model Functions¶
- underworld3.get_default_model()[source]¶
Get or create the default model for this UW3 session.
The default model automatically registers all meshes, swarms, variables, and solvers created during the session, enabling serialization and model orchestration without explicit user interaction.
- Returns:
The default model instance for this session
- Return type:
Example
>>> import underworld3 as uw >>> model = uw.get_default_model() >>> print(model) # See all registered objects >>> config = model.to_dict() # Serialize model
- underworld3.reset_default_model()[source]¶
Reset the default model to a fresh instance.
Useful for testing or starting a new simulation in an interactive session. All previously registered objects will be orphaned from the model registry.
Also resets global state including strict units mode to default (ON).
- Returns:
New default model instance
- Return type:
Example
>>> import underworld3 as uw >>> uw.reset_default_model() # Start fresh
Thermal Convection Configuration¶
- class underworld3.ThermalConvectionConfig[source]¶
Bases:
BaseModelConfiguration model for thermal convection simulations.
Demonstrates how to create specialized parameter configurations that work with the enhanced Model infrastructure.
- model_config: ClassVar[ConfigDict] = {'extra': 'allow'}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- underworld3.create_thermal_convection_model(config, name='thermal_convection')[source]¶
Create a Model instance configured for thermal convection.
Demonstrates integration between specialized configs and Model infrastructure.
- Parameters:
config (ThermalConvectionConfig) – Configuration object with all simulation parameters
name (str) – Model name
- Returns:
Configured model ready for thermal convection simulation
- Return type: