Solverz 0.0.1rc1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- solverz-0.0.1rc1/.gitattributes +2 -0
- solverz-0.0.1rc1/.github/workflows/debug github action.yml +19 -0
- solverz-0.0.1rc1/.github/workflows/doc-deploy.yml +56 -0
- solverz-0.0.1rc1/.github/workflows/python-package.yml +28 -0
- solverz-0.0.1rc1/.gitignore +23 -0
- solverz-0.0.1rc1/PKG-INFO +136 -0
- solverz-0.0.1rc1/README.md +111 -0
- solverz-0.0.1rc1/Solverz/__init__.py +15 -0
- solverz-0.0.1rc1/Solverz/code_printer/__init__.py +0 -0
- solverz-0.0.1rc1/Solverz/code_printer/make_module.py +34 -0
- solverz-0.0.1rc1/Solverz/code_printer/make_pyfunc.py +5 -0
- solverz-0.0.1rc1/Solverz/code_printer/matlab_printer.py +0 -0
- solverz-0.0.1rc1/Solverz/code_printer/py_printer.py +893 -0
- solverz-0.0.1rc1/Solverz/code_printer/test/__init__.py +0 -0
- solverz-0.0.1rc1/Solverz/code_printer/test/test_py_printer.py +266 -0
- solverz-0.0.1rc1/Solverz/equation/__init__.py +0 -0
- solverz-0.0.1rc1/Solverz/equation/eqn.py +487 -0
- solverz-0.0.1rc1/Solverz/equation/equations.py +641 -0
- solverz-0.0.1rc1/Solverz/equation/param.py +153 -0
- solverz-0.0.1rc1/Solverz/equation/test/__init__.py +0 -0
- solverz-0.0.1rc1/Solverz/equation/test/test_DAE.py +22 -0
- solverz-0.0.1rc1/Solverz/equation/test/test_Param.py +73 -0
- solverz-0.0.1rc1/Solverz/equation/test/test_eqn.py +22 -0
- solverz-0.0.1rc1/Solverz/equation/test/test_jac.py +65 -0
- solverz-0.0.1rc1/Solverz/equation/trigger.py +0 -0
- solverz-0.0.1rc1/Solverz/model/__init__.py +0 -0
- solverz-0.0.1rc1/Solverz/model/basic.py +93 -0
- solverz-0.0.1rc1/Solverz/num_api/Array.py +57 -0
- solverz-0.0.1rc1/Solverz/num_api/__init__.py +0 -0
- solverz-0.0.1rc1/Solverz/num_api/custom_function.py +218 -0
- solverz-0.0.1rc1/Solverz/num_api/num_eqn.py +38 -0
- solverz-0.0.1rc1/Solverz/num_api/numjac.py +93 -0
- solverz-0.0.1rc1/Solverz/num_api/test/__init__.py +0 -0
- solverz-0.0.1rc1/Solverz/num_api/test/test_Array.py +68 -0
- solverz-0.0.1rc1/Solverz/num_api/test/test_custom_func.py +51 -0
- solverz-0.0.1rc1/Solverz/num_api/test/test_numjac.py +25 -0
- solverz-0.0.1rc1/Solverz/solvers/__init__.py +4 -0
- solverz-0.0.1rc1/Solverz/solvers/daesolver/__init__.py +3 -0
- solverz-0.0.1rc1/Solverz/solvers/daesolver/beuler.py +83 -0
- solverz-0.0.1rc1/Solverz/solvers/daesolver/daeic.py +53 -0
- solverz-0.0.1rc1/Solverz/solvers/daesolver/rodas.py +486 -0
- solverz-0.0.1rc1/Solverz/solvers/daesolver/trapezoidal.py +84 -0
- solverz-0.0.1rc1/Solverz/solvers/daesolver/utilities.py +17 -0
- solverz-0.0.1rc1/Solverz/solvers/fdesolver.py +175 -0
- solverz-0.0.1rc1/Solverz/solvers/laesolver.py +36 -0
- solverz-0.0.1rc1/Solverz/solvers/nlaesolver/__init__.py +3 -0
- solverz-0.0.1rc1/Solverz/solvers/nlaesolver/cnr.py +115 -0
- solverz-0.0.1rc1/Solverz/solvers/nlaesolver/lm.py +51 -0
- solverz-0.0.1rc1/Solverz/solvers/nlaesolver/nr.py +54 -0
- solverz-0.0.1rc1/Solverz/solvers/nlaesolver/utilities.py +10 -0
- solverz-0.0.1rc1/Solverz/solvers/odesolver/__init__.py +0 -0
- solverz-0.0.1rc1/Solverz/solvers/odesolver/ode45.py +148 -0
- solverz-0.0.1rc1/Solverz/solvers/odesolver/rock.py +0 -0
- solverz-0.0.1rc1/Solverz/solvers/option.py +37 -0
- solverz-0.0.1rc1/Solverz/solvers/parser.py +108 -0
- solverz-0.0.1rc1/Solverz/solvers/solution.py +78 -0
- solverz-0.0.1rc1/Solverz/solvers/stats.py +12 -0
- solverz-0.0.1rc1/Solverz/solvers/test/__init__.py +0 -0
- solverz-0.0.1rc1/Solverz/solvers/test/test_rodas_event.py +84 -0
- solverz-0.0.1rc1/Solverz/sym_algebra/__init__.py +0 -0
- solverz-0.0.1rc1/Solverz/sym_algebra/functions.py +574 -0
- solverz-0.0.1rc1/Solverz/sym_algebra/matrix_calculus.py +455 -0
- solverz-0.0.1rc1/Solverz/sym_algebra/symbols.py +239 -0
- solverz-0.0.1rc1/Solverz/sym_algebra/test/__init__.py +0 -0
- solverz-0.0.1rc1/Solverz/sym_algebra/test/test_finite_difference.py +103 -0
- solverz-0.0.1rc1/Solverz/sym_algebra/test/test_matrix_calculus.py +48 -0
- solverz-0.0.1rc1/Solverz/sym_algebra/test/test_num_alg.py +104 -0
- solverz-0.0.1rc1/Solverz/sym_algebra/test/test_symbols.py +11 -0
- solverz-0.0.1rc1/Solverz/sym_algebra/transform.py +172 -0
- solverz-0.0.1rc1/Solverz/utilities/__init__.py +0 -0
- solverz-0.0.1rc1/Solverz/utilities/address.py +81 -0
- solverz-0.0.1rc1/Solverz/utilities/io.py +65 -0
- solverz-0.0.1rc1/Solverz/utilities/profile.py +14 -0
- solverz-0.0.1rc1/Solverz/utilities/test/__init__.py +0 -0
- solverz-0.0.1rc1/Solverz/utilities/test/test_address.py +41 -0
- solverz-0.0.1rc1/Solverz/utilities/type_checker.py +12 -0
- solverz-0.0.1rc1/Solverz/variable/__init__.py +0 -0
- solverz-0.0.1rc1/Solverz/variable/ssymbol.py +127 -0
- solverz-0.0.1rc1/Solverz/variable/test/__init__.py +0 -0
- solverz-0.0.1rc1/Solverz/variable/test/test_variable.py +123 -0
- solverz-0.0.1rc1/Solverz/variable/variables.py +282 -0
- solverz-0.0.1rc1/docs/Makefile +20 -0
- solverz-0.0.1rc1/docs/ext/convert-svg-to-pdf.py +99 -0
- solverz-0.0.1rc1/docs/ext/docscrape.py +555 -0
- solverz-0.0.1rc1/docs/ext/docscrape_sphinx.py +280 -0
- solverz-0.0.1rc1/docs/ext/numpydoc.py +196 -0
- solverz-0.0.1rc1/docs/make.bat +35 -0
- solverz-0.0.1rc1/docs/requirements.txt +21 -0
- solverz-0.0.1rc1/docs/src/_static/custom.css +145 -0
- solverz-0.0.1rc1/docs/src/_static/sympylogo.png +0 -0
- solverz-0.0.1rc1/docs/src/_static/sympylogo_big.png +0 -0
- solverz-0.0.1rc1/docs/src/advanced.md +134 -0
- solverz-0.0.1rc1/docs/src/conf.py +197 -0
- solverz-0.0.1rc1/docs/src/contributing.md +9 -0
- solverz-0.0.1rc1/docs/src/gethelp.md +12 -0
- solverz-0.0.1rc1/docs/src/gettingstart.md +274 -0
- solverz-0.0.1rc1/docs/src/index.rst +31 -0
- solverz-0.0.1rc1/docs/src/install.md +131 -0
- solverz-0.0.1rc1/docs/src/intro.md +105 -0
- solverz-0.0.1rc1/docs/src/pics/Hierarchy_of_equations.png +0 -0
- solverz-0.0.1rc1/docs/src/pics/difference_stencil.png +0 -0
- solverz-0.0.1rc1/docs/src/pics/res.png +0 -0
- solverz-0.0.1rc1/docs/src/reference/index.rst +50 -0
- solverz-0.0.1rc1/instances/4node3pipe.xlsx +0 -0
- solverz-0.0.1rc1/instances/4node3pipe_bench.xlsx +0 -0
- solverz-0.0.1rc1/instances/4node3pipe_change_sign.xlsx +0 -0
- solverz-0.0.1rc1/instances/4node3pipe_change_sign_bench.xlsx +0 -0
- solverz-0.0.1rc1/instances/dae_test.xlsx +0 -0
- solverz-0.0.1rc1/instances/dynamic_gas_flow_single_pipe.xlsx +0 -0
- solverz-0.0.1rc1/instances/ode_test.xlsx +0 -0
- solverz-0.0.1rc1/instances/test_burger.xlsx +0 -0
- solverz-0.0.1rc1/instances/test_m3b9.xlsx +0 -0
- solverz-0.0.1rc1/instances/test_ode45.xlsx +0 -0
- solverz-0.0.1rc1/instances/test_sirk.xlsx +0 -0
- solverz-0.0.1rc1/pyproject.toml +36 -0
- solverz-0.0.1rc1/requirements.txt +11 -0
- solverz-0.0.1rc1/res.png +0 -0
- solverz-0.0.1rc1/tests/__init__.py +2 -0
- solverz-0.0.1rc1/tests/test_0.py +14 -0
- solverz-0.0.1rc1/tests/test_dae.py +44 -0
- solverz-0.0.1rc1/tests/test_dhspf.py +112 -0
- solverz-0.0.1rc1/tests/test_dhspf_change_sign.py +160 -0
- solverz-0.0.1rc1/tests/test_dyn_gas_flow_single_pipe.py +64 -0
- solverz-0.0.1rc1/tests/test_gasflow.py +33 -0
- solverz-0.0.1rc1/tests/test_m3b9.py +101 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
name: debug github action manually
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
inputs:
|
|
7
|
+
debug_enabled:
|
|
8
|
+
type: boolean
|
|
9
|
+
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
|
|
10
|
+
required: false
|
|
11
|
+
default: false
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
runs-on: windows-latest
|
|
15
|
+
steps:
|
|
16
|
+
# Enable tmate debugging of manually-triggered workflows if the input option was provided
|
|
17
|
+
- name: Setup tmate session
|
|
18
|
+
uses: mxschmitt/action-tmate@v3
|
|
19
|
+
if: ${{ github.event_name == 'workflow_dispatch' && inputs.debug_enabled }}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: Azure Static Web Apps CI/CD
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
types: [opened, synchronize, reopened, closed]
|
|
9
|
+
branches:
|
|
10
|
+
- main
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build_and_deploy_job:
|
|
14
|
+
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
name: Build and Deploy Job
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v3
|
|
19
|
+
with:
|
|
20
|
+
submodules: true
|
|
21
|
+
lfs: false
|
|
22
|
+
- name: Bulid Docs
|
|
23
|
+
uses: actions/setup-python@v4
|
|
24
|
+
with:
|
|
25
|
+
python-version: '3.11'
|
|
26
|
+
cache: 'pip' # caching pip dependencies
|
|
27
|
+
- run: |
|
|
28
|
+
pip install -r requirements.txt
|
|
29
|
+
cd docs
|
|
30
|
+
pip install -r requirements.txt
|
|
31
|
+
make html
|
|
32
|
+
- name: Deploy
|
|
33
|
+
id: builddeploy
|
|
34
|
+
uses: Azure/static-web-apps-deploy@v1
|
|
35
|
+
with:
|
|
36
|
+
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_KIND_MUSHROOM_012AD4400 }}
|
|
37
|
+
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
|
|
38
|
+
action: "upload"
|
|
39
|
+
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
|
|
40
|
+
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
|
|
41
|
+
app_location: "/" # App source code path
|
|
42
|
+
api_location: "" # Api source code path - optional
|
|
43
|
+
output_location: "docs/build/html" # Built app content directory - optional
|
|
44
|
+
###### End of Repository/Build Configurations ######
|
|
45
|
+
|
|
46
|
+
close_pull_request_job:
|
|
47
|
+
if: github.event_name == 'pull_request' && github.event.action == 'closed'
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
name: Close Pull Request Job
|
|
50
|
+
steps:
|
|
51
|
+
- name: Close Pull Request
|
|
52
|
+
id: closepullrequest
|
|
53
|
+
uses: Azure/static-web-apps-deploy@v1
|
|
54
|
+
with:
|
|
55
|
+
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_KIND_MUSHROOM_012AD4400 }}
|
|
56
|
+
action: "close"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# This workflow will install Python dependencies (if not cached), run tests and lint with a variety of Python versions
|
|
2
|
+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
|
|
3
|
+
|
|
4
|
+
name: Python package
|
|
5
|
+
|
|
6
|
+
on: [push]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
|
|
11
|
+
runs-on: ${{ matrix.os }}
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
os: [ windows-latest ]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v3
|
|
18
|
+
- uses: actions/setup-python@v4
|
|
19
|
+
with:
|
|
20
|
+
python-version: '3.11'
|
|
21
|
+
cache: 'pip' # caching pip dependencies
|
|
22
|
+
- run: |
|
|
23
|
+
pip install -r requirements.txt
|
|
24
|
+
cd docs/
|
|
25
|
+
pip install -r requirements.txt
|
|
26
|
+
cd ..
|
|
27
|
+
- run: | # run both independent pytest and doctest
|
|
28
|
+
pytest -vv
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/.idea
|
|
2
|
+
/__pycache__
|
|
3
|
+
/tests/.pytest_cache/
|
|
4
|
+
/.pytest_cache/
|
|
5
|
+
/Solverz/__pycache__
|
|
6
|
+
/tests/__pycache__
|
|
7
|
+
*.docx
|
|
8
|
+
*.mlx
|
|
9
|
+
/study/
|
|
10
|
+
instances/vdp1.mat
|
|
11
|
+
tests/test.ipynb
|
|
12
|
+
tests/jax_test.ipynb
|
|
13
|
+
tests/console.ipynb
|
|
14
|
+
tests/test_julia.jl
|
|
15
|
+
tests/test_sp.ipynb
|
|
16
|
+
*.pyc
|
|
17
|
+
/docs/build/
|
|
18
|
+
Solverz/Lib/
|
|
19
|
+
Solverz/pyvenv.cfg
|
|
20
|
+
Solverz/Scripts
|
|
21
|
+
Solverz/share
|
|
22
|
+
*.nbc
|
|
23
|
+
*.nbi
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: Solverz
|
|
3
|
+
Version: 0.0.1rc1
|
|
4
|
+
Summary: A simulation modelling language
|
|
5
|
+
Project-URL: Homepage, https://github.com/smallbunnies/Solverz
|
|
6
|
+
Project-URL: Issues, https://github.com/smallbunnies/Solverz/issues
|
|
7
|
+
Author-email: Ruizhi Yu <rz.yu@foxmail.com>
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Requires-Python: >=3.11
|
|
13
|
+
Requires-Dist: dill>=0.3.7
|
|
14
|
+
Requires-Dist: matplotlib>=3.5.2
|
|
15
|
+
Requires-Dist: networkx>=3.1
|
|
16
|
+
Requires-Dist: numba==0.58.1
|
|
17
|
+
Requires-Dist: numpy>=1.26.3
|
|
18
|
+
Requires-Dist: openpyxl>=3.0.10
|
|
19
|
+
Requires-Dist: pandas>=1.4.2
|
|
20
|
+
Requires-Dist: pytest>=7.2.2
|
|
21
|
+
Requires-Dist: scipy>=1.12.0
|
|
22
|
+
Requires-Dist: sympy>=1.11.1
|
|
23
|
+
Requires-Dist: tqdm>=4.64.1
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# Overview
|
|
27
|
+
Solverz is an open-source python-based simulation modelling language that provides symbolic interfaces for you to model your equations and can then generate functions or numba-jitted python modules for numerical solutions.
|
|
28
|
+
|
|
29
|
+
Solverz supports three types of abstract equation types, that are
|
|
30
|
+
|
|
31
|
+
- Algebraic Equations (AEs) $0=F(y,p)$
|
|
32
|
+
- Finite Difference Algebraic Equations (FDAEs) $0=F(y,p,y_0)$
|
|
33
|
+
- Differential Algebraic Equations (DAEs) $M\dot{y}=F(t,y,p)$
|
|
34
|
+
|
|
35
|
+
where $p$ is the parameter set of your models, $y_0$ is the previous time node value of $y$.
|
|
36
|
+
|
|
37
|
+
For example, we want to know how long it takes for an apple to fall from a tree to the ground. We have the DAE
|
|
38
|
+
|
|
39
|
+
$$
|
|
40
|
+
\begin{aligned}
|
|
41
|
+
&v'=-9.8\\
|
|
42
|
+
&h'=v
|
|
43
|
+
\end{aligned}
|
|
44
|
+
$$
|
|
45
|
+
|
|
46
|
+
with $v(0)=20$ and $h(0)=0$, we can just type the codes
|
|
47
|
+
```python
|
|
48
|
+
import matplotlib.pyplot as plt
|
|
49
|
+
import numpy as np
|
|
50
|
+
from Solverz import Model, Var, Ode, Opt, made_numerical, Rodas
|
|
51
|
+
|
|
52
|
+
# Declare a simulation model
|
|
53
|
+
m = Model()
|
|
54
|
+
# Declare variables and equations
|
|
55
|
+
m.h = Var('h', 0)
|
|
56
|
+
m.v = Var('v', 20)
|
|
57
|
+
m.f1 = Ode('f1', f=m.v, diff_var=m.h)
|
|
58
|
+
m.f2 = Ode('f2', f=-9.8, diff_var=m.v)
|
|
59
|
+
# Create the symbolic equation instance and the variable combination
|
|
60
|
+
bball, y0 = m.create_instance()
|
|
61
|
+
# Transform symbolic equations to python numerical functions.
|
|
62
|
+
nbball = made_numerical(bball, y0, sparse=True)
|
|
63
|
+
|
|
64
|
+
# Define events, that is, if the apple hits the ground then the simulation will cease.
|
|
65
|
+
def events(t, y):
|
|
66
|
+
value = np.array([y[0]])
|
|
67
|
+
isterminal = np.array([1])
|
|
68
|
+
direction = np.array([-1])
|
|
69
|
+
return value, isterminal, direction
|
|
70
|
+
|
|
71
|
+
# Solve the DAE
|
|
72
|
+
sol = Rodas(nbball,
|
|
73
|
+
np.linspace(0, 30, 100),
|
|
74
|
+
y0,
|
|
75
|
+
Opt(event=events))
|
|
76
|
+
|
|
77
|
+
# Visualize
|
|
78
|
+
plt.plot(sol.T, sol.Y['h'][:, 0])
|
|
79
|
+
plt.xlabel('Time/s')
|
|
80
|
+
plt.ylabel('h/m')
|
|
81
|
+
plt.show()
|
|
82
|
+
```
|
|
83
|
+
Then we have
|
|
84
|
+
|
|
85
|
+

|
|
86
|
+
|
|
87
|
+
The model is solved with the stiffly accurate Rosenbrock type method, but you can also write your own solvers by the generated numerical interfaces since, for example, the Newton-Raphson solver implememtation for AEs is as simple as below.
|
|
88
|
+
```python
|
|
89
|
+
@ae_io_parser
|
|
90
|
+
def nr_method(eqn: nAE,
|
|
91
|
+
y: np.ndarray,
|
|
92
|
+
opt: Opt = None):
|
|
93
|
+
if opt is None:
|
|
94
|
+
opt = Opt(ite_tol=1e-8)
|
|
95
|
+
|
|
96
|
+
tol = opt.ite_tol
|
|
97
|
+
p = eqn.p
|
|
98
|
+
df = eqn.F(y, p)
|
|
99
|
+
ite = 0
|
|
100
|
+
# main loop
|
|
101
|
+
while max(abs(df)) > tol:
|
|
102
|
+
ite = ite + 1
|
|
103
|
+
y = y - solve(eqn.J(y, p), df)
|
|
104
|
+
df = eqn.F(y, p)
|
|
105
|
+
if ite >= 100:
|
|
106
|
+
print(f"Cannot converge within 100 iterations. Deviation: {max(abs(df))}!")
|
|
107
|
+
break
|
|
108
|
+
|
|
109
|
+
return aesol(y, ite)
|
|
110
|
+
```
|
|
111
|
+
The implementation of the NR solver just resembles the formulae you read in any numerical analysis book. This is because the numerical AE object `eqn` provides the $F(t,y,p)$ interface and its Jacobian $J(t,y,p)$, which is derived by symbolic differentiation.
|
|
112
|
+
|
|
113
|
+
Sometimes you have very complex models and you dont want to re-derive them everytime. With Solverz, you can just use
|
|
114
|
+
```python
|
|
115
|
+
from Solverz import module_printer
|
|
116
|
+
|
|
117
|
+
pyprinter = module_printer(bball,
|
|
118
|
+
y0,
|
|
119
|
+
'bounceball',
|
|
120
|
+
jit=True)
|
|
121
|
+
pyprinter.render()
|
|
122
|
+
```
|
|
123
|
+
to generate an independent python module of your simulation models. You can import them to your .py file by
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
from bounceball import mdl as nbball, y as y0
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
# Installation
|
|
130
|
+
|
|
131
|
+
# Useful Resources
|
|
132
|
+
|
|
133
|
+
- [Solverz Documentation](https://docs.solverz.org)
|
|
134
|
+
- [Solverz Cookbook](https://cookbook.solverz.org)
|
|
135
|
+
|
|
136
|
+
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Overview
|
|
2
|
+
Solverz is an open-source python-based simulation modelling language that provides symbolic interfaces for you to model your equations and can then generate functions or numba-jitted python modules for numerical solutions.
|
|
3
|
+
|
|
4
|
+
Solverz supports three types of abstract equation types, that are
|
|
5
|
+
|
|
6
|
+
- Algebraic Equations (AEs) $0=F(y,p)$
|
|
7
|
+
- Finite Difference Algebraic Equations (FDAEs) $0=F(y,p,y_0)$
|
|
8
|
+
- Differential Algebraic Equations (DAEs) $M\dot{y}=F(t,y,p)$
|
|
9
|
+
|
|
10
|
+
where $p$ is the parameter set of your models, $y_0$ is the previous time node value of $y$.
|
|
11
|
+
|
|
12
|
+
For example, we want to know how long it takes for an apple to fall from a tree to the ground. We have the DAE
|
|
13
|
+
|
|
14
|
+
$$
|
|
15
|
+
\begin{aligned}
|
|
16
|
+
&v'=-9.8\\
|
|
17
|
+
&h'=v
|
|
18
|
+
\end{aligned}
|
|
19
|
+
$$
|
|
20
|
+
|
|
21
|
+
with $v(0)=20$ and $h(0)=0$, we can just type the codes
|
|
22
|
+
```python
|
|
23
|
+
import matplotlib.pyplot as plt
|
|
24
|
+
import numpy as np
|
|
25
|
+
from Solverz import Model, Var, Ode, Opt, made_numerical, Rodas
|
|
26
|
+
|
|
27
|
+
# Declare a simulation model
|
|
28
|
+
m = Model()
|
|
29
|
+
# Declare variables and equations
|
|
30
|
+
m.h = Var('h', 0)
|
|
31
|
+
m.v = Var('v', 20)
|
|
32
|
+
m.f1 = Ode('f1', f=m.v, diff_var=m.h)
|
|
33
|
+
m.f2 = Ode('f2', f=-9.8, diff_var=m.v)
|
|
34
|
+
# Create the symbolic equation instance and the variable combination
|
|
35
|
+
bball, y0 = m.create_instance()
|
|
36
|
+
# Transform symbolic equations to python numerical functions.
|
|
37
|
+
nbball = made_numerical(bball, y0, sparse=True)
|
|
38
|
+
|
|
39
|
+
# Define events, that is, if the apple hits the ground then the simulation will cease.
|
|
40
|
+
def events(t, y):
|
|
41
|
+
value = np.array([y[0]])
|
|
42
|
+
isterminal = np.array([1])
|
|
43
|
+
direction = np.array([-1])
|
|
44
|
+
return value, isterminal, direction
|
|
45
|
+
|
|
46
|
+
# Solve the DAE
|
|
47
|
+
sol = Rodas(nbball,
|
|
48
|
+
np.linspace(0, 30, 100),
|
|
49
|
+
y0,
|
|
50
|
+
Opt(event=events))
|
|
51
|
+
|
|
52
|
+
# Visualize
|
|
53
|
+
plt.plot(sol.T, sol.Y['h'][:, 0])
|
|
54
|
+
plt.xlabel('Time/s')
|
|
55
|
+
plt.ylabel('h/m')
|
|
56
|
+
plt.show()
|
|
57
|
+
```
|
|
58
|
+
Then we have
|
|
59
|
+
|
|
60
|
+

|
|
61
|
+
|
|
62
|
+
The model is solved with the stiffly accurate Rosenbrock type method, but you can also write your own solvers by the generated numerical interfaces since, for example, the Newton-Raphson solver implememtation for AEs is as simple as below.
|
|
63
|
+
```python
|
|
64
|
+
@ae_io_parser
|
|
65
|
+
def nr_method(eqn: nAE,
|
|
66
|
+
y: np.ndarray,
|
|
67
|
+
opt: Opt = None):
|
|
68
|
+
if opt is None:
|
|
69
|
+
opt = Opt(ite_tol=1e-8)
|
|
70
|
+
|
|
71
|
+
tol = opt.ite_tol
|
|
72
|
+
p = eqn.p
|
|
73
|
+
df = eqn.F(y, p)
|
|
74
|
+
ite = 0
|
|
75
|
+
# main loop
|
|
76
|
+
while max(abs(df)) > tol:
|
|
77
|
+
ite = ite + 1
|
|
78
|
+
y = y - solve(eqn.J(y, p), df)
|
|
79
|
+
df = eqn.F(y, p)
|
|
80
|
+
if ite >= 100:
|
|
81
|
+
print(f"Cannot converge within 100 iterations. Deviation: {max(abs(df))}!")
|
|
82
|
+
break
|
|
83
|
+
|
|
84
|
+
return aesol(y, ite)
|
|
85
|
+
```
|
|
86
|
+
The implementation of the NR solver just resembles the formulae you read in any numerical analysis book. This is because the numerical AE object `eqn` provides the $F(t,y,p)$ interface and its Jacobian $J(t,y,p)$, which is derived by symbolic differentiation.
|
|
87
|
+
|
|
88
|
+
Sometimes you have very complex models and you dont want to re-derive them everytime. With Solverz, you can just use
|
|
89
|
+
```python
|
|
90
|
+
from Solverz import module_printer
|
|
91
|
+
|
|
92
|
+
pyprinter = module_printer(bball,
|
|
93
|
+
y0,
|
|
94
|
+
'bounceball',
|
|
95
|
+
jit=True)
|
|
96
|
+
pyprinter.render()
|
|
97
|
+
```
|
|
98
|
+
to generate an independent python module of your simulation models. You can import them to your .py file by
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from bounceball import mdl as nbball, y as y0
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
# Installation
|
|
105
|
+
|
|
106
|
+
# Useful Resources
|
|
107
|
+
|
|
108
|
+
- [Solverz Documentation](https://docs.solverz.org)
|
|
109
|
+
- [Solverz Cookbook](https://cookbook.solverz.org)
|
|
110
|
+
|
|
111
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from Solverz.equation.eqn import Eqn, Ode, HyperbolicPde
|
|
2
|
+
from Solverz.equation.equations import AE, FDAE, DAE
|
|
3
|
+
from Solverz.equation.param import Param, IdxParam, TimeSeriesParam
|
|
4
|
+
from Solverz.sym_algebra.symbols import idx, Para, iVar, iAliasVar
|
|
5
|
+
from Solverz.sym_algebra.functions import Sign, Abs, transpose, exp, Diag, Mat_Mul, sin, cos, Min, AntiWindUp, Saturation
|
|
6
|
+
from Solverz.num_api.custom_function import minmod_flag, minmod
|
|
7
|
+
from Solverz.variable.variables import Vars, TimeVars, as_Vars
|
|
8
|
+
from Solverz.solvers import *
|
|
9
|
+
from Solverz.code_printer.make_pyfunc import made_numerical
|
|
10
|
+
from Solverz.code_printer.py_printer import render_modules
|
|
11
|
+
from Solverz.code_printer.make_module import module_printer
|
|
12
|
+
from Solverz.utilities.io import save, load, save_result
|
|
13
|
+
from Solverz.utilities.profile import count_time
|
|
14
|
+
from Solverz.variable.ssymbol import Var, AliasVar
|
|
15
|
+
from Solverz.model.basic import Model
|
|
File without changes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from Solverz.code_printer.py_printer import render_modules as py_module_renderer
|
|
4
|
+
from Solverz.equation.equations import AE, FDAE, DAE
|
|
5
|
+
from Solverz.variable.variables import Vars
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class module_printer:
|
|
9
|
+
def __init__(self,
|
|
10
|
+
mdl: AE | FDAE | DAE,
|
|
11
|
+
variables: Vars | List[Vars],
|
|
12
|
+
name: str,
|
|
13
|
+
lang='python',
|
|
14
|
+
directory=None,
|
|
15
|
+
jit=False):
|
|
16
|
+
self.name = name
|
|
17
|
+
self.lang = lang
|
|
18
|
+
self.mdl = mdl
|
|
19
|
+
if isinstance(variables, Vars):
|
|
20
|
+
self.variables = [variables]
|
|
21
|
+
else:
|
|
22
|
+
self.variables = variables
|
|
23
|
+
self.directory = directory
|
|
24
|
+
self.jit = jit
|
|
25
|
+
|
|
26
|
+
def render(self):
|
|
27
|
+
if self.lang == 'python':
|
|
28
|
+
py_module_renderer(self.mdl,
|
|
29
|
+
*self.variables,
|
|
30
|
+
name=self.name,
|
|
31
|
+
directory=self.directory,
|
|
32
|
+
numba=self.jit)
|
|
33
|
+
else:
|
|
34
|
+
raise NotImplemented(f"{self.lang} module renderer not implemented!")
|
|
File without changes
|