From 41ceb3b25f2cd6ee4df8c6a88282473b0159e93f Mon Sep 17 00:00:00 2001 From: Jonathan Citrin Date: Wed, 17 Apr 2024 11:29:18 -0700 Subject: [PATCH] Enable time-dependent non-evolved (prescribed) core_profiles. 1. Also took the opportunity to combine various utility functions for core_profile boundary conditions, dataclass updates, initial and prescribed evolving condition updates, all into a single renamed update_core_profiles module. 2. Updated the sim tests to work for both .nc and legacy .h5 reference files 3. Included a new config variable which can disable the prescribed evolution. Can be useful e.g. if a user wants to initialize density scaled to a Greenwald fraction, and keep density fixed even if Ip is evolving. PiperOrigin-RevId: 625751237 --- torax/boundary_conditions.py | 105 ----------- torax/config.py | 5 + torax/config_slice.py | 6 + torax/fvm/residual_and_loss.py | 4 +- torax/fvm/tests/fvm.py | 10 +- torax/sim.py | 51 +++-- .../sources/tests/bootstrap_current_source.py | 4 +- torax/sources/tests/fusion_heat_source.py | 4 +- torax/sources/tests/qei_source.py | 6 +- torax/sources/tests/source.py | 16 +- torax/sources/tests/source_models.py | 6 +- torax/sources/tests/test_lib.py | 10 +- torax/stepper/linear_theta_method.py | 1 + torax/stepper/nonlinear_theta_method.py | 1 + torax/stepper/stepper.py | 14 +- torax/tests/boundary_conditions.py | 7 +- torax/tests/physics.py | 6 +- torax/tests/sim.py | 82 ++++---- torax/tests/sim_custom_sources.py | 2 +- torax/tests/sim_no_compile.py | 4 +- torax/tests/sim_output_source_profiles.py | 4 +- torax/tests/state.py | 24 +-- .../test_prescribed_timedependent_ne.nc | Bin 0 -> 251719 bytes .../test_prescribed_timedependent_ne.py | 90 +++++++++ torax/tests/test_data/test_timedependence.py | 1 + torax/tests/test_lib/explicit_stepper.py | 4 +- torax/tests/test_lib/sim_test_case.py | 5 +- torax/transport_model/tests/qlknn_wrapper.py | 4 +- ...tial_states.py => update_core_profiles.py} | 175 +++++++++++++++++- torax/update_state.py | 66 ------- 30 files changed, 427 insertions(+), 290 deletions(-) delete mode 100644 torax/boundary_conditions.py create mode 100644 torax/tests/test_data/test_prescribed_timedependent_ne.nc create mode 100644 torax/tests/test_data/test_prescribed_timedependent_ne.py rename torax/{initial_states.py => update_core_profiles.py} (77%) delete mode 100644 torax/update_state.py diff --git a/torax/boundary_conditions.py b/torax/boundary_conditions.py deleted file mode 100644 index b5137d8f..00000000 --- a/torax/boundary_conditions.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright 2024 DeepMind Technologies Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Utilities for computing and updating the boundary conditions for State.""" - -import jax -from jax import numpy as jnp -from torax import config_slice -from torax import constants -from torax import geometry -from torax import jax_utils -from torax import physics - - -# Type-alias for brevity. -BoundaryConditionsMap = dict[str, dict[str, jax.Array | None]] - - -def compute_boundary_conditions( - dynamic_config_slice: config_slice.DynamicConfigSlice, - geo: geometry.Geometry, -) -> BoundaryConditionsMap: - """Computes boundary conditions for time t and returns updates to State. - - Args: - dynamic_config_slice: Runtime configuration at time t. - geo: Geometry object - - Returns: - Mapping from State attribute names to dictionaries updating attributes of - each CellVariable in the state. This dict can in theory recursively replace - values in a State object. - """ - Ip = dynamic_config_slice.profile_conditions.Ip # pylint: disable=invalid-name - Ti_bound_right = jax_utils.error_if_not_positive( # pylint: disable=invalid-name - dynamic_config_slice.profile_conditions.Ti_bound_right, 'Ti_bound_right' - ) - Te_bound_right = jax_utils.error_if_not_positive( # pylint: disable=invalid-name - dynamic_config_slice.profile_conditions.Te_bound_right, 'Te_bound_right' - ) - - # calculate ne_bound_right - # pylint: disable=invalid-name - nGW = ( - dynamic_config_slice.profile_conditions.Ip - / (jnp.pi * geo.Rmin**2) - * 1e20 - / dynamic_config_slice.nref - ) - # pylint: enable=invalid-name - ne_bound_right = jnp.where( - dynamic_config_slice.profile_conditions.ne_bound_right_is_fGW, - dynamic_config_slice.profile_conditions.ne_bound_right * nGW, - dynamic_config_slice.profile_conditions.ne_bound_right, - ) - # define ion profile based on (flat) Zeff and single assumed impurity - # with Zimp. main ion limited to hydrogenic species for now. - # Assume isotopic balance for DT fusion power. Solve for ni based on: - # Zeff = (ni + Zimp**2 * nimp)/ne ; nimp*Zimp + ni = ne - - dilution_factor = physics.get_main_ion_dilution_factor( - dynamic_config_slice.plasma_composition.Zimp, - dynamic_config_slice.plasma_composition.Zeff, - ) - return { - 'temp_ion': dict( - left_face_grad_constraint=jnp.zeros(()), - right_face_grad_constraint=None, - right_face_constraint=jnp.array(Ti_bound_right), - ), - 'temp_el': dict( - left_face_grad_constraint=jnp.zeros(()), - right_face_grad_constraint=None, - right_face_constraint=jnp.array(Te_bound_right), - ), - 'ne': dict( - left_face_grad_constraint=jnp.zeros(()), - right_face_grad_constraint=None, - right_face_constraint=jnp.array(ne_bound_right), - ), - 'ni': dict( - left_face_grad_constraint=jnp.zeros(()), - right_face_grad_constraint=None, - right_face_constraint=jnp.array(ne_bound_right * dilution_factor), - ), - 'psi': dict( - right_face_grad_constraint=Ip - * 1e6 - * constants.CONSTANTS.mu0 - / geo.G2_face[-1] - * geo.rmax, - right_face_constraint=None, - ), - } diff --git a/torax/config.py b/torax/config.py index d42758cd..972aa326 100644 --- a/torax/config.py +++ b/torax/config.py @@ -287,6 +287,11 @@ class Numerics: current_eq: bool = False # Solve the density equation (n evolves over time) dens_eq: bool = False + # Enable time-dependent prescribed profiles. + # This option is provided to allow initialization of density profiles scaled + # to a Greenwald fraction, and freeze this density even if the current is time + # evolving. Otherwise the density will evolve to always maintain that GW frac. + enable_prescribed_profile_evolution: bool = True # q-profile correction factor. Used only in ad-hoc circular geometry model q_correction_factor: float = 1.38 diff --git a/torax/config_slice.py b/torax/config_slice.py index 97e09ab9..abe11bcf 100644 --- a/torax/config_slice.py +++ b/torax/config_slice.py @@ -339,6 +339,12 @@ class DynamicNumerics: # location if n != neped largeValue_n: float + # Enable time-dependent prescribed profiles. + # This option is provided to allow initialization of density profiles scaled + # to a Greenwald fraction, and freeze this density even if the current is time + # evolving. Otherwise the density will evolve to always maintain that GW frac. + enable_prescribed_profile_evolution: bool + @chex.dataclass(frozen=True) class DynamicExponentialFormulaConfigSlice: diff --git a/torax/fvm/residual_and_loss.py b/torax/fvm/residual_and_loss.py index 33f7b20d..45906010 100644 --- a/torax/fvm/residual_and_loss.py +++ b/torax/fvm/residual_and_loss.py @@ -29,7 +29,7 @@ from torax import geometry from torax import jax_utils from torax import state -from torax import update_state +from torax import update_core_profiles from torax.fvm import block_1d_coeffs from torax.fvm import cell_variable from torax.fvm import discrete_system @@ -252,7 +252,7 @@ def theta_method_block_residual( x_new_guess = fvm_conversions.vec_to_cell_variable_tuple( x_new_guess_vec, core_profiles_t_plus_dt, evolving_names ) - core_profiles_t_plus_dt = update_state.update_core_profiles( + core_profiles_t_plus_dt = update_core_profiles.update_evolving_core_profiles( core_profiles_t_plus_dt, x_new_guess, evolving_names, diff --git a/torax/fvm/tests/fvm.py b/torax/fvm/tests/fvm.py index 288fc957..58c07b09 100644 --- a/torax/fvm/tests/fvm.py +++ b/torax/fvm/tests/fvm.py @@ -26,7 +26,7 @@ from torax import config_slice from torax import fvm from torax import geometry -from torax import initial_states +from torax import update_core_profiles from torax.fvm import implicit_solve_block from torax.fvm import residual_and_loss from torax.sources import source_config @@ -380,7 +380,7 @@ def test_nonlinear_solve_block_loss_minimum( dynamic_config_slice = config_slice.build_dynamic_config_slice(config) static_config_slice = config_slice.build_static_config_slice(config) source_models = source_models_lib.SourceModels() - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice, static_config_slice, geo, source_models) evolving_names = tuple(['temp_ion']) explicit_source_profiles = source_models_lib.build_source_profiles( @@ -495,7 +495,7 @@ def test_implicit_solve_block_uses_updated_boundary_conditions(self): config, ) source_models = source_models_lib.SourceModels() - initial_core_profiles = initial_states.initial_core_profiles( + initial_core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice, static_config_slice, geo, source_models ) explicit_source_profiles = source_models_lib.build_source_profiles( @@ -619,7 +619,7 @@ def test_theta_residual_uses_updated_boundary_conditions(self): config, ) source_models = source_models_lib.SourceModels() - initial_core_profiles = initial_states.initial_core_profiles( + initial_core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice, static_config_slice_theta0, geo, source_models ) explicit_source_profiles = source_models_lib.build_source_profiles( @@ -652,7 +652,7 @@ def test_theta_residual_uses_updated_boundary_conditions(self): right_face_grad_constraint=None, right_face_constraint=initial_right_boundary, ) - core_profiles_t_plus_dt = initial_states.initial_core_profiles( + core_profiles_t_plus_dt = update_core_profiles.initial_core_profiles( dynamic_config_slice, static_config_slice_theta0, geo ) core_profiles_t_plus_dt = dataclasses.replace( diff --git a/torax/sim.py b/torax/sim.py index e8378e76..0fea317d 100644 --- a/torax/sim.py +++ b/torax/sim.py @@ -33,16 +33,15 @@ from absl import logging import jax import jax.numpy as jnp -from torax import boundary_conditions from torax import calc_coeffs from torax import config as config_lib from torax import config_slice from torax import fvm from torax import geometry -from torax import initial_states from torax import jax_utils from torax import physics from torax import state +from torax import update_core_profiles from torax.sources import source_models as source_models_lib from torax.sources import source_profiles as source_profiles_lib from torax.spectators import spectator as spectator_lib @@ -77,6 +76,7 @@ class CoeffsCallback: Attributes: core_profiles_t: The core plasma profiles at the start of the time step. + core_profiles_t_plus_dt: Core plasma profiles at the end of the time step. evolving_names: The names of the evolving variables. geo: See the docstring for `stepper.Stepper`. static_config_slice: See the docstring for `stepper.Stepper`. @@ -88,6 +88,7 @@ class CoeffsCallback: def __init__( self, core_profiles_t: state.CoreProfiles, + core_profiles_t_plus_dt: state.CoreProfiles, evolving_names: tuple[str, ...], geo: geometry.Geometry, static_config_slice: config_slice.StaticConfigSlice, @@ -96,6 +97,7 @@ def __init__( source_models: source_models_lib.SourceModels, ): self.core_profiles_t = core_profiles_t + self.core_profiles_t_plus_dt = core_profiles_t_plus_dt self.evolving_names = evolving_names self.geo = geo self.static_config_slice = static_config_slice @@ -113,10 +115,14 @@ def __call__( explicit_call: bool = False, ): replace = {k: v for k, v in zip(self.evolving_names, x)} - # TODO( b/326579003) revisit due to prescribed profiles - core_profiles = config_lib.recursive_replace( - self.core_profiles_t, **replace - ) + if explicit_call: + core_profiles = config_lib.recursive_replace( + self.core_profiles_t, **replace + ) + else: + core_profiles = config_lib.recursive_replace( + self.core_profiles_t_plus_dt, **replace + ) # update ion density in core_profiles if ne is being evolved. # Necessary for consistency in iterative nonlinear solutions if 'ne' in self.evolving_names: @@ -300,7 +306,10 @@ def __call__( # PDE system. # TODO( b/326579003) core_profiles_t_plus_dt = provide_core_profiles_t_plus_dt( - core_profiles_t, dynamic_config_slice_t_plus_dt, geo + core_profiles_t=core_profiles_t, + dynamic_config_slice_t_plus_dt=dynamic_config_slice_t_plus_dt, + static_config_slice=static_config_slice, + geo=geo, ) stepper_iterations = 0 @@ -361,7 +370,10 @@ def body_fun( input_state.t + dt, ) core_profiles_t_plus_dt = provide_core_profiles_t_plus_dt( - core_profiles_t, dynamic_config_slice_t_plus_dt, geo + core_profiles_t=core_profiles_t, + dynamic_config_slice_t_plus_dt=dynamic_config_slice_t_plus_dt, + static_config_slice=static_config_slice, + geo=geo, ) core_profiles, core_sources, core_transport, stepper_error_state = ( self._stepper_fn( @@ -426,7 +438,7 @@ def get_initial_state( source_models: source_models_lib.SourceModels, ) -> state.ToraxSimState: """Returns the initial state to be used by run_simulation().""" - initial_core_profiles = initial_states.initial_core_profiles( + initial_core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice, static_config_slice, geo, source_models ) return state.ToraxSimState( @@ -1083,26 +1095,39 @@ def update_psidot( def provide_core_profiles_t_plus_dt( core_profiles_t: state.CoreProfiles, dynamic_config_slice_t_plus_dt: config_slice.DynamicConfigSlice, + static_config_slice: config_slice.StaticConfigSlice, geo: geometry.Geometry, ) -> state.CoreProfiles: """Provides state at t_plus_dt with new boundary conditions and prescribed profiles.""" - updated_boundary_conditions = boundary_conditions.compute_boundary_conditions( - dynamic_config_slice_t_plus_dt, - geo, + updated_boundary_conditions = ( + update_core_profiles.compute_boundary_conditions( + dynamic_config_slice_t_plus_dt, + geo, + ) + ) + updated_values = update_core_profiles.update_prescribed_core_profiles( + core_profiles=core_profiles_t, + dynamic_config_slice=dynamic_config_slice_t_plus_dt, + static_config_slice=static_config_slice, + geo=geo, ) temp_ion = dataclasses.replace( core_profiles_t.temp_ion, + value=updated_values['temp_ion'], **updated_boundary_conditions['temp_ion'], ) temp_el = dataclasses.replace( core_profiles_t.temp_el, + value=updated_values['temp_el'], **updated_boundary_conditions['temp_el'], ) psi = dataclasses.replace( core_profiles_t.psi, **updated_boundary_conditions['psi'] ) ne = dataclasses.replace( - core_profiles_t.ne, **updated_boundary_conditions['ne'] + core_profiles_t.ne, + value=updated_values['ne'], + **updated_boundary_conditions['ne'], ) ni = dataclasses.replace( core_profiles_t.ni, diff --git a/torax/sources/tests/bootstrap_current_source.py b/torax/sources/tests/bootstrap_current_source.py index f87d2675..24cb9888 100644 --- a/torax/sources/tests/bootstrap_current_source.py +++ b/torax/sources/tests/bootstrap_current_source.py @@ -20,7 +20,7 @@ from torax import config as config_lib from torax import config_slice from torax import geometry -from torax import initial_states +from torax import update_core_profiles from torax.sources import bootstrap_current_source from torax.sources import source as source_lib from torax.sources import source_config @@ -47,7 +47,7 @@ def test_source_value(self): source = bootstrap_current_source.BootstrapCurrentSource() config = config_lib.Config() geo = geometry.build_circular_geometry(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, diff --git a/torax/sources/tests/fusion_heat_source.py b/torax/sources/tests/fusion_heat_source.py index 67ddb540..09197120 100644 --- a/torax/sources/tests/fusion_heat_source.py +++ b/torax/sources/tests/fusion_heat_source.py @@ -21,7 +21,7 @@ import numpy as np from torax import config_slice from torax import constants -from torax import initial_states +from torax import update_core_profiles from torax.sources import fusion_heat_source from torax.sources import source from torax.sources import source_config @@ -61,7 +61,7 @@ def test_calc_fusion( geo = references.geo nref = config.nref - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, diff --git a/torax/sources/tests/qei_source.py b/torax/sources/tests/qei_source.py index c3bce91c..7bdda262 100644 --- a/torax/sources/tests/qei_source.py +++ b/torax/sources/tests/qei_source.py @@ -19,7 +19,7 @@ from torax import config as config_lib from torax import config_slice from torax import geometry -from torax import initial_states +from torax import update_core_profiles from torax.sources import qei_source from torax.sources import source as source_lib from torax.sources import source_config @@ -48,7 +48,7 @@ def test_source_value(self): source = qei_source.QeiSource() config = config_lib.Config() geo = geometry.build_circular_geometry(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, @@ -70,7 +70,7 @@ def test_invalid_source_types_raise_errors(self): source = qei_source.QeiSource() config = config_lib.Config() geo = geometry.build_circular_geometry(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, diff --git a/torax/sources/tests/source.py b/torax/sources/tests/source.py index b0ea20c2..b5983680 100644 --- a/torax/sources/tests/source.py +++ b/torax/sources/tests/source.py @@ -22,7 +22,7 @@ from torax import config as config_lib from torax import config_slice from torax import geometry -from torax import initial_states +from torax import update_core_profiles from torax.sources import source as source_lib from torax.sources import source_config from torax.sources import source_models as source_models_lib @@ -42,7 +42,7 @@ def test_zero_profile_works_by_default(self): sources={source.name: source_config.SourceConfig()} ) geo = geometry.build_circular_geometry(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, @@ -77,7 +77,7 @@ def test_unsupported_types_raise_errors(self): sources={source.name: source_config.SourceConfig()} ) geo = geometry.build_circular_geometry(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, @@ -112,7 +112,7 @@ def test_defaults_output_zeros(self): sources={source.name: source_config.SourceConfig()} ) geo = geometry.build_circular_geometry(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, @@ -166,7 +166,7 @@ def test_overriding_default_formula(self): sources={source.name: source_config.SourceConfig()} ) geo = geometry.build_circular_geometry(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, @@ -201,7 +201,7 @@ def test_overriding_model(self): sources={source.name: source_config.SourceConfig()} ) geo = geometry.build_circular_geometry(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, @@ -265,7 +265,7 @@ def test_custom_formula(self): numerics=config_lib.Numerics(nr=5), ) geo = geometry.build_circular_geometry(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, @@ -294,7 +294,7 @@ def test_multiple_profiles_raises_error(self): numerics=config_lib.Numerics(nr=5), ) geo = geometry.build_circular_geometry(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, diff --git a/torax/sources/tests/source_models.py b/torax/sources/tests/source_models.py index b17c9f59..a040c385 100644 --- a/torax/sources/tests/source_models.py +++ b/torax/sources/tests/source_models.py @@ -22,7 +22,7 @@ import torax # useful for setting up jax properly. from torax import config_slice from torax import geometry -from torax import initial_states +from torax import update_core_profiles from torax.sources import source as source_lib from torax.sources import source_config from torax.sources import source_models as source_models_lib @@ -46,7 +46,7 @@ def test_computing_source_profiles_works_with_all_defaults(self): dynamic_config_slice = config_slice.build_dynamic_config_slice(config) geo = torax.build_circular_geometry(config) source_models = source_models_lib.SourceModels() - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, @@ -153,7 +153,7 @@ def foo_formula(unused_dcs, geo: geometry.Geometry, unused_state): ) dynamic_config_slice = config_slice.build_dynamic_config_slice(config) geo = torax.build_circular_geometry(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, diff --git a/torax/sources/tests/test_lib.py b/torax/sources/tests/test_lib.py index ef11e28a..48956501 100644 --- a/torax/sources/tests/test_lib.py +++ b/torax/sources/tests/test_lib.py @@ -24,7 +24,7 @@ from torax import config as config_lib from torax import config_slice from torax import geometry -from torax import initial_states +from torax import update_core_profiles from torax.sources import source as source_lib from torax.sources import source_config as source_config_lib from torax.sources import source_models as source_models_lib @@ -103,7 +103,7 @@ def test_source_value(self): else: source_models = source_models_lib.SourceModels() geo = geometry.build_circular_geometry(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, @@ -122,7 +122,7 @@ def test_invalid_source_types_raise_errors(self): """Tests that using unsupported types raises an error.""" config = config_lib.Config() geo = geometry.build_circular_geometry(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, @@ -157,7 +157,7 @@ def test_source_value(self): self.assertIsInstance(source, source_lib.IonElectronSource) config = config_lib.Config() geo = geometry.build_circular_geometry(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, @@ -177,7 +177,7 @@ def test_invalid_source_types_raise_errors(self): """Tests that using unsupported types raises an error.""" config = config_lib.Config() geo = geometry.build_circular_geometry(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=config_slice.build_dynamic_config_slice(config), static_config_slice=config_slice.build_static_config_slice(config), geo=geo, diff --git a/torax/stepper/linear_theta_method.py b/torax/stepper/linear_theta_method.py index 0b8fa23d..95cba3da 100644 --- a/torax/stepper/linear_theta_method.py +++ b/torax/stepper/linear_theta_method.py @@ -67,6 +67,7 @@ def _x_new( # Instantiate coeffs_callback class coeffs_callback = self.callback_class( core_profiles_t=core_profiles_t, + core_profiles_t_plus_dt=core_profiles_t_plus_dt, evolving_names=evolving_names, geo=geo, static_config_slice=static_config_slice, diff --git a/torax/stepper/nonlinear_theta_method.py b/torax/stepper/nonlinear_theta_method.py index a8494325..f5f7a100 100644 --- a/torax/stepper/nonlinear_theta_method.py +++ b/torax/stepper/nonlinear_theta_method.py @@ -76,6 +76,7 @@ def _x_new( coeffs_callback = self.callback_class( core_profiles_t=core_profiles_t, + core_profiles_t_plus_dt=core_profiles_t_plus_dt, evolving_names=evolving_names, geo=geo, static_config_slice=static_config_slice, diff --git a/torax/stepper/stepper.py b/torax/stepper/stepper.py index f1166e36..04e8728a 100644 --- a/torax/stepper/stepper.py +++ b/torax/stepper/stepper.py @@ -25,7 +25,7 @@ from torax import fvm from torax import geometry from torax import state -from torax import update_state +from torax import update_core_profiles from torax.sources import source_models as source_models_lib from torax.sources import source_profiles from torax.transport_model import transport_model as transport_model_lib @@ -145,11 +145,13 @@ def __call__( core_transport = state.CoreTransport.zeros(geo) error = 0 - core_profiles_t_plus_dt = update_state.update_core_profiles( - core_profiles_t_plus_dt, - x_new, - evolving_names, - dynamic_config_slice_t_plus_dt, + core_profiles_t_plus_dt = ( + update_core_profiles.update_evolving_core_profiles( + core_profiles_t_plus_dt, + x_new, + evolving_names, + dynamic_config_slice_t_plus_dt, + ) ) return ( diff --git a/torax/tests/boundary_conditions.py b/torax/tests/boundary_conditions.py index 4ccde8f5..99409093 100644 --- a/torax/tests/boundary_conditions.py +++ b/torax/tests/boundary_conditions.py @@ -17,12 +17,11 @@ from absl.testing import absltest import numpy as np -from torax import boundary_conditions from torax import config as config_lib from torax import config_slice from torax import constants from torax import geometry -from torax import initial_states +from torax import update_core_profiles class BoundaryConditionsTest(absltest.TestCase): @@ -49,12 +48,12 @@ def test_setting_boundary_conditions(self): initial_dynamic_config_slice = config_slice.build_dynamic_config_slice( config ) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( initial_dynamic_config_slice, static_config_slice, geo ) dynamic_config_slice = config_slice.build_dynamic_config_slice(config, 0.5) - bc = boundary_conditions.compute_boundary_conditions( + bc = update_core_profiles.compute_boundary_conditions( dynamic_config_slice, geo, ) diff --git a/torax/tests/physics.py b/torax/tests/physics.py index 0175925a..10b971d6 100644 --- a/torax/tests/physics.py +++ b/torax/tests/physics.py @@ -22,7 +22,7 @@ from torax import config_slice from torax import constants from torax import geometry -from torax import initial_states +from torax import update_core_profiles from torax import physics from torax.sources import source_models as source_models_lib from torax.tests.test_lib import torax_refs @@ -106,12 +106,12 @@ def test_update_psi_from_j( # pylint: disable=protected-access if isinstance(geo, geometry.CircularGeometry): - currents = initial_states._prescribe_currents_no_bootstrap( + currents = update_core_profiles._prescribe_currents_no_bootstrap( dynamic_config_slice, geo, source_models=source_models_lib.SourceModels(), ) - psi = initial_states._update_psi_from_j( + psi = update_core_profiles._update_psi_from_j( dynamic_config_slice, geo, currents ).value elif isinstance(geo, geometry.CHEASEGeometry): diff --git a/torax/tests/sim.py b/torax/tests/sim.py index 9cd1d433..4bc2ae20 100644 --- a/torax/tests/sim.py +++ b/torax/tests/sim.py @@ -45,7 +45,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_explicit', 'test_explicit.py', - 'test_explicit', + 'test_explicit.h5', _ALL_PROFILES, 0, ), @@ -54,7 +54,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_crank_nicolson', 'test_crank_nicolson.py', - 'test_implicit', + 'test_implicit.h5', ('temp_ion', 'temp_el'), 2e-1, ), @@ -62,7 +62,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_implicit', 'test_implicit.py', - 'test_implicit', + 'test_implicit.h5', _ALL_PROFILES, 0, ), @@ -70,7 +70,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_qei', 'test_qei.py', - 'test_qei', + 'test_qei.h5', _ALL_PROFILES, 0, ), @@ -78,7 +78,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_arraytimestepcalculator', 'test_qei.py', - 'test_qei', + 'test_qei.h5', _ALL_PROFILES, 0, True, @@ -87,7 +87,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_pedestal', 'test_pedestal.py', - 'test_pedestal', + 'test_pedestal.h5', _ALL_PROFILES, 0, ), @@ -95,7 +95,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_cgmheat', 'test_cgmheat.py', - 'test_cgmheat', + 'test_cgmheat.h5', _ALL_PROFILES, 0, ), @@ -104,7 +104,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_semiimplicit_convection', 'test_semiimplicit_convection.py', - 'test_semiimplicit_convection', + 'test_semiimplicit_convection.h5', _ALL_PROFILES, 0, ), @@ -112,7 +112,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_qlknnheat', 'test_qlknnheat.py', - 'test_qlknnheat', + 'test_qlknnheat.h5', _ALL_PROFILES, 0, 1e-11, @@ -122,7 +122,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_fixed_dt', 'test_fixed_dt.py', - 'test_fixed_dt', + 'test_fixed_dt.h5', _ALL_PROFILES, 0, 1e-11, @@ -132,7 +132,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_psiequation', 'test_psiequation.py', - 'test_psiequation', + 'test_psiequation.h5', _ALL_PROFILES, 0, ), @@ -140,7 +140,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_psi_and_heat', 'test_psi_and_heat.py', - 'test_psi_and_heat', + 'test_psi_and_heat.h5', _ALL_PROFILES, 0, ), @@ -148,7 +148,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_absolute_jext', 'test_absolute_jext.py', - 'test_psi_and_heat', + 'test_psi_and_heat.h5', _ALL_PROFILES, 0, ), @@ -160,7 +160,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_newton_raphson_zeroiter', 'test_newton_raphson_zeroiter.py', - 'test_psi_and_heat', + 'test_psi_and_heat.h5', _ALL_PROFILES, 0, ), @@ -168,7 +168,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_bootstrap', 'test_bootstrap.py', - 'test_bootstrap', + 'test_bootstrap.h5', _ALL_PROFILES, 0, ), @@ -176,7 +176,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_psi_heat_dens', 'test_psi_heat_dens.py', - 'test_psi_heat_dens', + 'test_psi_heat_dens.h5', _ALL_PROFILES, 0, ), @@ -184,7 +184,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_particle_sources_constant', 'test_particle_sources_constant.py', - 'test_particle_sources_constant', + 'test_particle_sources_constant.h5', _ALL_PROFILES, 0, ), @@ -192,7 +192,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_particle_sources_cgm', 'test_particle_sources_cgm.py', - 'test_particle_sources_cgm', + 'test_particle_sources_cgm.h5', _ALL_PROFILES, 0, ), @@ -200,7 +200,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_fusion_power', 'test_fusion_power.py', - 'test_fusion_power', + 'test_fusion_power.h5', _ALL_PROFILES, 0, ), @@ -208,7 +208,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_all_transport_fusion_qlknn', 'test_all_transport_fusion_qlknn.py', - 'test_all_transport_fusion_qlknn', + 'test_all_transport_fusion_qlknn.h5', _ALL_PROFILES, 0, ), @@ -216,7 +216,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_chease', 'test_chease.py', - 'test_chease', + 'test_chease.h5', _ALL_PROFILES, 0, ), @@ -224,7 +224,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_ohmic_power', 'test_ohmic_power.py', - 'test_ohmic_power', + 'test_ohmic_power.h5', _ALL_PROFILES, 0, ), @@ -232,7 +232,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_qei_chease_highdens', 'test_qei_chease_highdens.py', - 'test_qei_chease_highdens', + 'test_qei_chease_highdens.h5', _ALL_PROFILES, 0, ), @@ -240,7 +240,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_psichease_ip_parameters', 'test_psichease_ip_parameters.py', - 'test_psichease_ip_parameters', + 'test_psichease_ip_parameters.h5', _ALL_PROFILES, 0, ), @@ -248,7 +248,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_psichease_ip_chease', 'test_psichease_ip_chease.py', - 'test_psichease_ip_chease', + 'test_psichease_ip_chease.h5', _ALL_PROFILES, 0, ), @@ -256,7 +256,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_psichease_prescribed_jtot', 'test_psichease_prescribed_jtot.py', - 'test_psichease_prescribed_jtot', + 'test_psichease_prescribed_jtot.h5', _ALL_PROFILES, 0, ), @@ -264,7 +264,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_psichease_prescribed_johm', 'test_psichease_prescribed_johm.py', - 'test_psichease_prescribed_johm', + 'test_psichease_prescribed_johm.h5', _ALL_PROFILES, 0, ), @@ -272,7 +272,15 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_timedependence', 'test_timedependence.py', - 'test_timedependence', + 'test_timedependence.h5', + _ALL_PROFILES, + 0, + ), + # Tests prescribed time-dependent ne (tied to GW frac with evolving Ip). + ( + 'test_prescribed_timedependent_ne', + 'test_prescribed_timedependent_ne.py', + 'test_prescribed_timedependent_ne.nc', _ALL_PROFILES, 0, ), @@ -281,7 +289,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_ne_qlknn_defromchie', 'test_ne_qlknn_defromchie.py', - 'test_ne_qlknn_defromchie', + 'test_ne_qlknn_defromchie.h5', _ALL_PROFILES, 0, ), @@ -289,7 +297,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_ne_qlknn_deff_veff', 'test_ne_qlknn_deff_veff.py', - 'test_ne_qlknn_deff_veff', + 'test_ne_qlknn_deff_veff.h5', _ALL_PROFILES, 0, ), @@ -297,7 +305,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_all_transport_crank_nicolson', 'test_all_transport_crank_nicolson.py', - 'test_all_transport_crank_nicolson', + 'test_all_transport_crank_nicolson.h5', _ALL_PROFILES, 0, ), @@ -306,7 +314,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_pc_method_ne', 'test_pc_method_ne.py', - 'test_pc_method_ne', + 'test_pc_method_ne.h5', _ALL_PROFILES, 0, ), @@ -314,7 +322,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_iterbaseline_mockup', 'test_iterbaseline_mockup.py', - 'test_iterbaseline_mockup', + 'test_iterbaseline_mockup.h5', _ALL_PROFILES, 1e-10, ), @@ -322,7 +330,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_iterhybrid_mockup', 'test_iterhybrid_mockup.py', - 'test_iterhybrid_mockup', + 'test_iterhybrid_mockup.h5', _ALL_PROFILES, 0, ), @@ -331,7 +339,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_iterhybrid_predictor_corrector', 'test_iterhybrid_predictor_corrector.py', - 'test_iterhybrid_predictor_corrector', + 'test_iterhybrid_predictor_corrector.h5', _ALL_PROFILES, 0, ), @@ -339,7 +347,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_iterhybrid_newton', 'test_iterhybrid_newton.py', - 'test_iterhybrid_newton', + 'test_iterhybrid_newton.h5', _ALL_PROFILES, 0, ), @@ -349,7 +357,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_iterhybrid_rampup', 'test_iterhybrid_rampup.py', - 'test_iterhybrid_rampup', + 'test_iterhybrid_rampup.h5', _ALL_PROFILES, 0, 1e-9 diff --git a/torax/tests/sim_custom_sources.py b/torax/tests/sim_custom_sources.py index 54c8abc8..f51d8cee 100644 --- a/torax/tests/sim_custom_sources.py +++ b/torax/tests/sim_custom_sources.py @@ -126,7 +126,7 @@ def custom_source_formula(dynamic_config, geo, unused_state): # Load reference profiles ref_profiles, ref_time = self._get_refs( - 'test_particle_sources_constant', _ALL_PROFILES + 'test_particle_sources_constant.h5', _ALL_PROFILES ) # Set up the sim with the original config. We set up the sim only once and diff --git a/torax/tests/sim_no_compile.py b/torax/tests/sim_no_compile.py index 25b19ec1..4ab90b86 100644 --- a/torax/tests/sim_no_compile.py +++ b/torax/tests/sim_no_compile.py @@ -32,7 +32,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_implicit_optimizer_no_compile', 'test_implicit_short_optimizer.py', - 'test_implicit_short', + 'test_implicit_short.h5', _ALL_PROFILES, 1e-5, None, @@ -43,7 +43,7 @@ class SimTest(sim_test_case.SimTestCase): ( 'test_qlknnheat', 'test_qlknnheat.py', - 'test_qlknnheat', + 'test_qlknnheat.h5', _ALL_PROFILES, 0, 1e-11, diff --git a/torax/tests/sim_output_source_profiles.py b/torax/tests/sim_output_source_profiles.py index cff2aca9..fc13ed03 100644 --- a/torax/tests/sim_output_source_profiles.py +++ b/torax/tests/sim_output_source_profiles.py @@ -26,7 +26,7 @@ from torax import config as config_lib from torax import config_slice from torax import geometry -from torax import initial_states +from torax import update_core_profiles from torax import sim as sim_lib from torax import state as state_module from torax.fvm import cell_variable @@ -72,7 +72,7 @@ def test_merging_source_profiles(self): source_models=source_models, value=2.0, ) - qei_core_profiles = initial_states.initial_core_profiles( + qei_core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice=dynamic_config_slice, static_config_slice=static_config_slice, geo=geo, diff --git a/torax/tests/state.py b/torax/tests/state.py index b385cc1e..b398b9af 100644 --- a/torax/tests/state.py +++ b/torax/tests/state.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Unit tests for torax.state and torax.initial_states.""" +"""Unit tests for torax.state and torax.update_core_profiles.""" import functools from typing import Callable @@ -25,7 +25,7 @@ from torax import config as config_lib from torax import config_slice from torax import geometry -from torax import initial_states +from torax import update_core_profiles from torax import state from torax.sources import source_models as source_models_lib from torax.tests.test_lib import torax_refs @@ -44,7 +44,7 @@ def make_hist(config, geo): initial_counter = jnp.array(0) def scan_f(counter: jax.Array, _) -> tuple[jax.Array, state.CoreProfiles]: - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( config_slice.build_dynamic_config_slice(config), config_slice.build_static_config_slice(config), geo, @@ -82,7 +82,7 @@ def test_sanity_check( ): """Make sure State.sanity_check can be called.""" references = references_getter() - basic_core_profiles = initial_states.initial_core_profiles( + basic_core_profiles = update_core_profiles.initial_core_profiles( config_slice.build_dynamic_config_slice(references.config), config_slice.build_static_config_slice(references.config), references.geo, @@ -134,7 +134,7 @@ def test_project( class InitialStatesTest(parameterized.TestCase): - """Unit tests for the `torax.initial_states` module.""" + """Unit tests for the `torax.update_core_profiles` module.""" def test_initial_boundary_condition_from_time_dependent_params(self): """Tests that the initial boundary conditions are set from the config.""" @@ -150,7 +150,7 @@ def test_initial_boundary_condition_from_time_dependent_params(self): ), ), ) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( config_slice.build_dynamic_config_slice(config), config_slice.build_static_config_slice(config), geometry.build_circular_geometry(config), @@ -207,22 +207,22 @@ def test_initial_psi_from_j( ), ) geo = geo_builder(config1) - core_profiles1 = initial_states.initial_core_profiles( + core_profiles1 = update_core_profiles.initial_core_profiles( config_slice.build_dynamic_config_slice(config1), config_slice.build_static_config_slice(config1), geo=geo, ) - core_profiles2 = initial_states.initial_core_profiles( + core_profiles2 = update_core_profiles.initial_core_profiles( config_slice.build_dynamic_config_slice(config2), config_slice.build_static_config_slice(config2), geo=geo, ) - core_profiles3 = initial_states.initial_core_profiles( + core_profiles3 = update_core_profiles.initial_core_profiles( config_slice.build_dynamic_config_slice(config3), config_slice.build_static_config_slice(config3), geo=geo, ) - core_profiles3_helper = initial_states.initial_core_profiles( + core_profiles3_helper = update_core_profiles.initial_core_profiles( config_slice.build_dynamic_config_slice(config3_helper), config_slice.build_static_config_slice(config3_helper), geo=geo, @@ -299,12 +299,12 @@ def test_initial_psi_from_geo_noop_circular(self): config2 = config_lib.Config( initial_psi_from_j=True, ) - core_profiles1 = initial_states.initial_core_profiles( + core_profiles1 = update_core_profiles.initial_core_profiles( config_slice.build_dynamic_config_slice(config1), config_slice.build_static_config_slice(config1), geometry.build_circular_geometry(config1), ) - core_profiles2 = initial_states.initial_core_profiles( + core_profiles2 = update_core_profiles.initial_core_profiles( config_slice.build_dynamic_config_slice(config2), config_slice.build_static_config_slice(config2), geometry.build_circular_geometry(config2), diff --git a/torax/tests/test_data/test_prescribed_timedependent_ne.nc b/torax/tests/test_data/test_prescribed_timedependent_ne.nc new file mode 100644 index 0000000000000000000000000000000000000000..eeba789fa922995153c111eb0caf0e23607c5a66 GIT binary patch literal 251719 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 av#kJi9bHAkPG5o)F338jFRA+5dHx60N620P literal 0 HcmV?d00001 diff --git a/torax/tests/test_data/test_prescribed_timedependent_ne.py b/torax/tests/test_data/test_prescribed_timedependent_ne.py new file mode 100644 index 00000000..fb4c4fe7 --- /dev/null +++ b/torax/tests/test_data/test_prescribed_timedependent_ne.py @@ -0,0 +1,90 @@ +# Copyright 2024 DeepMind Technologies Limited +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tests time dependent boundary conditions and sources. + +Ip from parameters. implicit + pereverzev-corrigan, Ti+Te+Psi, Pei standard +dens, pedestal, chi from QLKNN. Includes time dependent Ip, Ptot, and +pedestal, mocking up current-overshoot and an LH transition +""" + +from torax import config as config_lib +from torax import geometry +from torax import sim as sim_lib +from torax.sources import source_config +from torax.stepper import linear_theta_method + + +def get_config() -> config_lib.Config: + return config_lib.Config( + profile_conditions=config_lib.ProfileConditions( + Ti_bound_left=10, + Te_bound_left=10, + Ip={0: 5, 4: 15, 6: 12, 8: 12}, + Tiped={0: 2, 4: 2, 6: 5, 8: 4}, + Teped={0: 2, 4: 2, 6: 5, 8: 4}, + ), + numerics=config_lib.Numerics( + current_eq=True, + resistivity_mult=50, # to shorten current diffusion time for the test + bootstrap_mult=0, # remove bootstrap current + dtmult=150, + maxdt=0.5, + t_final=10, + enable_prescribed_profile_evolution=True, + ), + w=0.18202270915319393, + S_pellet_tot=0, + S_puff_tot=0, + S_nbi_tot=0, + Ptot={0: 20e6, 9: 20e6, 10: 120e6, 15: 120e6}, + transport=config_lib.TransportConfig( + transport_model="qlknn", + apply_inner_patch=True, + chii_inner=2.0, + chie_inner=2.0, + rho_inner=0.3, + ), + solver=config_lib.SolverConfig( + predictor_corrector=False, + use_pereverzev=True, + ), + sources=dict( + fusion_heat_source=source_config.SourceConfig( + source_type=source_config.SourceType.ZERO, + ), + ohmic_heat_source=source_config.SourceConfig( + source_type=source_config.SourceType.ZERO, + ), + ), + ) + + +def get_geometry(config: config_lib.Config) -> geometry.Geometry: + return geometry.build_chease_geometry( + config, + geometry_file="ITER_hybrid_citrin_equil_cheasedata.mat2cols", + Ip_from_parameters=True, + ) + + +def get_sim() -> sim_lib.Sim: + # This approach is currently lightweight because so many objects require + # config for construction, but over time we expect to transition to most + # config taking place via constructor args in this function. + config = get_config() + geo = get_geometry(config) + return sim_lib.build_sim_from_config( + config, geo, linear_theta_method.LinearThetaMethod + ) diff --git a/torax/tests/test_data/test_timedependence.py b/torax/tests/test_data/test_timedependence.py index fd848b12..945308cf 100644 --- a/torax/tests/test_data/test_timedependence.py +++ b/torax/tests/test_data/test_timedependence.py @@ -42,6 +42,7 @@ def get_config() -> config_lib.Config: dtmult=150, maxdt=0.5, t_final=10, + enable_prescribed_profile_evolution=False, ), w=0.18202270915319393, S_pellet_tot=0, diff --git a/torax/tests/test_lib/explicit_stepper.py b/torax/tests/test_lib/explicit_stepper.py index 7e7a8259..0a51af35 100644 --- a/torax/tests/test_lib/explicit_stepper.py +++ b/torax/tests/test_lib/explicit_stepper.py @@ -23,13 +23,13 @@ import jax from jax import numpy as jnp -from torax import boundary_conditions from torax import config_slice from torax import constants from torax import fvm from torax import geometry from torax import physics from torax import state +from torax import update_core_profiles from torax.sources import source_models from torax.sources import source_profiles from torax.stepper import stepper as stepper_lib @@ -110,7 +110,7 @@ def __call__( ) # Update the potentially time-dependent boundary conditions as well. updated_boundary_conditions = ( - boundary_conditions.compute_boundary_conditions( + update_core_profiles.compute_boundary_conditions( dynamic_config_slice_t_plus_dt, geo, ) diff --git a/torax/tests/test_lib/sim_test_case.py b/torax/tests/test_lib/sim_test_case.py index 766fd286..8f930829 100644 --- a/torax/tests/test_lib/sim_test_case.py +++ b/torax/tests/test_lib/sim_test_case.py @@ -59,7 +59,7 @@ def setUp(self): self.test_data_dir = os.path.join(src_dir, torax_dir, 'tests/test_data') def _expected_results_path(self, test_name: str) -> str: - return os.path.join(self.test_data_dir, f'{test_name}.h5') + return os.path.join(self.test_data_dir, f'{test_name}') def _get_config_module( self, @@ -228,8 +228,7 @@ def _test_torax_sim( Args: config_name: Name of py config to load. (Leave off dir path, include ".py") - ref_name: Name of h5 reference solution to load. (Leave off dir path, - ".h5") + ref_name: Name of reference filename to load. (Leave off dir path) profiles: List of names of variables to check. rtol: Optional float, to override the class level rtol. atol: Optional float, to override the class level atol. diff --git a/torax/transport_model/tests/qlknn_wrapper.py b/torax/transport_model/tests/qlknn_wrapper.py index b2e1b406..7c4299e0 100644 --- a/torax/transport_model/tests/qlknn_wrapper.py +++ b/torax/transport_model/tests/qlknn_wrapper.py @@ -20,7 +20,7 @@ from torax import config as config_lib from torax import config_slice from torax import geometry -from torax import initial_states +from torax import update_core_profiles from torax.transport_model import qlknn_wrapper @@ -38,7 +38,7 @@ def test_qlknn_wrapper_cache_works(self): geo = geometry.build_circular_geometry(config) dynamic_config_slice = config_slice.build_dynamic_config_slice(config) static_config_slice = config_slice.build_static_config_slice(config) - core_profiles = initial_states.initial_core_profiles( + core_profiles = update_core_profiles.initial_core_profiles( dynamic_config_slice, static_config_slice, geo ) qlknn_jitted(dynamic_config_slice, geo, core_profiles) diff --git a/torax/initial_states.py b/torax/update_core_profiles.py similarity index 77% rename from torax/initial_states.py rename to torax/update_core_profiles.py index 93be8349..72aec5eb 100644 --- a/torax/initial_states.py +++ b/torax/update_core_profiles.py @@ -466,8 +466,7 @@ def _update_psi_from_j( ) scale = jnp.concatenate(( jnp.zeros((1,)), - constants.CONSTANTS.mu0 - / (2 * jnp.pi * geo.Rmaj * geo.G2_hires[1:]), + constants.CONSTANTS.mu0 / (2 * jnp.pi * geo.Rmaj * geo.G2_hires[1:]), )) # dpsi_dr on the cell grid dpsi_dr_hires = scale * integrated @@ -649,6 +648,178 @@ def initial_core_profiles( return core_profiles +def update_prescribed_core_profiles( + core_profiles: state.CoreProfiles, + dynamic_config_slice: config_slice.DynamicConfigSlice, + static_config_slice: config_slice.StaticConfigSlice, + geo: Geometry, +) -> dict[str, jax.Array]: + """Updates core profiles which are not being evolved by PDE. + + Uses same functions as for profile initialization. + + Args: + core_profiles: Core profiles dataclass to be updated + dynamic_config_slice: Dynamic configuration parameters at t=t_initial. + static_config_slice: Static simulation configuration parameters. + geo: Torus geometry. + + Returns: + Updated core profiles. + """ + # pylint: disable=invalid-name + + # If profiles are not evolved, they can still potential be time-evolving, + # depending on the config. If so, they are updated below. + if ( + not static_config_slice.ion_heat_eq + and dynamic_config_slice.numerics.enable_prescribed_profile_evolution + ): + temp_ion = _update_ti(dynamic_config_slice, static_config_slice, geo).value + else: + temp_ion = core_profiles.temp_ion.value + if ( + not static_config_slice.el_heat_eq + and dynamic_config_slice.numerics.enable_prescribed_profile_evolution + ): + temp_el = _update_te(dynamic_config_slice, static_config_slice, geo).value + else: + temp_el = core_profiles.temp_el.value + if ( + not static_config_slice.dens_eq + and dynamic_config_slice.numerics.enable_prescribed_profile_evolution + ): + ne, _ = _update_dens(dynamic_config_slice, static_config_slice, geo) + ne = ne.value + else: + ne = core_profiles.ne.value + + return {'temp_ion': temp_ion, 'temp_el': temp_el, 'ne': ne} + + +def update_evolving_core_profiles( + core_profiles: state.CoreProfiles, + x_new: tuple[fvm.cell_variable.CellVariable, ...], + evolving_names: tuple[str, ...], + dynamic_config_slice: config_slice.DynamicConfigSlice, +) -> state.CoreProfiles: + """Returns the new core profiles after updating the evolving variables. + + Args: + core_profiles: The old set of core plasma profiles. + x_new: The new values of the evolving variables. + evolving_names: The names of the evolving variables. + dynamic_config_slice: The dynamic config slice. + """ + + def get_update(x_new, var): + """Returns the new value of `var`.""" + if var in evolving_names: + return x_new[evolving_names.index(var)] + # `var` is not evolving, so its new value is just its old value + return getattr(core_profiles, var) + + temp_ion = get_update(x_new, 'temp_ion') + temp_el = get_update(x_new, 'temp_el') + psi = get_update(x_new, 'psi') + ne = get_update(x_new, 'ne') + ni = dataclasses.replace( + core_profiles.ni, + value=ne.value + * physics.get_main_ion_dilution_factor( + dynamic_config_slice.plasma_composition.Zimp, + dynamic_config_slice.plasma_composition.Zeff, + ), + ) + + return dataclasses.replace( + core_profiles, + temp_ion=temp_ion, + temp_el=temp_el, + psi=psi, + ne=ne, + ni=ni, + ) + + +def compute_boundary_conditions( + dynamic_config_slice: config_slice.DynamicConfigSlice, + geo: geometry.Geometry, +) -> dict[str, dict[str, jax.Array | None]]: + """Computes boundary conditions for time t and returns updates to State. + + Args: + dynamic_config_slice: Runtime configuration at time t. + geo: Geometry object + + Returns: + Mapping from State attribute names to dictionaries updating attributes of + each CellVariable in the state. This dict can in theory recursively replace + values in a State object. + """ + Ip = dynamic_config_slice.profile_conditions.Ip # pylint: disable=invalid-name + Ti_bound_right = jax_utils.error_if_not_positive( # pylint: disable=invalid-name + dynamic_config_slice.profile_conditions.Ti_bound_right, 'Ti_bound_right' + ) + Te_bound_right = jax_utils.error_if_not_positive( # pylint: disable=invalid-name + dynamic_config_slice.profile_conditions.Te_bound_right, 'Te_bound_right' + ) + + # calculate ne_bound_right + # pylint: disable=invalid-name + nGW = ( + dynamic_config_slice.profile_conditions.Ip + / (jnp.pi * geo.Rmin**2) + * 1e20 + / dynamic_config_slice.nref + ) + # pylint: enable=invalid-name + ne_bound_right = jnp.where( + dynamic_config_slice.profile_conditions.ne_bound_right_is_fGW, + dynamic_config_slice.profile_conditions.ne_bound_right * nGW, + dynamic_config_slice.profile_conditions.ne_bound_right, + ) + # define ion profile based on (flat) Zeff and single assumed impurity + # with Zimp. main ion limited to hydrogenic species for now. + # Assume isotopic balance for DT fusion power. Solve for ni based on: + # Zeff = (ni + Zimp**2 * nimp)/ne ; nimp*Zimp + ni = ne + + dilution_factor = physics.get_main_ion_dilution_factor( + dynamic_config_slice.plasma_composition.Zimp, + dynamic_config_slice.plasma_composition.Zeff, + ) + return { + 'temp_ion': dict( + left_face_grad_constraint=jnp.zeros(()), + right_face_grad_constraint=None, + right_face_constraint=jnp.array(Ti_bound_right), + ), + 'temp_el': dict( + left_face_grad_constraint=jnp.zeros(()), + right_face_grad_constraint=None, + right_face_constraint=jnp.array(Te_bound_right), + ), + 'ne': dict( + left_face_grad_constraint=jnp.zeros(()), + right_face_grad_constraint=None, + right_face_constraint=jnp.array(ne_bound_right), + ), + 'ni': dict( + left_face_grad_constraint=jnp.zeros(()), + right_face_grad_constraint=None, + right_face_constraint=jnp.array(ne_bound_right * dilution_factor), + ), + 'psi': dict( + right_face_grad_constraint=Ip + * 1e6 + * constants.CONSTANTS.mu0 + / geo.G2_face[-1] + * geo.rmax, + right_face_constraint=None, + ), + } + + # pylint: disable=invalid-name def _get_jtot_hires( dynamic_config_slice: config_slice.DynamicConfigSlice, diff --git a/torax/update_state.py b/torax/update_state.py deleted file mode 100644 index c95763db..00000000 --- a/torax/update_state.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2024 DeepMind Technologies Limited -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Function to update the state.""" - -import dataclasses -from torax import config_slice -from torax import physics -from torax import state -from torax.fvm import cell_variable - - -def update_core_profiles( - core_profiles: state.CoreProfiles, - x_new: tuple[cell_variable.CellVariable, ...], - evolving_names: tuple[str, ...], - dynamic_config_slice: config_slice.DynamicConfigSlice, -) -> state.CoreProfiles: - """Returns the new core profiles after updating the evolving variables. - - Args: - core_profiles: The old set of core plasma profiles. - x_new: The new values of the evolving variables. - evolving_names: The names of the evolving variables. - dynamic_config_slice: The dynamic config slice. - """ - - def get_update(x_new, var): - """Returns the new value of `var`.""" - if var in evolving_names: - return x_new[evolving_names.index(var)] - # `var` is not evolving, so its new value is just its old value - return getattr(core_profiles, var) - - temp_ion = get_update(x_new, 'temp_ion') - temp_el = get_update(x_new, 'temp_el') - psi = get_update(x_new, 'psi') - ne = get_update(x_new, 'ne') - ni = dataclasses.replace( - core_profiles.ni, - value=ne.value - * physics.get_main_ion_dilution_factor( - dynamic_config_slice.plasma_composition.Zimp, - dynamic_config_slice.plasma_composition.Zeff, - ), - ) - - return dataclasses.replace( - core_profiles, - temp_ion=temp_ion, - temp_el=temp_el, - psi=psi, - ne=ne, - ni=ni, - )