From 1be3b2289e26aa793cdea1c8ecbb7482a7c505c2 Mon Sep 17 00:00:00 2001 From: Jonathan Demaeyer Date: Fri, 21 Mar 2025 11:57:13 +0100 Subject: [PATCH 01/15] Added new modules to doc and corrected symbolic tendencies docstrings --- .../source/files/technical/functions.rst | 6 +++ .../source/files/technical/tensors.rst | 4 ++ model_test/test_aotensor_sym_dynT.py | 3 ++ model_test/test_base_symbolic.py | 1 + qgs/functions/symbolic_tendencies.py | 45 +++++++++++-------- 5 files changed, 41 insertions(+), 18 deletions(-) diff --git a/documentation/source/files/technical/functions.rst b/documentation/source/files/technical/functions.rst index fed6003..065b867 100644 --- a/documentation/source/files/technical/functions.rst +++ b/documentation/source/files/technical/functions.rst @@ -10,5 +10,11 @@ The functions module contains utility functions used by the model, as well as so .. automodule:: qgs.functions.tendencies :members: +.. automodule:: qgs.functions.symbolic_mul + :members: + +.. automodule:: qgs.functions.symbolic_tendencies + :members: + .. automodule:: qgs.functions.util :members: diff --git a/documentation/source/files/technical/tensors.rst b/documentation/source/files/technical/tensors.rst index 3a20dee..486e49c 100644 --- a/documentation/source/files/technical/tensors.rst +++ b/documentation/source/files/technical/tensors.rst @@ -11,3 +11,7 @@ Module holding the model's tendencies tensor encoding each of their additive ter .. automodule:: qgs.tensors.atmo_thermo_tensor :show-inheritance: :members: + +.. automodule:: qgs.tensors.symbolic_qgtensor + :show-inheritance: + :members: diff --git a/model_test/test_aotensor_sym_dynT.py b/model_test/test_aotensor_sym_dynT.py index 852b2a6..2f7904c 100644 --- a/model_test/test_aotensor_sym_dynT.py +++ b/model_test/test_aotensor_sym_dynT.py @@ -22,6 +22,7 @@ real_eps = np.finfo(np.float64).eps + class TestSymbolicAOTensorDynT(TestBaseSymbolic): ''' Test class for the Dynamic T Symbolic Tensor @@ -85,6 +86,7 @@ def numerical_outputs(self, output_func=None): for coo, val in zip(num_aotensor.tensor.coords.T, num_aotensor.tensor.data): _ip_string_format(tfunc, 'num_aotensor', coo, val) + def _ip_string_format(func, symbol, indices, value): if abs(value) >= real_eps: s = symbol @@ -93,5 +95,6 @@ def _ip_string_format(func, symbol, indices, value): s += " = % .5E" % value func(s) + if __name__ == "__main__": unittest.main() diff --git a/model_test/test_base_symbolic.py b/model_test/test_base_symbolic.py index b540410..05b56c3 100644 --- a/model_test/test_base_symbolic.py +++ b/model_test/test_base_symbolic.py @@ -13,6 +13,7 @@ real_eps = np.finfo(np.float64).eps + class TestBaseSymbolic(unittest.TestCase): reference = list() diff --git a/qgs/functions/symbolic_tendencies.py b/qgs/functions/symbolic_tendencies.py index 4fd9160..7d2b071 100644 --- a/qgs/functions/symbolic_tendencies.py +++ b/qgs/functions/symbolic_tendencies.py @@ -7,8 +7,7 @@ """ -import numpy as np -from sympy import Symbol, lambdify +from sympy import Symbol import warnings from qgs.functions.symbolic_mul import symbolic_sparse_mult2, symbolic_sparse_mult3, symbolic_sparse_mult4, \ @@ -20,7 +19,7 @@ python_lang_translation = { 'sqrt': 'math.sqrt', 'pi': 'math.pi', - 'lambda': 'lmda' # Remove conflict for lambda function in python + 'lambda': 'lmda' # Remove conflict for lambda function in python } fortran_lang_translation = { @@ -49,13 +48,13 @@ def create_symbolic_equations(params, atm_ip=None, ocn_ip=None, gnd_ip=None, con ---------- params: QgParams The parameters fully specifying the model configuration. - atm_ip: SymbolicAtmosphericInnerProducts, optional + atm_ip: AtmosphericSymbolicInnerProducts, optional Allows for stored inner products to be input. - ocn_ip: SymbolicOceanInnerProducts, optional + ocn_ip: OceanSymbolicInnerProducts, optional Allows for stored inner products to be input. - gnd_ip: SymbolicGroundInnerProducts, optional + gnd_ip: GroundSymbolicInnerProducts, optional Allows for stored inner products to be input. - continuation_variables: Iterable(Parameter, ScalingParameter, ParametersArray) + continuation_variables: list(Parameter, ScalingParameter or ParametersArray) The variables to not substitute and to leave in the equations, if `None` all variables are substituted. language: str Options for the output language syntax: 'python', 'julia', 'fortran', 'auto', 'mathematica'. @@ -75,7 +74,7 @@ def create_symbolic_equations(params, atm_ip=None, ocn_ip=None, gnd_ip=None, con The substituted functions in the language syntax specified, as a string. dict_eq_simplified: dict(~sympy.core.expr.Expr) Dictionary of the substituted Jacobian matrix. - inner_products: tuple(SymbolicAtmosphericInnerProducts, SymbolicOceanicInnerProducts, SymbolicGroundInnerProducts) + inner_products: tuple(AtmosphericSymbolicInnerProducts, OceanicSymbolicInnerProducts, GroundSymbolicInnerProducts) If `return_inner_products` is `True`, the inner products of the system. eq_simplified: dict(~sympy.core.expr.Expr) If `return_symbolic_eqs` is `True`, dictionary of the model tendencies symbolic functions. @@ -198,15 +197,17 @@ def translate_equations(equations, language='python'): Parameters ---------- - equations: dict(string), list, string + equations: dict(str), list, str Dictionary, list, or string of the symbolic model equations. - language: string + language: str Language syntax that the equations are returned in. Options are: + - `python` - `fortran` - `julia` - `auto` - `mathematica` + Default to `python`. Returns @@ -243,7 +244,7 @@ def translate_equations(equations, language='python'): for k in translator.keys(): str_eq = str_eq.replace(k, translator[k]) else: - raise warnings.warn("Expected a dict, list, or string input") + raise ValueError("Expected a dict, list, or string input") return str_eq @@ -335,7 +336,7 @@ def equations_to_string(equations): Returns ------- - dict(~string) + dict(str) Dictionary of the substituted symbolic model equations. """ @@ -357,13 +358,15 @@ def equation_as_function(equations, params, language='python', continuation_vari The parameters fully specifying the model configuration. language: str Language syntax that the equations are returned in. Options are: + - `python` - `fortran` - `julia` - `auto` - `mathematica` + Default to `python`. - continuation_variables: Iterable(Parameter, ScalingParameter, ParametersArray) + continuation_variables: list(Parameter, ScalingParameter, ParametersArray) Variables that are not substituted with numerical values. If `None`, all symbols are substituted. Returns @@ -372,6 +375,7 @@ def equation_as_function(equations, params, language='python', continuation_vari Output is a function as a string in the specified language syntax. """ + # TODO: f_output seems to be always a list of string here. To check !! if continuation_variables is None: continuation_variables = list() @@ -446,6 +450,7 @@ def equation_as_function(equations, params, language='python', continuation_vari f_output = ['\n'.join(auto_file), '\n'.join(auto_config)] if language == 'mathematica': + raise NotImplemented("Mathematica code output is not yet available.") # TODO: This function needs testing before release f_output.append('F = Array[' + str(len(eq_dict)) + ']') @@ -472,13 +477,15 @@ def jacobian_as_function(equations, params, language='python', continuation_vari The parameters fully specifying the model configuration. language: str Language syntax that the equations are returned in. Options are: + - `python` - `fortran` - `julia` - `auto` - `mathematica` + Default to `python`. - continuation_variables: Iterable(Parameter, ScalingParameter, ParametersArray) + continuation_variables: list(Parameter, ScalingParameter, ParametersArray) Variables that are not substituted with numerical values. If `None`, all symbols are substituted. Returns @@ -487,6 +494,7 @@ def jacobian_as_function(equations, params, language='python', continuation_vari Output is a function as a string in the specified language syntax """ + # TODO: f_output seems to be always a list of string here. To check !! if continuation_variables is None: continuation_variables = list() @@ -562,6 +570,7 @@ def jacobian_as_function(equations, params, language='python', continuation_vari if language == 'mathematica': # TODO: This function needs testing before release + raise NotImplemented("Mathematica code output is not yet available.") f_output.append('jac = Array[' + str(len(eq_dict)) + ']') @@ -578,7 +587,7 @@ def jacobian_as_function(equations, params, language='python', continuation_vari def create_auto_file(equations, params, continuation_variables, auto_main_template=None, auto_c_template=None, initialize_params=False, initialize_solution=False): - """Creates the auto configuration file and the model file. + """Creates the AUTO configuration file and the model file. Saves files to specified folder. Parameters @@ -587,7 +596,7 @@ def create_auto_file(equations, params, continuation_variables, auto_main_templa Dictionary of the substituted symbolic model equations params: QgParams The parameters fully specifying the model configuration. - continuation_variables: Iterable(Parameter, ScalingParameter, ParametersArray) + continuation_variables: list(Parameter, ScalingParameter or ParametersArray) Variables that are not substituted with numerical values. If `None`, all symbols are substituted auto_main_template: str, optional The template to be used to generate the main AUTO file. @@ -602,10 +611,10 @@ def create_auto_file(equations, params, continuation_variables, auto_main_templa Returns ------- - auto_file: Str + auto_file: str The auto model file as a string - auto_config: Str + auto_config: str Auto configuration file as a string """ From 137611578fe63e015ac7353789f48c216ec09f6d Mon Sep 17 00:00:00 2001 From: Jonathan Demaeyer Date: Fri, 21 Mar 2025 12:04:30 +0100 Subject: [PATCH 02/15] Corrected symbolic mult docstrings --- qgs/functions/symbolic_mul.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qgs/functions/symbolic_mul.py b/qgs/functions/symbolic_mul.py index 3707ea4..f04d8ed 100644 --- a/qgs/functions/symbolic_mul.py +++ b/qgs/functions/symbolic_mul.py @@ -14,8 +14,8 @@ def add_to_dict(dic, loc, value): """Adds `value` to dictionary `dic`, with the dictionary key of `loc`. If the dictionary did not have a key of `loc` before, a new key is made. - # Jonathan: Add parameters descriptions """ + # TODO: add parameters description try: dic[loc] += value @@ -29,6 +29,8 @@ def symbolic_tensordot(a, b, axes=2): This is based on `Numpy`_ :meth:`~numpy.tensordot` . + .. _Numpy: https://numpy.org/ + Parameters ---------- a, b: ~sympy.tensor.array.DenseNDimArray or ~sympy.tensor.array.SparseNDimArray @@ -40,11 +42,9 @@ def symbolic_tensordot(a, b, axes=2): Returns ------- - output: sympy tensor + output: Sympy tensor The tensor dot product of the input. - .. _Numpy: https://numpy.org/ - """ as_ = a.shape nda = len(as_) From 5f8693e6cf1c2d6c336a6d8ccebbed4d10b38dd7 Mon Sep 17 00:00:00 2001 From: Jonathan Demaeyer Date: Fri, 21 Mar 2025 12:23:06 +0100 Subject: [PATCH 03/15] Update of the symbolic tensors docstrings --- qgs/tensors/symbolic_qgtensor.py | 39 ++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/qgs/tensors/symbolic_qgtensor.py b/qgs/tensors/symbolic_qgtensor.py index 64b0111..1ac70cb 100644 --- a/qgs/tensors/symbolic_qgtensor.py +++ b/qgs/tensors/symbolic_qgtensor.py @@ -54,9 +54,9 @@ class SymbolicQgsTensor(object): ground_inner_products: None or GroundInnerProducts The inner products of the ground basis functions on which the model's PDE ground equations are projected. If `None`, disable the ground tendencies. Default to `None`. - tensor: sparse.COO(float) + tensor: ~sympy.tensor.array.ImmutableSparseNDimArray The tensor :math:`\\mathcal{T}_{i,j,k}` :math:`i`-th components. - jacobian_tensor: sparse.COO(float) + jacobian_tensor: ~sympy.tensor.array.ImmutableSparseNDimArray The jacobian tensor :math:`\\mathcal{T}_{i,j,k} + \\mathcal{T}_{i,k,j}` :math:`i`-th components. """ @@ -800,16 +800,20 @@ def sub_tensor(self, tensor=None, continuation_variables=None): Parameters ---------- - tensor: dict or ~sympy.tensor.array.ImmutableSparseNDimArray + tensor: dict(~sympy.core.expr.Expr or float) or ~sympy.tensor.array.ImmutableSparseNDimArray + Tensor of model tendencies, either as - continuation_variables: Iterable(Parameter, ScalingParameter, ParametersArray) + - a dictionary with keys of non-zero coordinates, and values of Sympy expressions or floats + - or a sparse Sympy tensor + + continuation_variables: list(Parameter, ScalingParameter or ParametersArray) Variables which remain symbolic, all other variables are substituted with numerical values. If `None` all variables are substituted. Returns ------- - ten_out: dict - Dictionary of the substituted tensor of the model tendencies, with coordinates and value + ten_out: dict(float) + Dictionary of the substituted tensor of the model tendencies, with coordinates and numerical values """ if continuation_variables is None: @@ -842,14 +846,19 @@ def print_tensor(self, tensor=None, dict_opp=True, tol=1e-10): Parameters ---------- - tensor: dict or ~sympy.tensor.array.ImmutableSparseNDimArray - Tensor of model tendencies, either as a dictionary with keys of non-zero coordinates, and values of ~sympy.core.symbol.Symbol or floats, or as a - ~sympy.tensor.array.ImmutableSparseNDimArray . + tensor: dict(~sympy.core.expr.Expr or float) or ~sympy.tensor.array.ImmutableSparseNDimArray + Tensor of model tendencies, either as + + - a dictionary with keys of non-zero coordinates, and values of Sympy expressions or floats + - or a sparse Sympy tensor + dict_opp: bool ... tol: float ... """ + # TODO: Docstring need to be completed here + if tensor is None: if dict_opp: temp_ten = self.tensor_dic @@ -910,9 +919,9 @@ class SymbolicQgsTensorDynamicT(SymbolicQgsTensor): ground_inner_products: None or GroundInnerProducts The inner products of the ground basis functions on which the model's PDE ground equations are projected. If `None`, disable the ground tendencies. Default to `None`. - tensor: sparse.COO(float) + tensor: ~sympy.tensor.array.ImmutableSparseNDimArray The tensor :math:`\\mathcal{T}_{i,j,k}` :math:`i`-th components. - jacobian_tensor: sparse.COO(float) + jacobian_tensor: ~sympy.tensor.array.ImmutableSparseNDimArray The jacobian tensor :math:`\\mathcal{T}_{i,j,k} + \\mathcal{T}_{i,k,j}` :math:`i`-th components. """ @@ -1270,9 +1279,9 @@ class SymbolicQgsTensorT4(SymbolicQgsTensor): ground_inner_products: None or GroundInnerProducts The inner products of the ground basis functions on which the model's PDE ground equations are projected. If `None`, disable the ground tendencies. Default to `None`. - tensor: sparse.COO(float) + tensor: ~sympy.tensor.array.ImmutableSparseNDimArray The tensor :math:`\\mathcal{T}_{i,j,k}` :math:`i`-th components. - jacobian_tensor: sparse.COO(float) + jacobian_tensor: ~sympy.tensor.array.ImmutableSparseNDimArray The jacobian tensor :math:`\\mathcal{T}_{i,j,k} + \\mathcal{T}_{i,k,j}` :math:`i`-th components. """ @@ -1451,9 +1460,9 @@ def _shift_dict_keys(dic, shift): Parameters ---------- - dic: dictionary + dic: dict - shift: Tuple + shift: tuple """ shifted_dic = dict() From e4999a79eba601fda9540edaae9f66382eedfae4 Mon Sep 17 00:00:00 2001 From: Jonathan Demaeyer Date: Fri, 21 Mar 2025 12:28:10 +0100 Subject: [PATCH 04/15] Corrected parameter class docstrings --- qgs/params/parameter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qgs/params/parameter.py b/qgs/params/parameter.py index 1917307..7823b83 100644 --- a/qgs/params/parameter.py +++ b/qgs/params/parameter.py @@ -998,7 +998,7 @@ class ParametersArray(np.ndarray): description: str or list(str) or array(str), optional String or an iterable of strings, describing the parameters. If an iterable, should have the same length or shape as `values`. - symbols ~sympy.core.symbol.Symbol or list(~sympy.core.symbol.Symbol) or ~numpy.ndarray(~sympy.core.symbol.Symbol), optional + symbols: ~sympy.core.symbol.Symbol or list(~sympy.core.symbol.Symbol) or ~numpy.ndarray(~sympy.core.symbol.Symbol), optional A `Sympy`_ symbol or an iterable of symbols, to represent the parameters in symbolic expressions. If an iterable, should have the same length or shape as `values`. symbolic_expressions: ~sympy.core.expr.Expr or list(~sympy.core.expr.Expr) or ~numpy.ndarray(~sympy.core.expr.Expr), optional From 52c7e9b8631e293dbd0379ee0c1cc67d79fba70b Mon Sep 17 00:00:00 2001 From: Jonathan Demaeyer Date: Mon, 24 Mar 2025 16:09:52 +0100 Subject: [PATCH 05/15] Update of the doc itself Changed the name of the function creating the tendencies --- README.md | 4 +-- .../source/files/general_information.rst | 4 +-- .../source/files/technical_description.rst | 13 ++++--- documentation/source/files/user_guide.rst | 34 ++++++++++++------- ...symbolic_output_land_atmosphere-AUTO.ipynb | 6 ++-- .../symbolic_output_land_atmosphere.ipynb | 6 ++-- qgs/functions/symbolic_tendencies.py | 10 +++--- 7 files changed, 45 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 60b9746..f7907cd 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ Note that the Jupyter notebooks are not concerned by this recommendation and wor #### Activating DifferentialEquations.jl optional support In addition to the qgs builtin Runge-Kutta integrator, the qgs model can alternatively be integrated with a package called [DifferentialEquations.jl](https://github.com/SciML/DifferentialEquations.jl) written in [Julia](https://julialang.org/), and available through the -[diffeqpy](https://github.com/SciML/diffeqpy) python package. +[diffeqpy](https://github.com/SciML/diffeqpy) Python package. The diffeqpy package first installation step is done by Anaconda in the qgs environment but then you must [install Julia](https://julialang.org/downloads/) and follow the final manual installation instruction found in the [diffeqpy README](https://github.com/SciML/diffeqpy). These can be summed up as opening a terminal and doing: @@ -208,7 +208,7 @@ Non-exhaustive list: * [Q-GCM](http://q-gcm.org/): A mid-latitude grid based ocean-atmosphere model like MAOOAM. Code in Fortran, interface is in Python. -* [pyqg](https://github.com/pyqg/pyqg): A pseudo-spectral python solver for quasi-geostrophic systems. +* [pyqg](https://github.com/pyqg/pyqg): A pseudo-spectral Python solver for quasi-geostrophic systems. * [Isca](https://execlim.github.io/IscaWebsite/index.html): Research GCM written in Fortran and largely configured with Python scripts, with internal coding changes required for non-standard cases. diff --git a/documentation/source/files/general_information.rst b/documentation/source/files/general_information.rst index 2626422..be6a53d 100644 --- a/documentation/source/files/general_information.rst +++ b/documentation/source/files/general_information.rst @@ -161,7 +161,7 @@ A review of your pull request will follow with possibly suggestions of changes b Please consider the following guidelines before submitting: * Before submitting a pull request, double check that the branch to be merged contains only changes you wish to add to the master branch. This will save time in reviewing the code. -* For any changes to the core model files, please check your submission by running the tests found in the folder `model_test <../../../../model_test>`_ to ensure that the model tensors are still valid (see the section :ref:`files/user_guide:5. Developers information` of the :ref:`files/user_guide:User guide`). Please do not make changes to existing test cases. +* For any changes to the core model files, please check your submission by running the tests found in the folder `model_test <../../../../model_test>`_ to ensure that the model tensors are still valid (see the section :ref:`files/user_guide:6. Developers information` of the :ref:`files/user_guide:User guide`). Please do not make changes to existing test cases. * For substantial additions of code, including a test case (using `unittest`_) in the folder `model_test <../../../../model_test>`_ is recommended. * Please document the new functionalities in the documentation. Code addition without documentation addition will not be accepted. The documentation is done with `sphinx`_ and follows the Numpy conventions. Please take a look to the actual code to get an idea about how to document the code. * If your addition can be considered as a tool not directly related to the core of the model, please develop it in the toolbox folder. @@ -182,7 +182,7 @@ Non-exhaustive list: * `Q-GCM `_: A mid-latitude grid based ocean-atmosphere model like MAOOAM. Code in Fortran, interface is in Python. -* `pyqg `_: A pseudo-spectral python solver for quasi-geostrophic systems. +* `pyqg `_: A pseudo-spectral Python solver for quasi-geostrophic systems. * `Isca `_: Research GCM written in Fortran and largely configured with Python scripts, with internal coding changes required for non-standard cases. diff --git a/documentation/source/files/technical_description.rst b/documentation/source/files/technical_description.rst index 7270c02..d403ea6 100644 --- a/documentation/source/files/technical_description.rst +++ b/documentation/source/files/technical_description.rst @@ -101,11 +101,11 @@ Using `Sympy`_ qgs offers the functionality to return the ordinary differential * Python * Julia -* Fortran-90 -* Mathematica -* AUTO-p07 continuation software +* Fortran 90 +* `AUTO-p07 `_ continuation software +* `Mathematica `_ (still being tested) -This also allows the user to specify their own integration method for solving the model equations in python. +This also allows the user to specify their own integration method for solving the model equations in Python. Additional technical information @@ -117,7 +117,9 @@ Additional technical information * qgs has a `tangent linear model`_ optimized to run ensembles of initial conditions as well, with a broadcast integration of the tangent model thanks to `Numpy`_. -* The symbolic output functionality of the qgs model relies on `Sympy`_ to perform the tensor calculations. This library is significantly slower than the numerical equivilent and as a result it is currently only feasible to generate the symbolic model equations for model resolutions up to :math:`4x4`. +* The symbolic output functionality of the qgs model relies on `Sympy`_ to perform the tensor calculations. + This library is significantly slower than the numerical equivalent and as a result it is currently only feasible to + generate the symbolic model equations for model resolutions up to :math:`4x4`. References ---------- @@ -131,3 +133,4 @@ References .. _multiprocessing: https://docs.python.org/3.7/library/multiprocessing.html#module-multiprocessing .. _tangent linear model: http://glossary.ametsoc.org/wiki/Tangent_linear_model .. _ordinary differential equations: https://en.wikipedia.org/wiki/Ordinary_differential_equation +.. _Sympy: https://www.sympy.org/ diff --git a/documentation/source/files/user_guide.rst b/documentation/source/files/user_guide.rst index f73e18a..64c3e7d 100644 --- a/documentation/source/files/user_guide.rst +++ b/documentation/source/files/user_guide.rst @@ -18,7 +18,7 @@ This guide provides: 1. The different ways to configure qgs in order to obtain the function :math:`\boldsymbol{f}` are explained in the section :ref:`files/user_guide:2. Configuration of qgs`. 2. Some specific ways to configure qgs detailed in the section :ref:`files/user_guide:3. Using user-defined symbolic basis`. -3. Examples of usages of the model's tendencies function :math:`\boldsymbol{f}` are given in the section :ref:`files/user_guide:4. Using qgs (once configured)`. +3. Examples of usages of the model's tendencies function :math:`\boldsymbol{f}` are given in the section :ref:`files/user_guide:5. Using qgs (once configured)`. 2. Configuration of qgs ----------------------- @@ -227,7 +227,7 @@ Jacobian matrix :math:`\boldsymbol{\mathrm{Df}}`. Just pass it to the function : f, Df = create_tendencies(model_parameters) The function :meth:`f` hence produced can be used to generate the model's trajectories. -See the section :ref:`files/user_guide:4. Using qgs (once configured)` for the possible usages. +See the section :ref:`files/user_guide:5. Using qgs (once configured)` for the possible usages. 2.5 Saving your model ^^^^^^^^^^^^^^^^^^^^^^^ @@ -466,29 +466,37 @@ See also the following section for the possible usages. 4. Symbolic outputs ------------------- -If the user wants to generate the model tendencies with non-fixed parameters, use the tendencies in another programming language, or use their own integrator in python, the qgs framework can use `Sympy`_ to proform the above calculations symbolically rather than numerically. +If the user wants to generate the model tendencies with non-fixed parameters, or use the tendencies in another programming language, +the qgs framework can use `Sympy`_ to perform the above calculations symbolically rather than numerically. -To return the tendencies including specified parameter values, or to format the tendencies in another programming language, the qgs model is configured as shown in section :ref:`files/user_guide:Configuration of qgs`, however the **Symbolic** inner product is always used in this pipeline. To create the symbolic tendencies, the instance of :class:`.QgParams` is passed to the function :func:`.create_symbolic_tendencies`: +To return the tendencies including specified parameter values, or to format the tendencies in another programming language, +the qgs model is configured as shown in section :ref:`files/user_guide:2. Configuration of qgs`, however the **Symbolic** inner +product is always used in this pipeline. +To create the symbolic tendencies, the instance of :class:`.QgParams` is passed to the function :func:`.create_symbolic_tendencies`: .. code:: ipython3 - from qgs.functions.symbolic_tendencies import create_symbolic_equations + from qgs.functions.symbolic_tendencies import create_symbolic_tendencies parameters = [model_parameters.par1, model_parameters.par2, model_parameters.par3] - f = create_symbolic_equations(model_parameters, continuation_variables=parameters, language='python') + f = create_symbolic_tendencies(model_parameters, continuation_variables=parameters, language='python') -The varibale :meth:`f` is a string of the model tendencies, formatted in the programming language specified by the keyword :meth:`language`. The model tendencies will contain the specified :meth:`continuation_variables` as free parameters. +The variable :code:`f` is a string of the model tendencies, formatted in the programming language specified by the +keyword :code:`language`. The model tendencies will contain the specified :code:`continuation_variables` as free parameters. Currently the framework can format the equations in the following programming languages: -* :meth:`python` -* :meth:`julia` -* :meth:`fortran` -* :meth:`mathematica` -* :meth:`auto` +* :code:`python` +* :code:`julia` +* :code:`fortran` +* :code:`auto` +* :code:`mathematica` (still under test) -1. Using qgs (once configured) +Some example on how to use this functionality are provided in the +`notebooks/symbolic_outputs <../../../../notebooks/symbolic_outputs>`_ folder. + +5. Using qgs (once configured) --------------------------------- Once the function :math:`\boldsymbol{f}` giving the model's tendencies has been obtained, it is possible to use it with diff --git a/notebooks/symbolic_outputs/symbolic_output_land_atmosphere-AUTO.ipynb b/notebooks/symbolic_outputs/symbolic_output_land_atmosphere-AUTO.ipynb index 06495d6..a7866e6 100644 --- a/notebooks/symbolic_outputs/symbolic_output_land_atmosphere-AUTO.ipynb +++ b/notebooks/symbolic_outputs/symbolic_output_land_atmosphere-AUTO.ipynb @@ -65,7 +65,7 @@ "outputs": [], "source": [ "import sys, os\n", - "sys.path.extend([os.path.abspath('../')])" + "sys.path.extend([os.path.abspath('../../')])" ] }, { @@ -114,7 +114,7 @@ "metadata": {}, "outputs": [], "source": [ - "from qgs.functions.symbolic_tendencies import create_symbolic_equations" + "from qgs.functions.symbolic_tendencies import create_symbolic_tendencies" ] }, { @@ -238,7 +238,7 @@ "metadata": {}, "outputs": [], "source": [ - "funcs, = create_symbolic_equations(model_parameters, continuation_variables=[model_parameters.gotemperature_params.C[0], model_parameters.atemperature_params.C[0], model_parameters.atmospheric_params.kd, model_parameters.atmospheric_params.kdp], language='auto')" + "funcs, = create_symbolic_tendencies(model_parameters, continuation_variables=[model_parameters.gotemperature_params.C[0], model_parameters.atemperature_params.C[0], model_parameters.atmospheric_params.kd, model_parameters.atmospheric_params.kdp], language='auto')" ] }, { diff --git a/notebooks/symbolic_outputs/symbolic_output_land_atmosphere.ipynb b/notebooks/symbolic_outputs/symbolic_output_land_atmosphere.ipynb index 822fe14..7b2a050 100644 --- a/notebooks/symbolic_outputs/symbolic_output_land_atmosphere.ipynb +++ b/notebooks/symbolic_outputs/symbolic_output_land_atmosphere.ipynb @@ -54,7 +54,7 @@ "outputs": [], "source": [ "import sys, os\n", - "sys.path.extend([os.path.abspath('../')])" + "sys.path.extend([os.path.abspath('../../')])" ] }, { @@ -113,7 +113,7 @@ "metadata": {}, "outputs": [], "source": [ - "from qgs.functions.symbolic_tendencies import create_symbolic_equations\n", + "from qgs.functions.symbolic_tendencies import create_symbolic_tendencies\n", "from qgs.functions.tendencies import create_tendencies" ] }, @@ -260,7 +260,7 @@ "outputs": [], "source": [ "%%time\n", - "funcs, = create_symbolic_equations(model_parameters, continuation_variables=[model_parameters.gotemperature_params.C[0], model_parameters.atemperature_params.C[0], model_parameters.atmospheric_params.kd, model_parameters.atmospheric_params.kdp], language='python')" + "funcs, = create_symbolic_tendencies(model_parameters, continuation_variables=[model_parameters.gotemperature_params.C[0], model_parameters.atemperature_params.C[0], model_parameters.atmospheric_params.kd, model_parameters.atmospheric_params.kdp], language='python')" ] }, { diff --git a/qgs/functions/symbolic_tendencies.py b/qgs/functions/symbolic_tendencies.py index 7d2b071..59f643e 100644 --- a/qgs/functions/symbolic_tendencies.py +++ b/qgs/functions/symbolic_tendencies.py @@ -39,10 +39,10 @@ } -def create_symbolic_equations(params, atm_ip=None, ocn_ip=None, gnd_ip=None, continuation_variables=None, - language='python', return_inner_products=False, return_jacobian=False, - return_symbolic_eqs=False, return_symbolic_qgtensor=False): - """Function to output the raw symbolic functions of the qgs model. +def create_symbolic_tendencies(params, atm_ip=None, ocn_ip=None, gnd_ip=None, continuation_variables=None, + language='python', return_inner_products=False, return_jacobian=False, + return_symbolic_eqs=False, return_symbolic_qgtensor=False): + """Function to output the raw symbolic tendencies of the qgs model. Parameters ---------- @@ -263,11 +263,13 @@ def format_equations(equations, params, save_loc=None, language='python', print_ Location to save the outputs as a .txt file. language: str Language syntax that the equations are returned in. Options are: + - `python` - `fortran` - `julia` - `auto` - `mathematica` + Default to `python`. print_equations: bool If `True`, equations are printed by the function, if `False`, equation strings are returned by the function. From d5228886e9778e3d95256ac7c1b4f0a7187325bf Mon Sep 17 00:00:00 2001 From: Jonathan Demaeyer Date: Wed, 26 Mar 2025 14:50:19 +0100 Subject: [PATCH 06/15] First batch of mods --- qgs/functions/symbolic_mul.py | 15 +-------------- qgs/functions/symbolic_tendencies.py | 19 ++++++++----------- qgs/functions/util.py | 20 ++++++++++++++++++++ qgs/params/parameter.py | 1 - qgs/tensors/symbolic_qgtensor.py | 6 ++---- 5 files changed, 31 insertions(+), 30 deletions(-) diff --git a/qgs/functions/symbolic_mul.py b/qgs/functions/symbolic_mul.py index f04d8ed..3f32d92 100644 --- a/qgs/functions/symbolic_mul.py +++ b/qgs/functions/symbolic_mul.py @@ -8,20 +8,7 @@ """ from sympy import tensorproduct, tensorcontraction - - -def add_to_dict(dic, loc, value): - """Adds `value` to dictionary `dic`, with the dictionary key of `loc`. - If the dictionary did not have a key of `loc` before, a new key is made. - - """ - # TODO: add parameters description - - try: - dic[loc] += value - except: - dic[loc] = value - return dic +from qgs.functions.util import add_to_dict def symbolic_tensordot(a, b, axes=2): diff --git a/qgs/functions/symbolic_tendencies.py b/qgs/functions/symbolic_tendencies.py index 59f643e..03d5b40 100644 --- a/qgs/functions/symbolic_tendencies.py +++ b/qgs/functions/symbolic_tendencies.py @@ -55,7 +55,9 @@ def create_symbolic_tendencies(params, atm_ip=None, ocn_ip=None, gnd_ip=None, co gnd_ip: GroundSymbolicInnerProducts, optional Allows for stored inner products to be input. continuation_variables: list(Parameter, ScalingParameter or ParametersArray) - The variables to not substitute and to leave in the equations, if `None` all variables are substituted. + The variables to not substitute and to leave in the equations, if `None`, no variables are substituted. + If an empty list is provided, then all variables are substituted, providing fully numerical tendencies. + Default to `None'. language: str Options for the output language syntax: 'python', 'julia', 'fortran', 'auto', 'mathematica'. Default to 'python'. @@ -85,7 +87,7 @@ def create_symbolic_tendencies(params, atm_ip=None, ocn_ip=None, gnd_ip=None, co make_ip_subs = True if continuation_variables is None: - make_ip_subs = False # TODO: check this !!! For me it should be True because if no cv then all subs are done. + make_ip_subs = False else: for cv in continuation_variables: try: @@ -373,11 +375,11 @@ def equation_as_function(equations, params, language='python', continuation_vari Returns ------- - f_output: callable or str + f_output: str Output is a function as a string in the specified language syntax. """ - # TODO: f_output seems to be always a list of string here. To check !! + if continuation_variables is None: continuation_variables = list() @@ -492,11 +494,11 @@ def jacobian_as_function(equations, params, language='python', continuation_vari Returns ------- - f_output: callable or str + f_output: str Output is a function as a string in the specified language syntax """ - # TODO: f_output seems to be always a list of string here. To check !! + if continuation_variables is None: continuation_variables = list() @@ -622,11 +624,6 @@ def create_auto_file(equations, params, continuation_variables, auto_main_templa # TODO: There is some weird double tab spacings in the output, and I am not sure why - # User passes the equations, with the variables to leave as variables. - # The existing model parameters are used to populate the auto file - # The variables given as `continuation_variables` remain in the equations. - # There is a limit of 1-10 remaining variables - if (len(continuation_variables) < 1) or (len(continuation_variables) > 10): raise ValueError("Too many variables for auto file") diff --git a/qgs/functions/util.py b/qgs/functions/util.py index d6ae059..c78bdae 100644 --- a/qgs/functions/util.py +++ b/qgs/functions/util.py @@ -11,6 +11,26 @@ from numba import njit +def add_to_dict(dic, loc, value): + """Adds `value` to dictionary `dic`, with the dictionary key of `loc`. + If the dictionary did not have a key of `loc` before, a new key is made. + + Parameters + ---------- + dic: dict + Dictionary to add the value to. + loc: + Item of the dictionary to add the value to. + value: + Value to add. + """ + try: + dic[loc] += value + except: + dic[loc] = value + return dic + + @njit def reverse(a): """Numba-jitted function to reverse a 1D array. diff --git a/qgs/params/parameter.py b/qgs/params/parameter.py index 7823b83..c741031 100644 --- a/qgs/params/parameter.py +++ b/qgs/params/parameter.py @@ -64,7 +64,6 @@ # TODO: Automatize warnings and errors -# TODO: Implement operations for arrays class ScalingParameter(float): """Class of model's dimension parameter. diff --git a/qgs/tensors/symbolic_qgtensor.py b/qgs/tensors/symbolic_qgtensor.py index 1ac70cb..196c312 100644 --- a/qgs/tensors/symbolic_qgtensor.py +++ b/qgs/tensors/symbolic_qgtensor.py @@ -6,7 +6,8 @@ equations. """ -from qgs.functions.symbolic_mul import add_to_dict, symbolic_tensordot +from qgs.functions.symbolic_mul import symbolic_tensordot +from qgs.functions.util import add_to_dict from qgs.params.params import Parameter, ScalingParameter, ParametersArray, Params import numpy as np @@ -1247,9 +1248,6 @@ def compute_tensor(self): class SymbolicQgsTensorT4(SymbolicQgsTensor): - # TODO: this takes a long time (>1hr) to run. I think we need a better way to run the non-stored z, v, Z, V IPs. Maybe do not allow `n` as a continuation parameter for this version? - # TODO: Create a warning about long run-times. - """qgs dynamical temperature first order (linear) symbolic tendencies tensor class. Parameters From 8c7a14e2884356391a140348a6ed1992351f08f3 Mon Sep 17 00:00:00 2001 From: ushham Date: Wed, 26 Mar 2025 15:27:34 +0100 Subject: [PATCH 07/15] documentation in sym_qgtensor completed --- qgs/tensors/symbolic_qgtensor.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/qgs/tensors/symbolic_qgtensor.py b/qgs/tensors/symbolic_qgtensor.py index 196c312..3fa3534 100644 --- a/qgs/tensors/symbolic_qgtensor.py +++ b/qgs/tensors/symbolic_qgtensor.py @@ -847,18 +847,20 @@ def print_tensor(self, tensor=None, dict_opp=True, tol=1e-10): Parameters ---------- - tensor: dict(~sympy.core.expr.Expr or float) or ~sympy.tensor.array.ImmutableSparseNDimArray + tensor: dict(~sympy.core.expr.Expr or float) or ~sympy.tensor.array.ImmutableSparseNDimArray or `None` Tensor of model tendencies, either as - a dictionary with keys of non-zero coordinates, and values of Sympy expressions or floats - or a sparse Sympy tensor + If `None`, defaults to the stored tensor. + Defaults to `None`. + dict_opp: bool - ... + If `True`, returns the unsimplified symbolic expressions, if `False` the simplified expressions are returned. tol: float - ... + The tolerance to allow for numerical errors when finding non-zero values. """ - # TODO: Docstring need to be completed here if tensor is None: if dict_opp: @@ -1230,7 +1232,6 @@ def _compute_non_stored_full_dict(self): def compute_tensor(self): """Routine to compute the tensor.""" - # gathering if self.params.T4: # TODO: Make a proper error message for here raise ValueError("Parameters are set for T4 version, set dynamic_T=True") @@ -1427,7 +1428,6 @@ def _compute_non_stored_full_dict(self): def compute_tensor(self): """Routine to compute the tensor.""" - # gathering if not self.params.T4: raise ValueError("Parameters are not set for T4 version") @@ -1444,10 +1444,8 @@ def compute_tensor(self): def _kronecker_delta(i, j): - if i == j: return 1 - else: return 0 @@ -1459,8 +1457,10 @@ def _shift_dict_keys(dic, shift): Parameters ---------- dic: dict + Dictionary representing a tensor. shift: tuple + A tuple that represents the shift in the tensor indices. """ shifted_dic = dict() @@ -1472,13 +1472,16 @@ def _shift_dict_keys(dic, shift): def _parameter_substitutions(params, continuation_variables): - + """ + Returns the set of parameters values that are the be substitutes, + removing the parameters given in `continuation_variables`. + """ subs = _parameter_values(params) for _, obj in params.__dict__.items(): if issubclass(obj.__class__, Params): subs.update(_parameter_values(obj)) - # Manually add properties from class + # Manually add properties from scaling class subs[params.scale_params.L.symbol] = params.scale_params.L subs[params.scale_params.beta.symbol] = params.scale_params.beta From 814a3d75d3e73c5d1f68bdbcd23909d619a62d7e Mon Sep 17 00:00:00 2001 From: ushham Date: Thu, 27 Mar 2025 14:01:45 +0100 Subject: [PATCH 08/15] Substitutions are based on params class values instead of passing a dict --- .../symbolic_output_land_atmosphere.ipynb | 19 ++++--- qgs/functions/symbolic_tendencies.py | 8 +-- qgs/params/params.py | 42 +++++++++++++++ qgs/tensors/symbolic_qgtensor.py | 52 ++++++------------- 4 files changed, 76 insertions(+), 45 deletions(-) diff --git a/notebooks/symbolic_outputs/symbolic_output_land_atmosphere.ipynb b/notebooks/symbolic_outputs/symbolic_output_land_atmosphere.ipynb index 7b2a050..5cf7ed6 100644 --- a/notebooks/symbolic_outputs/symbolic_output_land_atmosphere.ipynb +++ b/notebooks/symbolic_outputs/symbolic_output_land_atmosphere.ipynb @@ -141,7 +141,7 @@ "outputs": [], "source": [ "# Time parameters\n", - "dt = 0.1\n" + "dt = 0.1" ] }, { @@ -260,7 +260,15 @@ "outputs": [], "source": [ "%%time\n", - "funcs, = create_symbolic_tendencies(model_parameters, continuation_variables=[model_parameters.gotemperature_params.C[0], model_parameters.atemperature_params.C[0], model_parameters.atmospheric_params.kd, model_parameters.atmospheric_params.kdp], language='python')" + "funcs, = create_symbolic_tendencies(\n", + " model_parameters, \n", + " continuation_variables=[\n", + " model_parameters.gotemperature_params.C[0],\n", + " model_parameters.atemperature_params.C[0],\n", + " model_parameters.atmospheric_params.kd,\n", + " model_parameters.atmospheric_params.kdp\n", + " ], \n", + " language='python')" ] }, { @@ -476,10 +484,7 @@ " plt.ylabel('$'+model_parameters.latex_var_string[vary]+'$');\n", "\n", " plt.legend()\n", - " k+=1\n", - "\n", - "\n", - "\n" + " k+=1" ] } ], @@ -499,7 +504,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.16" + "version": "3.8.10" } }, "nbformat": 4, diff --git a/qgs/functions/symbolic_tendencies.py b/qgs/functions/symbolic_tendencies.py index 03d5b40..631f9f5 100644 --- a/qgs/functions/symbolic_tendencies.py +++ b/qgs/functions/symbolic_tendencies.py @@ -88,6 +88,10 @@ def create_symbolic_tendencies(params, atm_ip=None, ocn_ip=None, gnd_ip=None, co if continuation_variables is None: make_ip_subs = False + + # Generates list of all available parameters + continuation_variables = params._all_items + else: for cv in continuation_variables: try: @@ -601,7 +605,7 @@ def create_auto_file(equations, params, continuation_variables, auto_main_templa params: QgParams The parameters fully specifying the model configuration. continuation_variables: list(Parameter, ScalingParameter or ParametersArray) - Variables that are not substituted with numerical values. If `None`, all symbols are substituted + Variables that are not substituted with numerical values. If `None`, no symbols are substituted auto_main_template: str, optional The template to be used to generate the main AUTO file. If not provided, use the default template. @@ -622,8 +626,6 @@ def create_auto_file(equations, params, continuation_variables, auto_main_templa Auto configuration file as a string """ - # TODO: There is some weird double tab spacings in the output, and I am not sure why - if (len(continuation_variables) < 1) or (len(continuation_variables) > 10): raise ValueError("Too many variables for auto file") diff --git a/qgs/params/params.py b/qgs/params/params.py index 5d34b41..1ffbe58 100644 --- a/qgs/params/params.py +++ b/qgs/params/params.py @@ -1329,6 +1329,48 @@ def dimensional_time(self): c = 24 * 3600 * 365 return 1 / (self.scale_params.f0 * c) + def _parameter_values(self, obj=None): + """Function produces a dictionary of the symbol and the corresponding numerical value""" + + subs = list() + iter_vals = obj.__dict__.values() if obj is not None else self.__dict__.values() + for val in iter_vals: + if isinstance(val, Parameter): + subs.append(val) + + if isinstance(val, ScalingParameter): + subs.append(val) + + if isinstance(val, ParametersArray): + for v in val: + if v.symbol != 0: + subs.append(v) + return subs + + @property + def _all_items(self): + """ + Function to return a dict of all symbols that represent parameters, + along with their current numerical values. + + Returns + ------- + dict + """ + + subs = self._parameter_values() + + for _, obj in self.__dict__.items(): + if issubclass(obj.__class__, Params): + for v in self._parameter_values(obj): + subs.append(v) + + # Manually add properties from scaling class + subs.append(self.scale_params.L) + subs.append(self.scale_params.beta) + + return subs + # ------------------------------------------------------------------- # Config setters to be used with symbolic inner products # ------------------------------------------------------------------- diff --git a/qgs/tensors/symbolic_qgtensor.py b/qgs/tensors/symbolic_qgtensor.py index 3fa3534..856fbec 100644 --- a/qgs/tensors/symbolic_qgtensor.py +++ b/qgs/tensors/symbolic_qgtensor.py @@ -1473,49 +1473,31 @@ def _shift_dict_keys(dic, shift): def _parameter_substitutions(params, continuation_variables): """ - Returns the set of parameters values that are the be substitutes, + Returns the set of parameters values that are the be substituted, removing the parameters given in `continuation_variables`. """ - subs = _parameter_values(params) - for _, obj in params.__dict__.items(): - if issubclass(obj.__class__, Params): - subs.update(_parameter_values(obj)) - # Manually add properties from scaling class - subs[params.scale_params.L.symbol] = params.scale_params.L - subs[params.scale_params.beta.symbol] = params.scale_params.beta + subs = params._all_items + + if continuation_variables is None: + continuation_variables = list() # Remove variables in continuation variables for cv in continuation_variables: if isinstance(cv, ParametersArray): - for cv_i in cv.symbols: - subs.pop(cv_i) - elif hasattr(cv, "symbol"): - subs.pop(cv.symbol) + for cv_i in cv: + subs.remove(cv_i) + elif isinstance(cv, Parameter): + subs.remove(cv) else: # Try ... who knows... - subs.pop(cv) - - return subs - - -def _parameter_values(pars): - """Function takes a parameter class and produces a dictionary of the symbol and the corresponding numerical value""" - - subs = dict() - for val in pars.__dict__.values(): - if isinstance(val, Parameter): - if val.symbol is not None: - subs[val.symbol] = val - - if isinstance(val, ScalingParameter): - if val.symbol is not None: - subs[val.symbol] = val - - if isinstance(val, ParametersArray): - for v in val: - if v.symbol is not None or v.symbol != 0: - subs[v.symbol] = v - return subs + subs.remove(cv) + + # make the remaining items into a dict + sub_dic = {} + for p in subs: + if p.symbol is not None: + sub_dic[p.symbol] = float(p) + return sub_dic if __name__ == "__main__": From a3f649e4779d6c8ab39638438457f0460172a68f Mon Sep 17 00:00:00 2001 From: ushham Date: Thu, 27 Mar 2025 14:06:56 +0100 Subject: [PATCH 09/15] Fixing some doc strings --- qgs/params/params.py | 6 +++--- qgs/tensors/symbolic_qgtensor.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/qgs/params/params.py b/qgs/params/params.py index 1ffbe58..13c6fae 100644 --- a/qgs/params/params.py +++ b/qgs/params/params.py @@ -1330,7 +1330,7 @@ def dimensional_time(self): return 1 / (self.scale_params.f0 * c) def _parameter_values(self, obj=None): - """Function produces a dictionary of the symbol and the corresponding numerical value""" + """Function produces a list of the values in the parameters class, or any class passed""" subs = list() iter_vals = obj.__dict__.values() if obj is not None else self.__dict__.values() @@ -1350,12 +1350,12 @@ def _parameter_values(self, obj=None): @property def _all_items(self): """ - Function to return a dict of all symbols that represent parameters, + Function to return a list of all values in the parameter class, along with their current numerical values. Returns ------- - dict + list """ subs = self._parameter_values() diff --git a/qgs/tensors/symbolic_qgtensor.py b/qgs/tensors/symbolic_qgtensor.py index 856fbec..75e880b 100644 --- a/qgs/tensors/symbolic_qgtensor.py +++ b/qgs/tensors/symbolic_qgtensor.py @@ -1473,7 +1473,7 @@ def _shift_dict_keys(dic, shift): def _parameter_substitutions(params, continuation_variables): """ - Returns the set of parameters values that are the be substituted, + Returns a dict of parameters values that are to be substituted, removing the parameters given in `continuation_variables`. """ @@ -1492,7 +1492,7 @@ def _parameter_substitutions(params, continuation_variables): else: # Try ... who knows... subs.remove(cv) - # make the remaining items into a dict + # make the remaining items into a dict to pass to sympy subs function sub_dic = {} for p in subs: if p.symbol is not None: From d4a195bd6c3e017debf1b232aacf1c7a20701ac1 Mon Sep 17 00:00:00 2001 From: ushham Date: Fri, 28 Mar 2025 10:59:53 +0100 Subject: [PATCH 10/15] continuation_variables made mandatory and doc edits --- qgs/functions/symbolic_tendencies.py | 16 ++++++++-------- qgs/tensors/symbolic_qgtensor.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/qgs/functions/symbolic_tendencies.py b/qgs/functions/symbolic_tendencies.py index 631f9f5..0d9ff8a 100644 --- a/qgs/functions/symbolic_tendencies.py +++ b/qgs/functions/symbolic_tendencies.py @@ -39,7 +39,7 @@ } -def create_symbolic_tendencies(params, atm_ip=None, ocn_ip=None, gnd_ip=None, continuation_variables=None, +def create_symbolic_tendencies(params, continuation_variables, atm_ip=None, ocn_ip=None, gnd_ip=None, language='python', return_inner_products=False, return_jacobian=False, return_symbolic_eqs=False, return_symbolic_qgtensor=False): """Function to output the raw symbolic tendencies of the qgs model. @@ -48,16 +48,16 @@ def create_symbolic_tendencies(params, atm_ip=None, ocn_ip=None, gnd_ip=None, co ---------- params: QgParams The parameters fully specifying the model configuration. + continuation_variables: list(Parameter, ScalingParameter or ParametersArray) or `None` + The variables to not substitute and to leave in the equations. + if `None`, no variables are substituted. + If an empty list is provided, then all variables are substituted, providing fully numerical tendencies. atm_ip: AtmosphericSymbolicInnerProducts, optional Allows for stored inner products to be input. ocn_ip: OceanSymbolicInnerProducts, optional Allows for stored inner products to be input. gnd_ip: GroundSymbolicInnerProducts, optional Allows for stored inner products to be input. - continuation_variables: list(Parameter, ScalingParameter or ParametersArray) - The variables to not substitute and to leave in the equations, if `None`, no variables are substituted. - If an empty list is provided, then all variables are substituted, providing fully numerical tendencies. - Default to `None'. language: str Options for the output language syntax: 'python', 'julia', 'fortran', 'auto', 'mathematica'. Default to 'python'. @@ -374,7 +374,7 @@ def equation_as_function(equations, params, language='python', continuation_vari - `mathematica` Default to `python`. - continuation_variables: list(Parameter, ScalingParameter, ParametersArray) + continuation_variables: list(Parameter, ScalingParameter, ParametersArray) or `None` Variables that are not substituted with numerical values. If `None`, all symbols are substituted. Returns @@ -493,7 +493,7 @@ def jacobian_as_function(equations, params, language='python', continuation_vari - `mathematica` Default to `python`. - continuation_variables: list(Parameter, ScalingParameter, ParametersArray) + continuation_variables: list(Parameter, ScalingParameter, ParametersArray) or `None` Variables that are not substituted with numerical values. If `None`, all symbols are substituted. Returns @@ -604,7 +604,7 @@ def create_auto_file(equations, params, continuation_variables, auto_main_templa Dictionary of the substituted symbolic model equations params: QgParams The parameters fully specifying the model configuration. - continuation_variables: list(Parameter, ScalingParameter or ParametersArray) + continuation_variables: list(Parameter, ScalingParameter or ParametersArray) or `None` Variables that are not substituted with numerical values. If `None`, no symbols are substituted auto_main_template: str, optional The template to be used to generate the main AUTO file. diff --git a/qgs/tensors/symbolic_qgtensor.py b/qgs/tensors/symbolic_qgtensor.py index 75e880b..4af20bb 100644 --- a/qgs/tensors/symbolic_qgtensor.py +++ b/qgs/tensors/symbolic_qgtensor.py @@ -807,7 +807,7 @@ def sub_tensor(self, tensor=None, continuation_variables=None): - a dictionary with keys of non-zero coordinates, and values of Sympy expressions or floats - or a sparse Sympy tensor - continuation_variables: list(Parameter, ScalingParameter or ParametersArray) + continuation_variables: list(Parameter, ScalingParameter or ParametersArray) or `None` Variables which remain symbolic, all other variables are substituted with numerical values. If `None` all variables are substituted. From f2627359d896a53f18e476c40188893097e9c27e Mon Sep 17 00:00:00 2001 From: Jonathan Demaeyer Date: Fri, 28 Mar 2025 11:05:56 +0100 Subject: [PATCH 11/15] Making continutation_variables arg mandatory --- qgs/functions/symbolic_tendencies.py | 53 +++++++++++++++------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/qgs/functions/symbolic_tendencies.py b/qgs/functions/symbolic_tendencies.py index 631f9f5..bc31f86 100644 --- a/qgs/functions/symbolic_tendencies.py +++ b/qgs/functions/symbolic_tendencies.py @@ -39,7 +39,7 @@ } -def create_symbolic_tendencies(params, atm_ip=None, ocn_ip=None, gnd_ip=None, continuation_variables=None, +def create_symbolic_tendencies(params, continuation_variables, atm_ip=None, ocn_ip=None, gnd_ip=None, language='python', return_inner_products=False, return_jacobian=False, return_symbolic_eqs=False, return_symbolic_qgtensor=False): """Function to output the raw symbolic tendencies of the qgs model. @@ -48,26 +48,25 @@ def create_symbolic_tendencies(params, atm_ip=None, ocn_ip=None, gnd_ip=None, co ---------- params: QgParams The parameters fully specifying the model configuration. + continuation_variables: list(Parameter, ScalingParameter or ParametersArray) or None + The variables to not substitute and to leave in the equations, if `None`, no variables are substituted. + If an empty list is provided, then all variables are substituted, providing fully numerical tendencies. atm_ip: AtmosphericSymbolicInnerProducts, optional Allows for stored inner products to be input. ocn_ip: OceanSymbolicInnerProducts, optional Allows for stored inner products to be input. gnd_ip: GroundSymbolicInnerProducts, optional Allows for stored inner products to be input. - continuation_variables: list(Parameter, ScalingParameter or ParametersArray) - The variables to not substitute and to leave in the equations, if `None`, no variables are substituted. - If an empty list is provided, then all variables are substituted, providing fully numerical tendencies. - Default to `None'. - language: str + language: str, optional Options for the output language syntax: 'python', 'julia', 'fortran', 'auto', 'mathematica'. Default to 'python'. - return_inner_products: bool + return_inner_products: bool, optional If `True`, return the inner products of the model. Default to `False`. - return_jacobian: bool + return_jacobian: bool, optional If `True`, return the Jacobian of the model. Default to `False`. - return_symbolic_eqs: bool + return_symbolic_eqs: bool, optional If `True`, return the substituted symbolic equations. - return_symbolic_qgtensor: bool + return_symbolic_qgtensor: bool, optional If `True`, return the symbolic tendencies tensor of the model. Default to `False`. Returns @@ -205,7 +204,7 @@ def translate_equations(equations, language='python'): ---------- equations: dict(str), list, str Dictionary, list, or string of the symbolic model equations. - language: str + language: str, optional Language syntax that the equations are returned in. Options are: - `python` @@ -265,9 +264,9 @@ def format_equations(equations, params, save_loc=None, language='python', print_ Dictionary of symbolic model equations. params: QgParams The parameters fully specifying the model configuration. - save_loc: str + save_loc: str, optional Location to save the outputs as a .txt file. - language: str + language: str, optional Language syntax that the equations are returned in. Options are: - `python` @@ -277,7 +276,7 @@ def format_equations(equations, params, save_loc=None, language='python', print_ - `mathematica` Default to `python`. - print_equations: bool + print_equations: bool, optional If `True`, equations are printed by the function, if `False`, equation strings are returned by the function. Defaults to `False` @@ -354,7 +353,7 @@ def equations_to_string(equations): return str_eq -def equation_as_function(equations, params, language='python', continuation_variables=None): +def equation_as_function(equations, params, continuation_variables, language='python'): """Converts the symbolic equations to a function in string format in the language syntax specified, or a lambdified python function. @@ -364,7 +363,11 @@ def equation_as_function(equations, params, language='python', continuation_vari Dictionary of the substituted symbolic model equations. params: QgParams The parameters fully specifying the model configuration. - language: str + continuation_variables: list(Parameter, ScalingParameter, ParametersArray) or None + Variables that are not substituted with numerical values. If `None`, all symbols are substituted. + The variables to not substitute and to leave in the equations, if `None`, no variables are substituted. + If an empty list is provided, then all variables are substituted, providing fully numerical tendencies. + language: str, optional Language syntax that the equations are returned in. Options are: - `python` @@ -374,8 +377,6 @@ def equation_as_function(equations, params, language='python', continuation_vari - `mathematica` Default to `python`. - continuation_variables: list(Parameter, ScalingParameter, ParametersArray) - Variables that are not substituted with numerical values. If `None`, all symbols are substituted. Returns ------- @@ -473,7 +474,7 @@ def equation_as_function(equations, params, language='python', continuation_vari return f_output -def jacobian_as_function(equations, params, language='python', continuation_variables=None): +def jacobian_as_function(equations, params, continuation_variables, language='python'): """Converts the symbolic equations of the jacobain to a function in string format in the language syntax specified, or a lambdified python function. @@ -483,7 +484,11 @@ def jacobian_as_function(equations, params, language='python', continuation_vari Dictionary of the substituted symbolic model equations. params: QgParams The parameters fully specifying the model configuration. - language: str + continuation_variables: list(Parameter, ScalingParameter, ParametersArray) or None + Variables that are not substituted with numerical values. If `None`, all symbols are substituted. + The variables to not substitute and to leave in the equations, if `None`, no variables are substituted. + If an empty list is provided, then all variables are substituted, providing fully numerical tendencies. + language: str, optional Language syntax that the equations are returned in. Options are: - `python` @@ -493,8 +498,6 @@ def jacobian_as_function(equations, params, language='python', continuation_vari - `mathematica` Default to `python`. - continuation_variables: list(Parameter, ScalingParameter, ParametersArray) - Variables that are not substituted with numerical values. If `None`, all symbols are substituted. Returns ------- @@ -604,8 +607,10 @@ def create_auto_file(equations, params, continuation_variables, auto_main_templa Dictionary of the substituted symbolic model equations params: QgParams The parameters fully specifying the model configuration. - continuation_variables: list(Parameter, ScalingParameter or ParametersArray) - Variables that are not substituted with numerical values. If `None`, no symbols are substituted + continuation_variables: list(Parameter, ScalingParameter, ParametersArray) + Variables that are not substituted with numerical values. + The variables to not substitute and to leave in the equations. + There must be at least one variable in this list and, due to AUTO constrains, its maximum length is 10. auto_main_template: str, optional The template to be used to generate the main AUTO file. If not provided, use the default template. From a4157c8680477294f4e9156fad3946b1312b7b89 Mon Sep 17 00:00:00 2001 From: Jonathan Demaeyer Date: Fri, 28 Mar 2025 11:12:46 +0100 Subject: [PATCH 12/15] Cont'd --- qgs/functions/symbolic_tendencies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qgs/functions/symbolic_tendencies.py b/qgs/functions/symbolic_tendencies.py index b6d8d91..987a0ea 100644 --- a/qgs/functions/symbolic_tendencies.py +++ b/qgs/functions/symbolic_tendencies.py @@ -48,7 +48,7 @@ def create_symbolic_tendencies(params, continuation_variables, atm_ip=None, ocn_ ---------- params: QgParams The parameters fully specifying the model configuration. - continuation_variables: list(Parameter, ScalingParameter or ParametersArray) or `None` + continuation_variables: list(Parameter, ScalingParameter or ParametersArray) or None The variables to not substitute and to leave in the equations. if `None`, no variables are substituted. If an empty list is provided, then all variables are substituted, providing fully numerical tendencies. From c17b723c7043ac38e1168c01918d1309609d8c6a Mon Sep 17 00:00:00 2001 From: Jonathan Demaeyer Date: Fri, 28 Mar 2025 11:16:33 +0100 Subject: [PATCH 13/15] Cont'd --- qgs/functions/symbolic_tendencies.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/qgs/functions/symbolic_tendencies.py b/qgs/functions/symbolic_tendencies.py index 987a0ea..40eb9d6 100644 --- a/qgs/functions/symbolic_tendencies.py +++ b/qgs/functions/symbolic_tendencies.py @@ -50,7 +50,7 @@ def create_symbolic_tendencies(params, continuation_variables, atm_ip=None, ocn_ The parameters fully specifying the model configuration. continuation_variables: list(Parameter, ScalingParameter or ParametersArray) or None The variables to not substitute and to leave in the equations. - if `None`, no variables are substituted. + If `None`, no variables are substituted. If an empty list is provided, then all variables are substituted, providing fully numerical tendencies. atm_ip: AtmosphericSymbolicInnerProducts, optional Allows for stored inner products to be input. @@ -365,8 +365,8 @@ def equation_as_function(equations, params, continuation_variables, language='py params: QgParams The parameters fully specifying the model configuration. continuation_variables: list(Parameter, ScalingParameter, ParametersArray) or None - Variables that are not substituted with numerical values. If `None`, all symbols are substituted. - The variables to not substitute and to leave in the equations, if `None`, no variables are substituted. + The variables to not substitute and to leave in the equations. + If `None`, no variables are substituted. If an empty list is provided, then all variables are substituted, providing fully numerical tendencies. language: str, optional Language syntax that the equations are returned in. Options are: @@ -486,8 +486,8 @@ def jacobian_as_function(equations, params, continuation_variables, language='py params: QgParams The parameters fully specifying the model configuration. continuation_variables: list(Parameter, ScalingParameter, ParametersArray) or None - Variables that are not substituted with numerical values. If `None`, all symbols are substituted. - The variables to not substitute and to leave in the equations, if `None`, no variables are substituted. + The variables to not substitute and to leave in the equations. + If `None`, no variables are substituted. If an empty list is provided, then all variables are substituted, providing fully numerical tendencies. language: str, optional Language syntax that the equations are returned in. Options are: @@ -609,9 +609,8 @@ def create_auto_file(equations, params, continuation_variables, auto_main_templa params: QgParams The parameters fully specifying the model configuration. continuation_variables: list(Parameter, ScalingParameter, ParametersArray) - Variables that are not substituted with numerical values. The variables to not substitute and to leave in the equations. - There must be at least one variable in this list and, due to AUTO constrains, its maximum length is 10. + There must be at least one variable in this list and, due to AUTO constraints, its maximum length is 10. auto_main_template: str, optional The template to be used to generate the main AUTO file. If not provided, use the default template. From bda2edb680df74ec41ae2f045ca3163d905f261f Mon Sep 17 00:00:00 2001 From: Jonathan Demaeyer Date: Fri, 28 Mar 2025 11:21:38 +0100 Subject: [PATCH 14/15] Precisions --- qgs/functions/symbolic_tendencies.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qgs/functions/symbolic_tendencies.py b/qgs/functions/symbolic_tendencies.py index 40eb9d6..5a6da6b 100644 --- a/qgs/functions/symbolic_tendencies.py +++ b/qgs/functions/symbolic_tendencies.py @@ -49,7 +49,7 @@ def create_symbolic_tendencies(params, continuation_variables, atm_ip=None, ocn_ params: QgParams The parameters fully specifying the model configuration. continuation_variables: list(Parameter, ScalingParameter or ParametersArray) or None - The variables to not substitute and to leave in the equations. + The variables to not substitute by their numerical value and to leave in the equations. If `None`, no variables are substituted. If an empty list is provided, then all variables are substituted, providing fully numerical tendencies. atm_ip: AtmosphericSymbolicInnerProducts, optional @@ -365,7 +365,7 @@ def equation_as_function(equations, params, continuation_variables, language='py params: QgParams The parameters fully specifying the model configuration. continuation_variables: list(Parameter, ScalingParameter, ParametersArray) or None - The variables to not substitute and to leave in the equations. + The variables to not substitute by their numerical value and to leave in the equations. If `None`, no variables are substituted. If an empty list is provided, then all variables are substituted, providing fully numerical tendencies. language: str, optional @@ -486,7 +486,7 @@ def jacobian_as_function(equations, params, continuation_variables, language='py params: QgParams The parameters fully specifying the model configuration. continuation_variables: list(Parameter, ScalingParameter, ParametersArray) or None - The variables to not substitute and to leave in the equations. + The variables to not substitute by their numerical value and to leave in the equations. If `None`, no variables are substituted. If an empty list is provided, then all variables are substituted, providing fully numerical tendencies. language: str, optional @@ -609,7 +609,7 @@ def create_auto_file(equations, params, continuation_variables, auto_main_templa params: QgParams The parameters fully specifying the model configuration. continuation_variables: list(Parameter, ScalingParameter, ParametersArray) - The variables to not substitute and to leave in the equations. + The variables to not substitute by their numerical value and to leave in the equations. There must be at least one variable in this list and, due to AUTO constraints, its maximum length is 10. auto_main_template: str, optional The template to be used to generate the main AUTO file. From c966e95dd00139fca7dde9f3db43bc89bf988479 Mon Sep 17 00:00:00 2001 From: ushham Date: Fri, 28 Mar 2025 12:09:32 +0100 Subject: [PATCH 15/15] Removal of pi substitution --- qgs/functions/symbolic_tendencies.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/qgs/functions/symbolic_tendencies.py b/qgs/functions/symbolic_tendencies.py index 5a6da6b..0e37fb8 100644 --- a/qgs/functions/symbolic_tendencies.py +++ b/qgs/functions/symbolic_tendencies.py @@ -18,19 +18,16 @@ python_lang_translation = { 'sqrt': 'math.sqrt', - 'pi': 'math.pi', 'lambda': 'lmda' # Remove conflict for lambda function in python } fortran_lang_translation = { 'conjugate': 'CONJG', 'epsilon': 'eps' # Remove conflict for EPSILON function in fortran - # TODO: may need to add variable for pi } julia_lang_translation = { '**': '^', - 'pi': 'pi()', 'conjugate': 'conj' }