Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +1 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/__pycache__/matrices.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/__pycache__/paulialgebra.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/__pycache__/sho.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/curve.py +1763 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/tests/__pycache__/__init__.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/tests/__pycache__/test_mixin.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/tests/test_activation.py +348 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/control/__init__.py +16 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/control/control_plots.py +978 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/tests/test_physics_matrices.py +84 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__init__.py +453 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__pycache__/__init__.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__pycache__/prefixes.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__pycache__/quantities.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/definitions/__init__.py +265 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/dimensions.py +590 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/quantities.py +152 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/__init__.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/cgs.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/length_weight_time.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/mks.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/mksa.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/natural.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/si.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/cgs.py +82 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/length_weight_time.py +156 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/mks.py +46 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/mksa.py +54 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/natural.py +27 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/si.py +377 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__init__.py +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/__init__.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_dimensions.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_dimensionsystem.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_prefixes.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_quantities.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_unitsystem.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_util.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_dimensions.py +150 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_prefixes.py +86 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_unit_system_cgs_gauss.py +55 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_unitsystem.py +86 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_util.py +178 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/unitsystem.py +205 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/util.py +265 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/vector/tests/__pycache__/test_functions.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/vector/tests/__pycache__/test_printing.cpython-311.pyc +0 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/vector/tests/test_vector.py +274 -0
- tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/polys/__pycache__/appellseqs.cpython-311.pyc +0 -0
.gitattributes
CHANGED
|
@@ -263,3 +263,4 @@ tuning-competition-baseline/.venv/lib/python3.11/site-packages/torch/_inductor/_
|
|
| 263 |
.venv/lib/python3.11/site-packages/setuptools/gui-arm64.exe filter=lfs diff=lfs merge=lfs -text
|
| 264 |
.venv/lib/python3.11/site-packages/numpy.libs/libquadmath-96973f99.so.0.0.0 filter=lfs diff=lfs merge=lfs -text
|
| 265 |
.venv/lib/python3.11/site-packages/numpy.libs/libgfortran-040039e1.so.5.0.0 filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 263 |
.venv/lib/python3.11/site-packages/setuptools/gui-arm64.exe filter=lfs diff=lfs merge=lfs -text
|
| 264 |
.venv/lib/python3.11/site-packages/numpy.libs/libquadmath-96973f99.so.0.0.0 filter=lfs diff=lfs merge=lfs -text
|
| 265 |
.venv/lib/python3.11/site-packages/numpy.libs/libgfortran-040039e1.so.5.0.0 filter=lfs diff=lfs merge=lfs -text
|
| 266 |
+
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/stats/__pycache__/stochastic_process_types.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/__pycache__/matrices.cpython-311.pyc
ADDED
|
Binary file (4.56 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/__pycache__/paulialgebra.cpython-311.pyc
ADDED
|
Binary file (8.87 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/__pycache__/sho.cpython-311.pyc
ADDED
|
Binary file (3.5 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/curve.py
ADDED
|
@@ -0,0 +1,1763 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Implementations of characteristic curves for musculotendon models."""
|
| 2 |
+
|
| 3 |
+
from dataclasses import dataclass
|
| 4 |
+
|
| 5 |
+
from sympy.core.expr import UnevaluatedExpr
|
| 6 |
+
from sympy.core.function import ArgumentIndexError, Function
|
| 7 |
+
from sympy.core.numbers import Float, Integer
|
| 8 |
+
from sympy.functions.elementary.exponential import exp, log
|
| 9 |
+
from sympy.functions.elementary.hyperbolic import cosh, sinh
|
| 10 |
+
from sympy.functions.elementary.miscellaneous import sqrt
|
| 11 |
+
from sympy.printing.precedence import PRECEDENCE
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
__all__ = [
|
| 15 |
+
'CharacteristicCurveCollection',
|
| 16 |
+
'CharacteristicCurveFunction',
|
| 17 |
+
'FiberForceLengthActiveDeGroote2016',
|
| 18 |
+
'FiberForceLengthPassiveDeGroote2016',
|
| 19 |
+
'FiberForceLengthPassiveInverseDeGroote2016',
|
| 20 |
+
'FiberForceVelocityDeGroote2016',
|
| 21 |
+
'FiberForceVelocityInverseDeGroote2016',
|
| 22 |
+
'TendonForceLengthDeGroote2016',
|
| 23 |
+
'TendonForceLengthInverseDeGroote2016',
|
| 24 |
+
]
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
class CharacteristicCurveFunction(Function):
|
| 28 |
+
"""Base class for all musculotendon characteristic curve functions."""
|
| 29 |
+
|
| 30 |
+
@classmethod
|
| 31 |
+
def eval(cls):
|
| 32 |
+
msg = (
|
| 33 |
+
f'Cannot directly instantiate {cls.__name__!r}, instances of '
|
| 34 |
+
f'characteristic curves must be of a concrete subclass.'
|
| 35 |
+
|
| 36 |
+
)
|
| 37 |
+
raise TypeError(msg)
|
| 38 |
+
|
| 39 |
+
def _print_code(self, printer):
|
| 40 |
+
"""Print code for the function defining the curve using a printer.
|
| 41 |
+
|
| 42 |
+
Explanation
|
| 43 |
+
===========
|
| 44 |
+
|
| 45 |
+
The order of operations may need to be controlled as constant folding
|
| 46 |
+
the numeric terms within the equations of a musculotendon
|
| 47 |
+
characteristic curve can sometimes results in a numerically-unstable
|
| 48 |
+
expression.
|
| 49 |
+
|
| 50 |
+
Parameters
|
| 51 |
+
==========
|
| 52 |
+
|
| 53 |
+
printer : Printer
|
| 54 |
+
The printer to be used to print a string representation of the
|
| 55 |
+
characteristic curve as valid code in the target language.
|
| 56 |
+
|
| 57 |
+
"""
|
| 58 |
+
return printer._print(printer.parenthesize(
|
| 59 |
+
self.doit(deep=False, evaluate=False), PRECEDENCE['Atom'],
|
| 60 |
+
))
|
| 61 |
+
|
| 62 |
+
_ccode = _print_code
|
| 63 |
+
_cupycode = _print_code
|
| 64 |
+
_cxxcode = _print_code
|
| 65 |
+
_fcode = _print_code
|
| 66 |
+
_jaxcode = _print_code
|
| 67 |
+
_lambdacode = _print_code
|
| 68 |
+
_mpmathcode = _print_code
|
| 69 |
+
_octave = _print_code
|
| 70 |
+
_pythoncode = _print_code
|
| 71 |
+
_numpycode = _print_code
|
| 72 |
+
_scipycode = _print_code
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
class TendonForceLengthDeGroote2016(CharacteristicCurveFunction):
|
| 76 |
+
r"""Tendon force-length curve based on De Groote et al., 2016 [1]_.
|
| 77 |
+
|
| 78 |
+
Explanation
|
| 79 |
+
===========
|
| 80 |
+
|
| 81 |
+
Gives the normalized tendon force produced as a function of normalized
|
| 82 |
+
tendon length.
|
| 83 |
+
|
| 84 |
+
The function is defined by the equation:
|
| 85 |
+
|
| 86 |
+
$fl^T = c_0 \exp{c_3 \left( \tilde{l}^T - c_1 \right)} - c_2$
|
| 87 |
+
|
| 88 |
+
with constant values of $c_0 = 0.2$, $c_1 = 0.995$, $c_2 = 0.25$, and
|
| 89 |
+
$c_3 = 33.93669377311689$.
|
| 90 |
+
|
| 91 |
+
While it is possible to change the constant values, these were carefully
|
| 92 |
+
selected in the original publication to give the characteristic curve
|
| 93 |
+
specific and required properties. For example, the function produces no
|
| 94 |
+
force when the tendon is in an unstrained state. It also produces a force
|
| 95 |
+
of 1 normalized unit when the tendon is under a 5% strain.
|
| 96 |
+
|
| 97 |
+
Examples
|
| 98 |
+
========
|
| 99 |
+
|
| 100 |
+
The preferred way to instantiate :class:`TendonForceLengthDeGroote2016` is using
|
| 101 |
+
the :meth:`~.with_defaults` constructor because this will automatically
|
| 102 |
+
populate the constants within the characteristic curve equation with the
|
| 103 |
+
floating point values from the original publication. This constructor takes
|
| 104 |
+
a single argument corresponding to normalized tendon length. We'll create a
|
| 105 |
+
:class:`~.Symbol` called ``l_T_tilde`` to represent this.
|
| 106 |
+
|
| 107 |
+
>>> from sympy import Symbol
|
| 108 |
+
>>> from sympy.physics.biomechanics import TendonForceLengthDeGroote2016
|
| 109 |
+
>>> l_T_tilde = Symbol('l_T_tilde')
|
| 110 |
+
>>> fl_T = TendonForceLengthDeGroote2016.with_defaults(l_T_tilde)
|
| 111 |
+
>>> fl_T
|
| 112 |
+
TendonForceLengthDeGroote2016(l_T_tilde, 0.2, 0.995, 0.25,
|
| 113 |
+
33.93669377311689)
|
| 114 |
+
|
| 115 |
+
It's also possible to populate the four constants with your own values too.
|
| 116 |
+
|
| 117 |
+
>>> from sympy import symbols
|
| 118 |
+
>>> c0, c1, c2, c3 = symbols('c0 c1 c2 c3')
|
| 119 |
+
>>> fl_T = TendonForceLengthDeGroote2016(l_T_tilde, c0, c1, c2, c3)
|
| 120 |
+
>>> fl_T
|
| 121 |
+
TendonForceLengthDeGroote2016(l_T_tilde, c0, c1, c2, c3)
|
| 122 |
+
|
| 123 |
+
You don't just have to use symbols as the arguments, it's also possible to
|
| 124 |
+
use expressions. Let's create a new pair of symbols, ``l_T`` and
|
| 125 |
+
``l_T_slack``, representing tendon length and tendon slack length
|
| 126 |
+
respectively. We can then represent ``l_T_tilde`` as an expression, the
|
| 127 |
+
ratio of these.
|
| 128 |
+
|
| 129 |
+
>>> l_T, l_T_slack = symbols('l_T l_T_slack')
|
| 130 |
+
>>> l_T_tilde = l_T/l_T_slack
|
| 131 |
+
>>> fl_T = TendonForceLengthDeGroote2016.with_defaults(l_T_tilde)
|
| 132 |
+
>>> fl_T
|
| 133 |
+
TendonForceLengthDeGroote2016(l_T/l_T_slack, 0.2, 0.995, 0.25,
|
| 134 |
+
33.93669377311689)
|
| 135 |
+
|
| 136 |
+
To inspect the actual symbolic expression that this function represents,
|
| 137 |
+
we can call the :meth:`~.doit` method on an instance. We'll use the keyword
|
| 138 |
+
argument ``evaluate=False`` as this will keep the expression in its
|
| 139 |
+
canonical form and won't simplify any constants.
|
| 140 |
+
|
| 141 |
+
>>> fl_T.doit(evaluate=False)
|
| 142 |
+
-0.25 + 0.2*exp(33.93669377311689*(l_T/l_T_slack - 0.995))
|
| 143 |
+
|
| 144 |
+
The function can also be differentiated. We'll differentiate with respect
|
| 145 |
+
to l_T using the ``diff`` method on an instance with the single positional
|
| 146 |
+
argument ``l_T``.
|
| 147 |
+
|
| 148 |
+
>>> fl_T.diff(l_T)
|
| 149 |
+
6.787338754623378*exp(33.93669377311689*(l_T/l_T_slack - 0.995))/l_T_slack
|
| 150 |
+
|
| 151 |
+
References
|
| 152 |
+
==========
|
| 153 |
+
|
| 154 |
+
.. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation
|
| 155 |
+
of direct collocation optimal control problem formulations for
|
| 156 |
+
solving the muscle redundancy problem, Annals of biomedical
|
| 157 |
+
engineering, 44(10), (2016) pp. 2922-2936
|
| 158 |
+
|
| 159 |
+
"""
|
| 160 |
+
|
| 161 |
+
@classmethod
|
| 162 |
+
def with_defaults(cls, l_T_tilde):
|
| 163 |
+
r"""Recommended constructor that will use the published constants.
|
| 164 |
+
|
| 165 |
+
Explanation
|
| 166 |
+
===========
|
| 167 |
+
|
| 168 |
+
Returns a new instance of the tendon force-length function using the
|
| 169 |
+
four constant values specified in the original publication.
|
| 170 |
+
|
| 171 |
+
These have the values:
|
| 172 |
+
|
| 173 |
+
$c_0 = 0.2$
|
| 174 |
+
$c_1 = 0.995$
|
| 175 |
+
$c_2 = 0.25$
|
| 176 |
+
$c_3 = 33.93669377311689$
|
| 177 |
+
|
| 178 |
+
Parameters
|
| 179 |
+
==========
|
| 180 |
+
|
| 181 |
+
l_T_tilde : Any (sympifiable)
|
| 182 |
+
Normalized tendon length.
|
| 183 |
+
|
| 184 |
+
"""
|
| 185 |
+
c0 = Float('0.2')
|
| 186 |
+
c1 = Float('0.995')
|
| 187 |
+
c2 = Float('0.25')
|
| 188 |
+
c3 = Float('33.93669377311689')
|
| 189 |
+
return cls(l_T_tilde, c0, c1, c2, c3)
|
| 190 |
+
|
| 191 |
+
@classmethod
|
| 192 |
+
def eval(cls, l_T_tilde, c0, c1, c2, c3):
|
| 193 |
+
"""Evaluation of basic inputs.
|
| 194 |
+
|
| 195 |
+
Parameters
|
| 196 |
+
==========
|
| 197 |
+
|
| 198 |
+
l_T_tilde : Any (sympifiable)
|
| 199 |
+
Normalized tendon length.
|
| 200 |
+
c0 : Any (sympifiable)
|
| 201 |
+
The first constant in the characteristic equation. The published
|
| 202 |
+
value is ``0.2``.
|
| 203 |
+
c1 : Any (sympifiable)
|
| 204 |
+
The second constant in the characteristic equation. The published
|
| 205 |
+
value is ``0.995``.
|
| 206 |
+
c2 : Any (sympifiable)
|
| 207 |
+
The third constant in the characteristic equation. The published
|
| 208 |
+
value is ``0.25``.
|
| 209 |
+
c3 : Any (sympifiable)
|
| 210 |
+
The fourth constant in the characteristic equation. The published
|
| 211 |
+
value is ``33.93669377311689``.
|
| 212 |
+
|
| 213 |
+
"""
|
| 214 |
+
pass
|
| 215 |
+
|
| 216 |
+
def _eval_evalf(self, prec):
|
| 217 |
+
"""Evaluate the expression numerically using ``evalf``."""
|
| 218 |
+
return self.doit(deep=False, evaluate=False)._eval_evalf(prec)
|
| 219 |
+
|
| 220 |
+
def doit(self, deep=True, evaluate=True, **hints):
|
| 221 |
+
"""Evaluate the expression defining the function.
|
| 222 |
+
|
| 223 |
+
Parameters
|
| 224 |
+
==========
|
| 225 |
+
|
| 226 |
+
deep : bool
|
| 227 |
+
Whether ``doit`` should be recursively called. Default is ``True``.
|
| 228 |
+
evaluate : bool.
|
| 229 |
+
Whether the SymPy expression should be evaluated as it is
|
| 230 |
+
constructed. If ``False``, then no constant folding will be
|
| 231 |
+
conducted which will leave the expression in a more numerically-
|
| 232 |
+
stable for values of ``l_T_tilde`` that correspond to a sensible
|
| 233 |
+
operating range for a musculotendon. Default is ``True``.
|
| 234 |
+
**kwargs : dict[str, Any]
|
| 235 |
+
Additional keyword argument pairs to be recursively passed to
|
| 236 |
+
``doit``.
|
| 237 |
+
|
| 238 |
+
"""
|
| 239 |
+
l_T_tilde, *constants = self.args
|
| 240 |
+
if deep:
|
| 241 |
+
hints['evaluate'] = evaluate
|
| 242 |
+
l_T_tilde = l_T_tilde.doit(deep=deep, **hints)
|
| 243 |
+
c0, c1, c2, c3 = [c.doit(deep=deep, **hints) for c in constants]
|
| 244 |
+
else:
|
| 245 |
+
c0, c1, c2, c3 = constants
|
| 246 |
+
|
| 247 |
+
if evaluate:
|
| 248 |
+
return c0*exp(c3*(l_T_tilde - c1)) - c2
|
| 249 |
+
|
| 250 |
+
return c0*exp(c3*UnevaluatedExpr(l_T_tilde - c1)) - c2
|
| 251 |
+
|
| 252 |
+
def fdiff(self, argindex=1):
|
| 253 |
+
"""Derivative of the function with respect to a single argument.
|
| 254 |
+
|
| 255 |
+
Parameters
|
| 256 |
+
==========
|
| 257 |
+
|
| 258 |
+
argindex : int
|
| 259 |
+
The index of the function's arguments with respect to which the
|
| 260 |
+
derivative should be taken. Argument indexes start at ``1``.
|
| 261 |
+
Default is ``1``.
|
| 262 |
+
|
| 263 |
+
"""
|
| 264 |
+
l_T_tilde, c0, c1, c2, c3 = self.args
|
| 265 |
+
if argindex == 1:
|
| 266 |
+
return c0*c3*exp(c3*UnevaluatedExpr(l_T_tilde - c1))
|
| 267 |
+
elif argindex == 2:
|
| 268 |
+
return exp(c3*UnevaluatedExpr(l_T_tilde - c1))
|
| 269 |
+
elif argindex == 3:
|
| 270 |
+
return -c0*c3*exp(c3*UnevaluatedExpr(l_T_tilde - c1))
|
| 271 |
+
elif argindex == 4:
|
| 272 |
+
return Integer(-1)
|
| 273 |
+
elif argindex == 5:
|
| 274 |
+
return c0*(l_T_tilde - c1)*exp(c3*UnevaluatedExpr(l_T_tilde - c1))
|
| 275 |
+
|
| 276 |
+
raise ArgumentIndexError(self, argindex)
|
| 277 |
+
|
| 278 |
+
def inverse(self, argindex=1):
|
| 279 |
+
"""Inverse function.
|
| 280 |
+
|
| 281 |
+
Parameters
|
| 282 |
+
==========
|
| 283 |
+
|
| 284 |
+
argindex : int
|
| 285 |
+
Value to start indexing the arguments at. Default is ``1``.
|
| 286 |
+
|
| 287 |
+
"""
|
| 288 |
+
return TendonForceLengthInverseDeGroote2016
|
| 289 |
+
|
| 290 |
+
def _latex(self, printer):
|
| 291 |
+
"""Print a LaTeX representation of the function defining the curve.
|
| 292 |
+
|
| 293 |
+
Parameters
|
| 294 |
+
==========
|
| 295 |
+
|
| 296 |
+
printer : Printer
|
| 297 |
+
The printer to be used to print the LaTeX string representation.
|
| 298 |
+
|
| 299 |
+
"""
|
| 300 |
+
l_T_tilde = self.args[0]
|
| 301 |
+
_l_T_tilde = printer._print(l_T_tilde)
|
| 302 |
+
return r'\operatorname{fl}^T \left( %s \right)' % _l_T_tilde
|
| 303 |
+
|
| 304 |
+
|
| 305 |
+
class TendonForceLengthInverseDeGroote2016(CharacteristicCurveFunction):
|
| 306 |
+
r"""Inverse tendon force-length curve based on De Groote et al., 2016 [1]_.
|
| 307 |
+
|
| 308 |
+
Explanation
|
| 309 |
+
===========
|
| 310 |
+
|
| 311 |
+
Gives the normalized tendon length that produces a specific normalized
|
| 312 |
+
tendon force.
|
| 313 |
+
|
| 314 |
+
The function is defined by the equation:
|
| 315 |
+
|
| 316 |
+
${fl^T}^{-1} = frac{\log{\frac{fl^T + c_2}{c_0}}}{c_3} + c_1$
|
| 317 |
+
|
| 318 |
+
with constant values of $c_0 = 0.2$, $c_1 = 0.995$, $c_2 = 0.25$, and
|
| 319 |
+
$c_3 = 33.93669377311689$. This function is the exact analytical inverse
|
| 320 |
+
of the related tendon force-length curve ``TendonForceLengthDeGroote2016``.
|
| 321 |
+
|
| 322 |
+
While it is possible to change the constant values, these were carefully
|
| 323 |
+
selected in the original publication to give the characteristic curve
|
| 324 |
+
specific and required properties. For example, the function produces no
|
| 325 |
+
force when the tendon is in an unstrained state. It also produces a force
|
| 326 |
+
of 1 normalized unit when the tendon is under a 5% strain.
|
| 327 |
+
|
| 328 |
+
Examples
|
| 329 |
+
========
|
| 330 |
+
|
| 331 |
+
The preferred way to instantiate :class:`TendonForceLengthInverseDeGroote2016` is
|
| 332 |
+
using the :meth:`~.with_defaults` constructor because this will automatically
|
| 333 |
+
populate the constants within the characteristic curve equation with the
|
| 334 |
+
floating point values from the original publication. This constructor takes
|
| 335 |
+
a single argument corresponding to normalized tendon force-length, which is
|
| 336 |
+
equal to the tendon force. We'll create a :class:`~.Symbol` called ``fl_T`` to
|
| 337 |
+
represent this.
|
| 338 |
+
|
| 339 |
+
>>> from sympy import Symbol
|
| 340 |
+
>>> from sympy.physics.biomechanics import TendonForceLengthInverseDeGroote2016
|
| 341 |
+
>>> fl_T = Symbol('fl_T')
|
| 342 |
+
>>> l_T_tilde = TendonForceLengthInverseDeGroote2016.with_defaults(fl_T)
|
| 343 |
+
>>> l_T_tilde
|
| 344 |
+
TendonForceLengthInverseDeGroote2016(fl_T, 0.2, 0.995, 0.25,
|
| 345 |
+
33.93669377311689)
|
| 346 |
+
|
| 347 |
+
It's also possible to populate the four constants with your own values too.
|
| 348 |
+
|
| 349 |
+
>>> from sympy import symbols
|
| 350 |
+
>>> c0, c1, c2, c3 = symbols('c0 c1 c2 c3')
|
| 351 |
+
>>> l_T_tilde = TendonForceLengthInverseDeGroote2016(fl_T, c0, c1, c2, c3)
|
| 352 |
+
>>> l_T_tilde
|
| 353 |
+
TendonForceLengthInverseDeGroote2016(fl_T, c0, c1, c2, c3)
|
| 354 |
+
|
| 355 |
+
To inspect the actual symbolic expression that this function represents,
|
| 356 |
+
we can call the :meth:`~.doit` method on an instance. We'll use the keyword
|
| 357 |
+
argument ``evaluate=False`` as this will keep the expression in its
|
| 358 |
+
canonical form and won't simplify any constants.
|
| 359 |
+
|
| 360 |
+
>>> l_T_tilde.doit(evaluate=False)
|
| 361 |
+
c1 + log((c2 + fl_T)/c0)/c3
|
| 362 |
+
|
| 363 |
+
The function can also be differentiated. We'll differentiate with respect
|
| 364 |
+
to l_T using the ``diff`` method on an instance with the single positional
|
| 365 |
+
argument ``l_T``.
|
| 366 |
+
|
| 367 |
+
>>> l_T_tilde.diff(fl_T)
|
| 368 |
+
1/(c3*(c2 + fl_T))
|
| 369 |
+
|
| 370 |
+
References
|
| 371 |
+
==========
|
| 372 |
+
|
| 373 |
+
.. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation
|
| 374 |
+
of direct collocation optimal control problem formulations for
|
| 375 |
+
solving the muscle redundancy problem, Annals of biomedical
|
| 376 |
+
engineering, 44(10), (2016) pp. 2922-2936
|
| 377 |
+
|
| 378 |
+
"""
|
| 379 |
+
|
| 380 |
+
@classmethod
|
| 381 |
+
def with_defaults(cls, fl_T):
|
| 382 |
+
r"""Recommended constructor that will use the published constants.
|
| 383 |
+
|
| 384 |
+
Explanation
|
| 385 |
+
===========
|
| 386 |
+
|
| 387 |
+
Returns a new instance of the inverse tendon force-length function
|
| 388 |
+
using the four constant values specified in the original publication.
|
| 389 |
+
|
| 390 |
+
These have the values:
|
| 391 |
+
|
| 392 |
+
$c_0 = 0.2$
|
| 393 |
+
$c_1 = 0.995$
|
| 394 |
+
$c_2 = 0.25$
|
| 395 |
+
$c_3 = 33.93669377311689$
|
| 396 |
+
|
| 397 |
+
Parameters
|
| 398 |
+
==========
|
| 399 |
+
|
| 400 |
+
fl_T : Any (sympifiable)
|
| 401 |
+
Normalized tendon force as a function of tendon length.
|
| 402 |
+
|
| 403 |
+
"""
|
| 404 |
+
c0 = Float('0.2')
|
| 405 |
+
c1 = Float('0.995')
|
| 406 |
+
c2 = Float('0.25')
|
| 407 |
+
c3 = Float('33.93669377311689')
|
| 408 |
+
return cls(fl_T, c0, c1, c2, c3)
|
| 409 |
+
|
| 410 |
+
@classmethod
|
| 411 |
+
def eval(cls, fl_T, c0, c1, c2, c3):
|
| 412 |
+
"""Evaluation of basic inputs.
|
| 413 |
+
|
| 414 |
+
Parameters
|
| 415 |
+
==========
|
| 416 |
+
|
| 417 |
+
fl_T : Any (sympifiable)
|
| 418 |
+
Normalized tendon force as a function of tendon length.
|
| 419 |
+
c0 : Any (sympifiable)
|
| 420 |
+
The first constant in the characteristic equation. The published
|
| 421 |
+
value is ``0.2``.
|
| 422 |
+
c1 : Any (sympifiable)
|
| 423 |
+
The second constant in the characteristic equation. The published
|
| 424 |
+
value is ``0.995``.
|
| 425 |
+
c2 : Any (sympifiable)
|
| 426 |
+
The third constant in the characteristic equation. The published
|
| 427 |
+
value is ``0.25``.
|
| 428 |
+
c3 : Any (sympifiable)
|
| 429 |
+
The fourth constant in the characteristic equation. The published
|
| 430 |
+
value is ``33.93669377311689``.
|
| 431 |
+
|
| 432 |
+
"""
|
| 433 |
+
pass
|
| 434 |
+
|
| 435 |
+
def _eval_evalf(self, prec):
|
| 436 |
+
"""Evaluate the expression numerically using ``evalf``."""
|
| 437 |
+
return self.doit(deep=False, evaluate=False)._eval_evalf(prec)
|
| 438 |
+
|
| 439 |
+
def doit(self, deep=True, evaluate=True, **hints):
|
| 440 |
+
"""Evaluate the expression defining the function.
|
| 441 |
+
|
| 442 |
+
Parameters
|
| 443 |
+
==========
|
| 444 |
+
|
| 445 |
+
deep : bool
|
| 446 |
+
Whether ``doit`` should be recursively called. Default is ``True``.
|
| 447 |
+
evaluate : bool.
|
| 448 |
+
Whether the SymPy expression should be evaluated as it is
|
| 449 |
+
constructed. If ``False``, then no constant folding will be
|
| 450 |
+
conducted which will leave the expression in a more numerically-
|
| 451 |
+
stable for values of ``l_T_tilde`` that correspond to a sensible
|
| 452 |
+
operating range for a musculotendon. Default is ``True``.
|
| 453 |
+
**kwargs : dict[str, Any]
|
| 454 |
+
Additional keyword argument pairs to be recursively passed to
|
| 455 |
+
``doit``.
|
| 456 |
+
|
| 457 |
+
"""
|
| 458 |
+
fl_T, *constants = self.args
|
| 459 |
+
if deep:
|
| 460 |
+
hints['evaluate'] = evaluate
|
| 461 |
+
fl_T = fl_T.doit(deep=deep, **hints)
|
| 462 |
+
c0, c1, c2, c3 = [c.doit(deep=deep, **hints) for c in constants]
|
| 463 |
+
else:
|
| 464 |
+
c0, c1, c2, c3 = constants
|
| 465 |
+
|
| 466 |
+
if evaluate:
|
| 467 |
+
return log((fl_T + c2)/c0)/c3 + c1
|
| 468 |
+
|
| 469 |
+
return log(UnevaluatedExpr((fl_T + c2)/c0))/c3 + c1
|
| 470 |
+
|
| 471 |
+
def fdiff(self, argindex=1):
|
| 472 |
+
"""Derivative of the function with respect to a single argument.
|
| 473 |
+
|
| 474 |
+
Parameters
|
| 475 |
+
==========
|
| 476 |
+
|
| 477 |
+
argindex : int
|
| 478 |
+
The index of the function's arguments with respect to which the
|
| 479 |
+
derivative should be taken. Argument indexes start at ``1``.
|
| 480 |
+
Default is ``1``.
|
| 481 |
+
|
| 482 |
+
"""
|
| 483 |
+
fl_T, c0, c1, c2, c3 = self.args
|
| 484 |
+
if argindex == 1:
|
| 485 |
+
return 1/(c3*(fl_T + c2))
|
| 486 |
+
elif argindex == 2:
|
| 487 |
+
return -1/(c0*c3)
|
| 488 |
+
elif argindex == 3:
|
| 489 |
+
return Integer(1)
|
| 490 |
+
elif argindex == 4:
|
| 491 |
+
return 1/(c3*(fl_T + c2))
|
| 492 |
+
elif argindex == 5:
|
| 493 |
+
return -log(UnevaluatedExpr((fl_T + c2)/c0))/c3**2
|
| 494 |
+
|
| 495 |
+
raise ArgumentIndexError(self, argindex)
|
| 496 |
+
|
| 497 |
+
def inverse(self, argindex=1):
|
| 498 |
+
"""Inverse function.
|
| 499 |
+
|
| 500 |
+
Parameters
|
| 501 |
+
==========
|
| 502 |
+
|
| 503 |
+
argindex : int
|
| 504 |
+
Value to start indexing the arguments at. Default is ``1``.
|
| 505 |
+
|
| 506 |
+
"""
|
| 507 |
+
return TendonForceLengthDeGroote2016
|
| 508 |
+
|
| 509 |
+
def _latex(self, printer):
|
| 510 |
+
"""Print a LaTeX representation of the function defining the curve.
|
| 511 |
+
|
| 512 |
+
Parameters
|
| 513 |
+
==========
|
| 514 |
+
|
| 515 |
+
printer : Printer
|
| 516 |
+
The printer to be used to print the LaTeX string representation.
|
| 517 |
+
|
| 518 |
+
"""
|
| 519 |
+
fl_T = self.args[0]
|
| 520 |
+
_fl_T = printer._print(fl_T)
|
| 521 |
+
return r'\left( \operatorname{fl}^T \right)^{-1} \left( %s \right)' % _fl_T
|
| 522 |
+
|
| 523 |
+
|
| 524 |
+
class FiberForceLengthPassiveDeGroote2016(CharacteristicCurveFunction):
|
| 525 |
+
r"""Passive muscle fiber force-length curve based on De Groote et al., 2016
|
| 526 |
+
[1]_.
|
| 527 |
+
|
| 528 |
+
Explanation
|
| 529 |
+
===========
|
| 530 |
+
|
| 531 |
+
The function is defined by the equation:
|
| 532 |
+
|
| 533 |
+
$fl^M_{pas} = \frac{\frac{\exp{c_1 \left(\tilde{l^M} - 1\right)}}{c_0} - 1}{\exp{c_1} - 1}$
|
| 534 |
+
|
| 535 |
+
with constant values of $c_0 = 0.6$ and $c_1 = 4.0$.
|
| 536 |
+
|
| 537 |
+
While it is possible to change the constant values, these were carefully
|
| 538 |
+
selected in the original publication to give the characteristic curve
|
| 539 |
+
specific and required properties. For example, the function produces a
|
| 540 |
+
passive fiber force very close to 0 for all normalized fiber lengths
|
| 541 |
+
between 0 and 1.
|
| 542 |
+
|
| 543 |
+
Examples
|
| 544 |
+
========
|
| 545 |
+
|
| 546 |
+
The preferred way to instantiate :class:`FiberForceLengthPassiveDeGroote2016` is
|
| 547 |
+
using the :meth:`~.with_defaults` constructor because this will automatically
|
| 548 |
+
populate the constants within the characteristic curve equation with the
|
| 549 |
+
floating point values from the original publication. This constructor takes
|
| 550 |
+
a single argument corresponding to normalized muscle fiber length. We'll
|
| 551 |
+
create a :class:`~.Symbol` called ``l_M_tilde`` to represent this.
|
| 552 |
+
|
| 553 |
+
>>> from sympy import Symbol
|
| 554 |
+
>>> from sympy.physics.biomechanics import FiberForceLengthPassiveDeGroote2016
|
| 555 |
+
>>> l_M_tilde = Symbol('l_M_tilde')
|
| 556 |
+
>>> fl_M = FiberForceLengthPassiveDeGroote2016.with_defaults(l_M_tilde)
|
| 557 |
+
>>> fl_M
|
| 558 |
+
FiberForceLengthPassiveDeGroote2016(l_M_tilde, 0.6, 4.0)
|
| 559 |
+
|
| 560 |
+
It's also possible to populate the two constants with your own values too.
|
| 561 |
+
|
| 562 |
+
>>> from sympy import symbols
|
| 563 |
+
>>> c0, c1 = symbols('c0 c1')
|
| 564 |
+
>>> fl_M = FiberForceLengthPassiveDeGroote2016(l_M_tilde, c0, c1)
|
| 565 |
+
>>> fl_M
|
| 566 |
+
FiberForceLengthPassiveDeGroote2016(l_M_tilde, c0, c1)
|
| 567 |
+
|
| 568 |
+
You don't just have to use symbols as the arguments, it's also possible to
|
| 569 |
+
use expressions. Let's create a new pair of symbols, ``l_M`` and
|
| 570 |
+
``l_M_opt``, representing muscle fiber length and optimal muscle fiber
|
| 571 |
+
length respectively. We can then represent ``l_M_tilde`` as an expression,
|
| 572 |
+
the ratio of these.
|
| 573 |
+
|
| 574 |
+
>>> l_M, l_M_opt = symbols('l_M l_M_opt')
|
| 575 |
+
>>> l_M_tilde = l_M/l_M_opt
|
| 576 |
+
>>> fl_M = FiberForceLengthPassiveDeGroote2016.with_defaults(l_M_tilde)
|
| 577 |
+
>>> fl_M
|
| 578 |
+
FiberForceLengthPassiveDeGroote2016(l_M/l_M_opt, 0.6, 4.0)
|
| 579 |
+
|
| 580 |
+
To inspect the actual symbolic expression that this function represents,
|
| 581 |
+
we can call the :meth:`~.doit` method on an instance. We'll use the keyword
|
| 582 |
+
argument ``evaluate=False`` as this will keep the expression in its
|
| 583 |
+
canonical form and won't simplify any constants.
|
| 584 |
+
|
| 585 |
+
>>> fl_M.doit(evaluate=False)
|
| 586 |
+
0.0186573603637741*(-1 + exp(6.66666666666667*(l_M/l_M_opt - 1)))
|
| 587 |
+
|
| 588 |
+
The function can also be differentiated. We'll differentiate with respect
|
| 589 |
+
to l_M using the ``diff`` method on an instance with the single positional
|
| 590 |
+
argument ``l_M``.
|
| 591 |
+
|
| 592 |
+
>>> fl_M.diff(l_M)
|
| 593 |
+
0.12438240242516*exp(6.66666666666667*(l_M/l_M_opt - 1))/l_M_opt
|
| 594 |
+
|
| 595 |
+
References
|
| 596 |
+
==========
|
| 597 |
+
|
| 598 |
+
.. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation
|
| 599 |
+
of direct collocation optimal control problem formulations for
|
| 600 |
+
solving the muscle redundancy problem, Annals of biomedical
|
| 601 |
+
engineering, 44(10), (2016) pp. 2922-2936
|
| 602 |
+
|
| 603 |
+
"""
|
| 604 |
+
|
| 605 |
+
@classmethod
|
| 606 |
+
def with_defaults(cls, l_M_tilde):
|
| 607 |
+
r"""Recommended constructor that will use the published constants.
|
| 608 |
+
|
| 609 |
+
Explanation
|
| 610 |
+
===========
|
| 611 |
+
|
| 612 |
+
Returns a new instance of the muscle fiber passive force-length
|
| 613 |
+
function using the four constant values specified in the original
|
| 614 |
+
publication.
|
| 615 |
+
|
| 616 |
+
These have the values:
|
| 617 |
+
|
| 618 |
+
$c_0 = 0.6$
|
| 619 |
+
$c_1 = 4.0$
|
| 620 |
+
|
| 621 |
+
Parameters
|
| 622 |
+
==========
|
| 623 |
+
|
| 624 |
+
l_M_tilde : Any (sympifiable)
|
| 625 |
+
Normalized muscle fiber length.
|
| 626 |
+
|
| 627 |
+
"""
|
| 628 |
+
c0 = Float('0.6')
|
| 629 |
+
c1 = Float('4.0')
|
| 630 |
+
return cls(l_M_tilde, c0, c1)
|
| 631 |
+
|
| 632 |
+
@classmethod
|
| 633 |
+
def eval(cls, l_M_tilde, c0, c1):
|
| 634 |
+
"""Evaluation of basic inputs.
|
| 635 |
+
|
| 636 |
+
Parameters
|
| 637 |
+
==========
|
| 638 |
+
|
| 639 |
+
l_M_tilde : Any (sympifiable)
|
| 640 |
+
Normalized muscle fiber length.
|
| 641 |
+
c0 : Any (sympifiable)
|
| 642 |
+
The first constant in the characteristic equation. The published
|
| 643 |
+
value is ``0.6``.
|
| 644 |
+
c1 : Any (sympifiable)
|
| 645 |
+
The second constant in the characteristic equation. The published
|
| 646 |
+
value is ``4.0``.
|
| 647 |
+
|
| 648 |
+
"""
|
| 649 |
+
pass
|
| 650 |
+
|
| 651 |
+
def _eval_evalf(self, prec):
|
| 652 |
+
"""Evaluate the expression numerically using ``evalf``."""
|
| 653 |
+
return self.doit(deep=False, evaluate=False)._eval_evalf(prec)
|
| 654 |
+
|
| 655 |
+
def doit(self, deep=True, evaluate=True, **hints):
|
| 656 |
+
"""Evaluate the expression defining the function.
|
| 657 |
+
|
| 658 |
+
Parameters
|
| 659 |
+
==========
|
| 660 |
+
|
| 661 |
+
deep : bool
|
| 662 |
+
Whether ``doit`` should be recursively called. Default is ``True``.
|
| 663 |
+
evaluate : bool.
|
| 664 |
+
Whether the SymPy expression should be evaluated as it is
|
| 665 |
+
constructed. If ``False``, then no constant folding will be
|
| 666 |
+
conducted which will leave the expression in a more numerically-
|
| 667 |
+
stable for values of ``l_T_tilde`` that correspond to a sensible
|
| 668 |
+
operating range for a musculotendon. Default is ``True``.
|
| 669 |
+
**kwargs : dict[str, Any]
|
| 670 |
+
Additional keyword argument pairs to be recursively passed to
|
| 671 |
+
``doit``.
|
| 672 |
+
|
| 673 |
+
"""
|
| 674 |
+
l_M_tilde, *constants = self.args
|
| 675 |
+
if deep:
|
| 676 |
+
hints['evaluate'] = evaluate
|
| 677 |
+
l_M_tilde = l_M_tilde.doit(deep=deep, **hints)
|
| 678 |
+
c0, c1 = [c.doit(deep=deep, **hints) for c in constants]
|
| 679 |
+
else:
|
| 680 |
+
c0, c1 = constants
|
| 681 |
+
|
| 682 |
+
if evaluate:
|
| 683 |
+
return (exp((c1*(l_M_tilde - 1))/c0) - 1)/(exp(c1) - 1)
|
| 684 |
+
|
| 685 |
+
return (exp((c1*UnevaluatedExpr(l_M_tilde - 1))/c0) - 1)/(exp(c1) - 1)
|
| 686 |
+
|
| 687 |
+
def fdiff(self, argindex=1):
|
| 688 |
+
"""Derivative of the function with respect to a single argument.
|
| 689 |
+
|
| 690 |
+
Parameters
|
| 691 |
+
==========
|
| 692 |
+
|
| 693 |
+
argindex : int
|
| 694 |
+
The index of the function's arguments with respect to which the
|
| 695 |
+
derivative should be taken. Argument indexes start at ``1``.
|
| 696 |
+
Default is ``1``.
|
| 697 |
+
|
| 698 |
+
"""
|
| 699 |
+
l_M_tilde, c0, c1 = self.args
|
| 700 |
+
if argindex == 1:
|
| 701 |
+
return c1*exp(c1*UnevaluatedExpr(l_M_tilde - 1)/c0)/(c0*(exp(c1) - 1))
|
| 702 |
+
elif argindex == 2:
|
| 703 |
+
return (
|
| 704 |
+
-c1*exp(c1*UnevaluatedExpr(l_M_tilde - 1)/c0)
|
| 705 |
+
*UnevaluatedExpr(l_M_tilde - 1)/(c0**2*(exp(c1) - 1))
|
| 706 |
+
)
|
| 707 |
+
elif argindex == 3:
|
| 708 |
+
return (
|
| 709 |
+
-exp(c1)*(-1 + exp(c1*UnevaluatedExpr(l_M_tilde - 1)/c0))/(exp(c1) - 1)**2
|
| 710 |
+
+ exp(c1*UnevaluatedExpr(l_M_tilde - 1)/c0)*(l_M_tilde - 1)/(c0*(exp(c1) - 1))
|
| 711 |
+
)
|
| 712 |
+
|
| 713 |
+
raise ArgumentIndexError(self, argindex)
|
| 714 |
+
|
| 715 |
+
def inverse(self, argindex=1):
|
| 716 |
+
"""Inverse function.
|
| 717 |
+
|
| 718 |
+
Parameters
|
| 719 |
+
==========
|
| 720 |
+
|
| 721 |
+
argindex : int
|
| 722 |
+
Value to start indexing the arguments at. Default is ``1``.
|
| 723 |
+
|
| 724 |
+
"""
|
| 725 |
+
return FiberForceLengthPassiveInverseDeGroote2016
|
| 726 |
+
|
| 727 |
+
def _latex(self, printer):
|
| 728 |
+
"""Print a LaTeX representation of the function defining the curve.
|
| 729 |
+
|
| 730 |
+
Parameters
|
| 731 |
+
==========
|
| 732 |
+
|
| 733 |
+
printer : Printer
|
| 734 |
+
The printer to be used to print the LaTeX string representation.
|
| 735 |
+
|
| 736 |
+
"""
|
| 737 |
+
l_M_tilde = self.args[0]
|
| 738 |
+
_l_M_tilde = printer._print(l_M_tilde)
|
| 739 |
+
return r'\operatorname{fl}^M_{pas} \left( %s \right)' % _l_M_tilde
|
| 740 |
+
|
| 741 |
+
|
| 742 |
+
class FiberForceLengthPassiveInverseDeGroote2016(CharacteristicCurveFunction):
|
| 743 |
+
r"""Inverse passive muscle fiber force-length curve based on De Groote et
|
| 744 |
+
al., 2016 [1]_.
|
| 745 |
+
|
| 746 |
+
Explanation
|
| 747 |
+
===========
|
| 748 |
+
|
| 749 |
+
Gives the normalized muscle fiber length that produces a specific normalized
|
| 750 |
+
passive muscle fiber force.
|
| 751 |
+
|
| 752 |
+
The function is defined by the equation:
|
| 753 |
+
|
| 754 |
+
${fl^M_{pas}}^{-1} = \frac{c_0 \log{\left(\exp{c_1} - 1\right)fl^M_pas + 1}}{c_1} + 1$
|
| 755 |
+
|
| 756 |
+
with constant values of $c_0 = 0.6$ and $c_1 = 4.0$. This function is the
|
| 757 |
+
exact analytical inverse of the related tendon force-length curve
|
| 758 |
+
``FiberForceLengthPassiveDeGroote2016``.
|
| 759 |
+
|
| 760 |
+
While it is possible to change the constant values, these were carefully
|
| 761 |
+
selected in the original publication to give the characteristic curve
|
| 762 |
+
specific and required properties. For example, the function produces a
|
| 763 |
+
passive fiber force very close to 0 for all normalized fiber lengths
|
| 764 |
+
between 0 and 1.
|
| 765 |
+
|
| 766 |
+
Examples
|
| 767 |
+
========
|
| 768 |
+
|
| 769 |
+
The preferred way to instantiate
|
| 770 |
+
:class:`FiberForceLengthPassiveInverseDeGroote2016` is using the
|
| 771 |
+
:meth:`~.with_defaults` constructor because this will automatically populate the
|
| 772 |
+
constants within the characteristic curve equation with the floating point
|
| 773 |
+
values from the original publication. This constructor takes a single
|
| 774 |
+
argument corresponding to the normalized passive muscle fiber length-force
|
| 775 |
+
component of the muscle fiber force. We'll create a :class:`~.Symbol` called
|
| 776 |
+
``fl_M_pas`` to represent this.
|
| 777 |
+
|
| 778 |
+
>>> from sympy import Symbol
|
| 779 |
+
>>> from sympy.physics.biomechanics import FiberForceLengthPassiveInverseDeGroote2016
|
| 780 |
+
>>> fl_M_pas = Symbol('fl_M_pas')
|
| 781 |
+
>>> l_M_tilde = FiberForceLengthPassiveInverseDeGroote2016.with_defaults(fl_M_pas)
|
| 782 |
+
>>> l_M_tilde
|
| 783 |
+
FiberForceLengthPassiveInverseDeGroote2016(fl_M_pas, 0.6, 4.0)
|
| 784 |
+
|
| 785 |
+
It's also possible to populate the two constants with your own values too.
|
| 786 |
+
|
| 787 |
+
>>> from sympy import symbols
|
| 788 |
+
>>> c0, c1 = symbols('c0 c1')
|
| 789 |
+
>>> l_M_tilde = FiberForceLengthPassiveInverseDeGroote2016(fl_M_pas, c0, c1)
|
| 790 |
+
>>> l_M_tilde
|
| 791 |
+
FiberForceLengthPassiveInverseDeGroote2016(fl_M_pas, c0, c1)
|
| 792 |
+
|
| 793 |
+
To inspect the actual symbolic expression that this function represents,
|
| 794 |
+
we can call the :meth:`~.doit` method on an instance. We'll use the keyword
|
| 795 |
+
argument ``evaluate=False`` as this will keep the expression in its
|
| 796 |
+
canonical form and won't simplify any constants.
|
| 797 |
+
|
| 798 |
+
>>> l_M_tilde.doit(evaluate=False)
|
| 799 |
+
c0*log(1 + fl_M_pas*(exp(c1) - 1))/c1 + 1
|
| 800 |
+
|
| 801 |
+
The function can also be differentiated. We'll differentiate with respect
|
| 802 |
+
to fl_M_pas using the ``diff`` method on an instance with the single positional
|
| 803 |
+
argument ``fl_M_pas``.
|
| 804 |
+
|
| 805 |
+
>>> l_M_tilde.diff(fl_M_pas)
|
| 806 |
+
c0*(exp(c1) - 1)/(c1*(fl_M_pas*(exp(c1) - 1) + 1))
|
| 807 |
+
|
| 808 |
+
References
|
| 809 |
+
==========
|
| 810 |
+
|
| 811 |
+
.. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation
|
| 812 |
+
of direct collocation optimal control problem formulations for
|
| 813 |
+
solving the muscle redundancy problem, Annals of biomedical
|
| 814 |
+
engineering, 44(10), (2016) pp. 2922-2936
|
| 815 |
+
|
| 816 |
+
"""
|
| 817 |
+
|
| 818 |
+
@classmethod
|
| 819 |
+
def with_defaults(cls, fl_M_pas):
|
| 820 |
+
r"""Recommended constructor that will use the published constants.
|
| 821 |
+
|
| 822 |
+
Explanation
|
| 823 |
+
===========
|
| 824 |
+
|
| 825 |
+
Returns a new instance of the inverse muscle fiber passive force-length
|
| 826 |
+
function using the four constant values specified in the original
|
| 827 |
+
publication.
|
| 828 |
+
|
| 829 |
+
These have the values:
|
| 830 |
+
|
| 831 |
+
$c_0 = 0.6$
|
| 832 |
+
$c_1 = 4.0$
|
| 833 |
+
|
| 834 |
+
Parameters
|
| 835 |
+
==========
|
| 836 |
+
|
| 837 |
+
fl_M_pas : Any (sympifiable)
|
| 838 |
+
Normalized passive muscle fiber force as a function of muscle fiber
|
| 839 |
+
length.
|
| 840 |
+
|
| 841 |
+
"""
|
| 842 |
+
c0 = Float('0.6')
|
| 843 |
+
c1 = Float('4.0')
|
| 844 |
+
return cls(fl_M_pas, c0, c1)
|
| 845 |
+
|
| 846 |
+
@classmethod
|
| 847 |
+
def eval(cls, fl_M_pas, c0, c1):
|
| 848 |
+
"""Evaluation of basic inputs.
|
| 849 |
+
|
| 850 |
+
Parameters
|
| 851 |
+
==========
|
| 852 |
+
|
| 853 |
+
fl_M_pas : Any (sympifiable)
|
| 854 |
+
Normalized passive muscle fiber force.
|
| 855 |
+
c0 : Any (sympifiable)
|
| 856 |
+
The first constant in the characteristic equation. The published
|
| 857 |
+
value is ``0.6``.
|
| 858 |
+
c1 : Any (sympifiable)
|
| 859 |
+
The second constant in the characteristic equation. The published
|
| 860 |
+
value is ``4.0``.
|
| 861 |
+
|
| 862 |
+
"""
|
| 863 |
+
pass
|
| 864 |
+
|
| 865 |
+
def _eval_evalf(self, prec):
|
| 866 |
+
"""Evaluate the expression numerically using ``evalf``."""
|
| 867 |
+
return self.doit(deep=False, evaluate=False)._eval_evalf(prec)
|
| 868 |
+
|
| 869 |
+
def doit(self, deep=True, evaluate=True, **hints):
|
| 870 |
+
"""Evaluate the expression defining the function.
|
| 871 |
+
|
| 872 |
+
Parameters
|
| 873 |
+
==========
|
| 874 |
+
|
| 875 |
+
deep : bool
|
| 876 |
+
Whether ``doit`` should be recursively called. Default is ``True``.
|
| 877 |
+
evaluate : bool.
|
| 878 |
+
Whether the SymPy expression should be evaluated as it is
|
| 879 |
+
constructed. If ``False``, then no constant folding will be
|
| 880 |
+
conducted which will leave the expression in a more numerically-
|
| 881 |
+
stable for values of ``l_T_tilde`` that correspond to a sensible
|
| 882 |
+
operating range for a musculotendon. Default is ``True``.
|
| 883 |
+
**kwargs : dict[str, Any]
|
| 884 |
+
Additional keyword argument pairs to be recursively passed to
|
| 885 |
+
``doit``.
|
| 886 |
+
|
| 887 |
+
"""
|
| 888 |
+
fl_M_pas, *constants = self.args
|
| 889 |
+
if deep:
|
| 890 |
+
hints['evaluate'] = evaluate
|
| 891 |
+
fl_M_pas = fl_M_pas.doit(deep=deep, **hints)
|
| 892 |
+
c0, c1 = [c.doit(deep=deep, **hints) for c in constants]
|
| 893 |
+
else:
|
| 894 |
+
c0, c1 = constants
|
| 895 |
+
|
| 896 |
+
if evaluate:
|
| 897 |
+
return c0*log(fl_M_pas*(exp(c1) - 1) + 1)/c1 + 1
|
| 898 |
+
|
| 899 |
+
return c0*log(UnevaluatedExpr(fl_M_pas*(exp(c1) - 1)) + 1)/c1 + 1
|
| 900 |
+
|
| 901 |
+
def fdiff(self, argindex=1):
|
| 902 |
+
"""Derivative of the function with respect to a single argument.
|
| 903 |
+
|
| 904 |
+
Parameters
|
| 905 |
+
==========
|
| 906 |
+
|
| 907 |
+
argindex : int
|
| 908 |
+
The index of the function's arguments with respect to which the
|
| 909 |
+
derivative should be taken. Argument indexes start at ``1``.
|
| 910 |
+
Default is ``1``.
|
| 911 |
+
|
| 912 |
+
"""
|
| 913 |
+
fl_M_pas, c0, c1 = self.args
|
| 914 |
+
if argindex == 1:
|
| 915 |
+
return c0*(exp(c1) - 1)/(c1*(fl_M_pas*(exp(c1) - 1) + 1))
|
| 916 |
+
elif argindex == 2:
|
| 917 |
+
return log(fl_M_pas*(exp(c1) - 1) + 1)/c1
|
| 918 |
+
elif argindex == 3:
|
| 919 |
+
return (
|
| 920 |
+
c0*fl_M_pas*exp(c1)/(c1*(fl_M_pas*(exp(c1) - 1) + 1))
|
| 921 |
+
- c0*log(fl_M_pas*(exp(c1) - 1) + 1)/c1**2
|
| 922 |
+
)
|
| 923 |
+
|
| 924 |
+
raise ArgumentIndexError(self, argindex)
|
| 925 |
+
|
| 926 |
+
def inverse(self, argindex=1):
|
| 927 |
+
"""Inverse function.
|
| 928 |
+
|
| 929 |
+
Parameters
|
| 930 |
+
==========
|
| 931 |
+
|
| 932 |
+
argindex : int
|
| 933 |
+
Value to start indexing the arguments at. Default is ``1``.
|
| 934 |
+
|
| 935 |
+
"""
|
| 936 |
+
return FiberForceLengthPassiveDeGroote2016
|
| 937 |
+
|
| 938 |
+
def _latex(self, printer):
|
| 939 |
+
"""Print a LaTeX representation of the function defining the curve.
|
| 940 |
+
|
| 941 |
+
Parameters
|
| 942 |
+
==========
|
| 943 |
+
|
| 944 |
+
printer : Printer
|
| 945 |
+
The printer to be used to print the LaTeX string representation.
|
| 946 |
+
|
| 947 |
+
"""
|
| 948 |
+
fl_M_pas = self.args[0]
|
| 949 |
+
_fl_M_pas = printer._print(fl_M_pas)
|
| 950 |
+
return r'\left( \operatorname{fl}^M_{pas} \right)^{-1} \left( %s \right)' % _fl_M_pas
|
| 951 |
+
|
| 952 |
+
|
| 953 |
+
class FiberForceLengthActiveDeGroote2016(CharacteristicCurveFunction):
|
| 954 |
+
r"""Active muscle fiber force-length curve based on De Groote et al., 2016
|
| 955 |
+
[1]_.
|
| 956 |
+
|
| 957 |
+
Explanation
|
| 958 |
+
===========
|
| 959 |
+
|
| 960 |
+
The function is defined by the equation:
|
| 961 |
+
|
| 962 |
+
$fl_{\text{act}}^M = c_0 \exp\left(-\frac{1}{2}\left(\frac{\tilde{l}^M - c_1}{c_2 + c_3 \tilde{l}^M}\right)^2\right)
|
| 963 |
+
+ c_4 \exp\left(-\frac{1}{2}\left(\frac{\tilde{l}^M - c_5}{c_6 + c_7 \tilde{l}^M}\right)^2\right)
|
| 964 |
+
+ c_8 \exp\left(-\frac{1}{2}\left(\frac{\tilde{l}^M - c_9}{c_{10} + c_{11} \tilde{l}^M}\right)^2\right)$
|
| 965 |
+
|
| 966 |
+
with constant values of $c0 = 0.814$, $c1 = 1.06$, $c2 = 0.162$,
|
| 967 |
+
$c3 = 0.0633$, $c4 = 0.433$, $c5 = 0.717$, $c6 = -0.0299$, $c7 = 0.2$,
|
| 968 |
+
$c8 = 0.1$, $c9 = 1.0$, $c10 = 0.354$, and $c11 = 0.0$.
|
| 969 |
+
|
| 970 |
+
While it is possible to change the constant values, these were carefully
|
| 971 |
+
selected in the original publication to give the characteristic curve
|
| 972 |
+
specific and required properties. For example, the function produces a
|
| 973 |
+
active fiber force of 1 at a normalized fiber length of 1, and an active
|
| 974 |
+
fiber force of 0 at normalized fiber lengths of 0 and 2.
|
| 975 |
+
|
| 976 |
+
Examples
|
| 977 |
+
========
|
| 978 |
+
|
| 979 |
+
The preferred way to instantiate :class:`FiberForceLengthActiveDeGroote2016` is
|
| 980 |
+
using the :meth:`~.with_defaults` constructor because this will automatically
|
| 981 |
+
populate the constants within the characteristic curve equation with the
|
| 982 |
+
floating point values from the original publication. This constructor takes
|
| 983 |
+
a single argument corresponding to normalized muscle fiber length. We'll
|
| 984 |
+
create a :class:`~.Symbol` called ``l_M_tilde`` to represent this.
|
| 985 |
+
|
| 986 |
+
>>> from sympy import Symbol
|
| 987 |
+
>>> from sympy.physics.biomechanics import FiberForceLengthActiveDeGroote2016
|
| 988 |
+
>>> l_M_tilde = Symbol('l_M_tilde')
|
| 989 |
+
>>> fl_M = FiberForceLengthActiveDeGroote2016.with_defaults(l_M_tilde)
|
| 990 |
+
>>> fl_M
|
| 991 |
+
FiberForceLengthActiveDeGroote2016(l_M_tilde, 0.814, 1.06, 0.162, 0.0633,
|
| 992 |
+
0.433, 0.717, -0.0299, 0.2, 0.1, 1.0, 0.354, 0.0)
|
| 993 |
+
|
| 994 |
+
It's also possible to populate the two constants with your own values too.
|
| 995 |
+
|
| 996 |
+
>>> from sympy import symbols
|
| 997 |
+
>>> c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11 = symbols('c0:12')
|
| 998 |
+
>>> fl_M = FiberForceLengthActiveDeGroote2016(l_M_tilde, c0, c1, c2, c3,
|
| 999 |
+
... c4, c5, c6, c7, c8, c9, c10, c11)
|
| 1000 |
+
>>> fl_M
|
| 1001 |
+
FiberForceLengthActiveDeGroote2016(l_M_tilde, c0, c1, c2, c3, c4, c5, c6,
|
| 1002 |
+
c7, c8, c9, c10, c11)
|
| 1003 |
+
|
| 1004 |
+
You don't just have to use symbols as the arguments, it's also possible to
|
| 1005 |
+
use expressions. Let's create a new pair of symbols, ``l_M`` and
|
| 1006 |
+
``l_M_opt``, representing muscle fiber length and optimal muscle fiber
|
| 1007 |
+
length respectively. We can then represent ``l_M_tilde`` as an expression,
|
| 1008 |
+
the ratio of these.
|
| 1009 |
+
|
| 1010 |
+
>>> l_M, l_M_opt = symbols('l_M l_M_opt')
|
| 1011 |
+
>>> l_M_tilde = l_M/l_M_opt
|
| 1012 |
+
>>> fl_M = FiberForceLengthActiveDeGroote2016.with_defaults(l_M_tilde)
|
| 1013 |
+
>>> fl_M
|
| 1014 |
+
FiberForceLengthActiveDeGroote2016(l_M/l_M_opt, 0.814, 1.06, 0.162, 0.0633,
|
| 1015 |
+
0.433, 0.717, -0.0299, 0.2, 0.1, 1.0, 0.354, 0.0)
|
| 1016 |
+
|
| 1017 |
+
To inspect the actual symbolic expression that this function represents,
|
| 1018 |
+
we can call the :meth:`~.doit` method on an instance. We'll use the keyword
|
| 1019 |
+
argument ``evaluate=False`` as this will keep the expression in its
|
| 1020 |
+
canonical form and won't simplify any constants.
|
| 1021 |
+
|
| 1022 |
+
>>> fl_M.doit(evaluate=False)
|
| 1023 |
+
0.814*exp(-19.0519737844841*(l_M/l_M_opt
|
| 1024 |
+
- 1.06)**2/(0.390740740740741*l_M/l_M_opt + 1)**2)
|
| 1025 |
+
+ 0.433*exp(-12.5*(l_M/l_M_opt - 0.717)**2/(l_M/l_M_opt - 0.1495)**2)
|
| 1026 |
+
+ 0.1*exp(-3.98991349867535*(l_M/l_M_opt - 1.0)**2)
|
| 1027 |
+
|
| 1028 |
+
The function can also be differentiated. We'll differentiate with respect
|
| 1029 |
+
to l_M using the ``diff`` method on an instance with the single positional
|
| 1030 |
+
argument ``l_M``.
|
| 1031 |
+
|
| 1032 |
+
>>> fl_M.diff(l_M)
|
| 1033 |
+
((-0.79798269973507*l_M/l_M_opt
|
| 1034 |
+
+ 0.79798269973507)*exp(-3.98991349867535*(l_M/l_M_opt - 1.0)**2)
|
| 1035 |
+
+ (10.825*(-l_M/l_M_opt + 0.717)/(l_M/l_M_opt - 0.1495)**2
|
| 1036 |
+
+ 10.825*(l_M/l_M_opt - 0.717)**2/(l_M/l_M_opt
|
| 1037 |
+
- 0.1495)**3)*exp(-12.5*(l_M/l_M_opt - 0.717)**2/(l_M/l_M_opt - 0.1495)**2)
|
| 1038 |
+
+ (31.0166133211401*(-l_M/l_M_opt + 1.06)/(0.390740740740741*l_M/l_M_opt
|
| 1039 |
+
+ 1)**2 + 13.6174190361677*(0.943396226415094*l_M/l_M_opt
|
| 1040 |
+
- 1)**2/(0.390740740740741*l_M/l_M_opt
|
| 1041 |
+
+ 1)**3)*exp(-21.4067977442463*(0.943396226415094*l_M/l_M_opt
|
| 1042 |
+
- 1)**2/(0.390740740740741*l_M/l_M_opt + 1)**2))/l_M_opt
|
| 1043 |
+
|
| 1044 |
+
References
|
| 1045 |
+
==========
|
| 1046 |
+
|
| 1047 |
+
.. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation
|
| 1048 |
+
of direct collocation optimal control problem formulations for
|
| 1049 |
+
solving the muscle redundancy problem, Annals of biomedical
|
| 1050 |
+
engineering, 44(10), (2016) pp. 2922-2936
|
| 1051 |
+
|
| 1052 |
+
"""
|
| 1053 |
+
|
| 1054 |
+
@classmethod
|
| 1055 |
+
def with_defaults(cls, l_M_tilde):
|
| 1056 |
+
r"""Recommended constructor that will use the published constants.
|
| 1057 |
+
|
| 1058 |
+
Explanation
|
| 1059 |
+
===========
|
| 1060 |
+
|
| 1061 |
+
Returns a new instance of the inverse muscle fiber act force-length
|
| 1062 |
+
function using the four constant values specified in the original
|
| 1063 |
+
publication.
|
| 1064 |
+
|
| 1065 |
+
These have the values:
|
| 1066 |
+
|
| 1067 |
+
$c0 = 0.814$
|
| 1068 |
+
$c1 = 1.06$
|
| 1069 |
+
$c2 = 0.162$
|
| 1070 |
+
$c3 = 0.0633$
|
| 1071 |
+
$c4 = 0.433$
|
| 1072 |
+
$c5 = 0.717$
|
| 1073 |
+
$c6 = -0.0299$
|
| 1074 |
+
$c7 = 0.2$
|
| 1075 |
+
$c8 = 0.1$
|
| 1076 |
+
$c9 = 1.0$
|
| 1077 |
+
$c10 = 0.354$
|
| 1078 |
+
$c11 = 0.0$
|
| 1079 |
+
|
| 1080 |
+
Parameters
|
| 1081 |
+
==========
|
| 1082 |
+
|
| 1083 |
+
fl_M_act : Any (sympifiable)
|
| 1084 |
+
Normalized passive muscle fiber force as a function of muscle fiber
|
| 1085 |
+
length.
|
| 1086 |
+
|
| 1087 |
+
"""
|
| 1088 |
+
c0 = Float('0.814')
|
| 1089 |
+
c1 = Float('1.06')
|
| 1090 |
+
c2 = Float('0.162')
|
| 1091 |
+
c3 = Float('0.0633')
|
| 1092 |
+
c4 = Float('0.433')
|
| 1093 |
+
c5 = Float('0.717')
|
| 1094 |
+
c6 = Float('-0.0299')
|
| 1095 |
+
c7 = Float('0.2')
|
| 1096 |
+
c8 = Float('0.1')
|
| 1097 |
+
c9 = Float('1.0')
|
| 1098 |
+
c10 = Float('0.354')
|
| 1099 |
+
c11 = Float('0.0')
|
| 1100 |
+
return cls(l_M_tilde, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11)
|
| 1101 |
+
|
| 1102 |
+
@classmethod
|
| 1103 |
+
def eval(cls, l_M_tilde, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11):
|
| 1104 |
+
"""Evaluation of basic inputs.
|
| 1105 |
+
|
| 1106 |
+
Parameters
|
| 1107 |
+
==========
|
| 1108 |
+
|
| 1109 |
+
l_M_tilde : Any (sympifiable)
|
| 1110 |
+
Normalized muscle fiber length.
|
| 1111 |
+
c0 : Any (sympifiable)
|
| 1112 |
+
The first constant in the characteristic equation. The published
|
| 1113 |
+
value is ``0.814``.
|
| 1114 |
+
c1 : Any (sympifiable)
|
| 1115 |
+
The second constant in the characteristic equation. The published
|
| 1116 |
+
value is ``1.06``.
|
| 1117 |
+
c2 : Any (sympifiable)
|
| 1118 |
+
The third constant in the characteristic equation. The published
|
| 1119 |
+
value is ``0.162``.
|
| 1120 |
+
c3 : Any (sympifiable)
|
| 1121 |
+
The fourth constant in the characteristic equation. The published
|
| 1122 |
+
value is ``0.0633``.
|
| 1123 |
+
c4 : Any (sympifiable)
|
| 1124 |
+
The fifth constant in the characteristic equation. The published
|
| 1125 |
+
value is ``0.433``.
|
| 1126 |
+
c5 : Any (sympifiable)
|
| 1127 |
+
The sixth constant in the characteristic equation. The published
|
| 1128 |
+
value is ``0.717``.
|
| 1129 |
+
c6 : Any (sympifiable)
|
| 1130 |
+
The seventh constant in the characteristic equation. The published
|
| 1131 |
+
value is ``-0.0299``.
|
| 1132 |
+
c7 : Any (sympifiable)
|
| 1133 |
+
The eighth constant in the characteristic equation. The published
|
| 1134 |
+
value is ``0.2``.
|
| 1135 |
+
c8 : Any (sympifiable)
|
| 1136 |
+
The ninth constant in the characteristic equation. The published
|
| 1137 |
+
value is ``0.1``.
|
| 1138 |
+
c9 : Any (sympifiable)
|
| 1139 |
+
The tenth constant in the characteristic equation. The published
|
| 1140 |
+
value is ``1.0``.
|
| 1141 |
+
c10 : Any (sympifiable)
|
| 1142 |
+
The eleventh constant in the characteristic equation. The published
|
| 1143 |
+
value is ``0.354``.
|
| 1144 |
+
c11 : Any (sympifiable)
|
| 1145 |
+
The tweflth constant in the characteristic equation. The published
|
| 1146 |
+
value is ``0.0``.
|
| 1147 |
+
|
| 1148 |
+
"""
|
| 1149 |
+
pass
|
| 1150 |
+
|
| 1151 |
+
def _eval_evalf(self, prec):
|
| 1152 |
+
"""Evaluate the expression numerically using ``evalf``."""
|
| 1153 |
+
return self.doit(deep=False, evaluate=False)._eval_evalf(prec)
|
| 1154 |
+
|
| 1155 |
+
def doit(self, deep=True, evaluate=True, **hints):
|
| 1156 |
+
"""Evaluate the expression defining the function.
|
| 1157 |
+
|
| 1158 |
+
Parameters
|
| 1159 |
+
==========
|
| 1160 |
+
|
| 1161 |
+
deep : bool
|
| 1162 |
+
Whether ``doit`` should be recursively called. Default is ``True``.
|
| 1163 |
+
evaluate : bool.
|
| 1164 |
+
Whether the SymPy expression should be evaluated as it is
|
| 1165 |
+
constructed. If ``False``, then no constant folding will be
|
| 1166 |
+
conducted which will leave the expression in a more numerically-
|
| 1167 |
+
stable for values of ``l_M_tilde`` that correspond to a sensible
|
| 1168 |
+
operating range for a musculotendon. Default is ``True``.
|
| 1169 |
+
**kwargs : dict[str, Any]
|
| 1170 |
+
Additional keyword argument pairs to be recursively passed to
|
| 1171 |
+
``doit``.
|
| 1172 |
+
|
| 1173 |
+
"""
|
| 1174 |
+
l_M_tilde, *constants = self.args
|
| 1175 |
+
if deep:
|
| 1176 |
+
hints['evaluate'] = evaluate
|
| 1177 |
+
l_M_tilde = l_M_tilde.doit(deep=deep, **hints)
|
| 1178 |
+
constants = [c.doit(deep=deep, **hints) for c in constants]
|
| 1179 |
+
c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11 = constants
|
| 1180 |
+
|
| 1181 |
+
if evaluate:
|
| 1182 |
+
return (
|
| 1183 |
+
c0*exp(-(((l_M_tilde - c1)/(c2 + c3*l_M_tilde))**2)/2)
|
| 1184 |
+
+ c4*exp(-(((l_M_tilde - c5)/(c6 + c7*l_M_tilde))**2)/2)
|
| 1185 |
+
+ c8*exp(-(((l_M_tilde - c9)/(c10 + c11*l_M_tilde))**2)/2)
|
| 1186 |
+
)
|
| 1187 |
+
|
| 1188 |
+
return (
|
| 1189 |
+
c0*exp(-((UnevaluatedExpr(l_M_tilde - c1)/(c2 + c3*l_M_tilde))**2)/2)
|
| 1190 |
+
+ c4*exp(-((UnevaluatedExpr(l_M_tilde - c5)/(c6 + c7*l_M_tilde))**2)/2)
|
| 1191 |
+
+ c8*exp(-((UnevaluatedExpr(l_M_tilde - c9)/(c10 + c11*l_M_tilde))**2)/2)
|
| 1192 |
+
)
|
| 1193 |
+
|
| 1194 |
+
def fdiff(self, argindex=1):
|
| 1195 |
+
"""Derivative of the function with respect to a single argument.
|
| 1196 |
+
|
| 1197 |
+
Parameters
|
| 1198 |
+
==========
|
| 1199 |
+
|
| 1200 |
+
argindex : int
|
| 1201 |
+
The index of the function's arguments with respect to which the
|
| 1202 |
+
derivative should be taken. Argument indexes start at ``1``.
|
| 1203 |
+
Default is ``1``.
|
| 1204 |
+
|
| 1205 |
+
"""
|
| 1206 |
+
l_M_tilde, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11 = self.args
|
| 1207 |
+
if argindex == 1:
|
| 1208 |
+
return (
|
| 1209 |
+
c0*(
|
| 1210 |
+
c3*(l_M_tilde - c1)**2/(c2 + c3*l_M_tilde)**3
|
| 1211 |
+
+ (c1 - l_M_tilde)/((c2 + c3*l_M_tilde)**2)
|
| 1212 |
+
)*exp(-(l_M_tilde - c1)**2/(2*(c2 + c3*l_M_tilde)**2))
|
| 1213 |
+
+ c4*(
|
| 1214 |
+
c7*(l_M_tilde - c5)**2/(c6 + c7*l_M_tilde)**3
|
| 1215 |
+
+ (c5 - l_M_tilde)/((c6 + c7*l_M_tilde)**2)
|
| 1216 |
+
)*exp(-(l_M_tilde - c5)**2/(2*(c6 + c7*l_M_tilde)**2))
|
| 1217 |
+
+ c8*(
|
| 1218 |
+
c11*(l_M_tilde - c9)**2/(c10 + c11*l_M_tilde)**3
|
| 1219 |
+
+ (c9 - l_M_tilde)/((c10 + c11*l_M_tilde)**2)
|
| 1220 |
+
)*exp(-(l_M_tilde - c9)**2/(2*(c10 + c11*l_M_tilde)**2))
|
| 1221 |
+
)
|
| 1222 |
+
elif argindex == 2:
|
| 1223 |
+
return exp(-(l_M_tilde - c1)**2/(2*(c2 + c3*l_M_tilde)**2))
|
| 1224 |
+
elif argindex == 3:
|
| 1225 |
+
return (
|
| 1226 |
+
c0*(l_M_tilde - c1)/(c2 + c3*l_M_tilde)**2
|
| 1227 |
+
*exp(-(l_M_tilde - c1)**2 /(2*(c2 + c3*l_M_tilde)**2))
|
| 1228 |
+
)
|
| 1229 |
+
elif argindex == 4:
|
| 1230 |
+
return (
|
| 1231 |
+
c0*(l_M_tilde - c1)**2/(c2 + c3*l_M_tilde)**3
|
| 1232 |
+
*exp(-(l_M_tilde - c1)**2/(2*(c2 + c3*l_M_tilde)**2))
|
| 1233 |
+
)
|
| 1234 |
+
elif argindex == 5:
|
| 1235 |
+
return (
|
| 1236 |
+
c0*l_M_tilde*(l_M_tilde - c1)**2/(c2 + c3*l_M_tilde)**3
|
| 1237 |
+
*exp(-(l_M_tilde - c1)**2/(2*(c2 + c3*l_M_tilde)**2))
|
| 1238 |
+
)
|
| 1239 |
+
elif argindex == 6:
|
| 1240 |
+
return exp(-(l_M_tilde - c5)**2/(2*(c6 + c7*l_M_tilde)**2))
|
| 1241 |
+
elif argindex == 7:
|
| 1242 |
+
return (
|
| 1243 |
+
c4*(l_M_tilde - c5)/(c6 + c7*l_M_tilde)**2
|
| 1244 |
+
*exp(-(l_M_tilde - c5)**2 /(2*(c6 + c7*l_M_tilde)**2))
|
| 1245 |
+
)
|
| 1246 |
+
elif argindex == 8:
|
| 1247 |
+
return (
|
| 1248 |
+
c4*(l_M_tilde - c5)**2/(c6 + c7*l_M_tilde)**3
|
| 1249 |
+
*exp(-(l_M_tilde - c5)**2/(2*(c6 + c7*l_M_tilde)**2))
|
| 1250 |
+
)
|
| 1251 |
+
elif argindex == 9:
|
| 1252 |
+
return (
|
| 1253 |
+
c4*l_M_tilde*(l_M_tilde - c5)**2/(c6 + c7*l_M_tilde)**3
|
| 1254 |
+
*exp(-(l_M_tilde - c5)**2/(2*(c6 + c7*l_M_tilde)**2))
|
| 1255 |
+
)
|
| 1256 |
+
elif argindex == 10:
|
| 1257 |
+
return exp(-(l_M_tilde - c9)**2/(2*(c10 + c11*l_M_tilde)**2))
|
| 1258 |
+
elif argindex == 11:
|
| 1259 |
+
return (
|
| 1260 |
+
c8*(l_M_tilde - c9)/(c10 + c11*l_M_tilde)**2
|
| 1261 |
+
*exp(-(l_M_tilde - c9)**2 /(2*(c10 + c11*l_M_tilde)**2))
|
| 1262 |
+
)
|
| 1263 |
+
elif argindex == 12:
|
| 1264 |
+
return (
|
| 1265 |
+
c8*(l_M_tilde - c9)**2/(c10 + c11*l_M_tilde)**3
|
| 1266 |
+
*exp(-(l_M_tilde - c9)**2/(2*(c10 + c11*l_M_tilde)**2))
|
| 1267 |
+
)
|
| 1268 |
+
elif argindex == 13:
|
| 1269 |
+
return (
|
| 1270 |
+
c8*l_M_tilde*(l_M_tilde - c9)**2/(c10 + c11*l_M_tilde)**3
|
| 1271 |
+
*exp(-(l_M_tilde - c9)**2/(2*(c10 + c11*l_M_tilde)**2))
|
| 1272 |
+
)
|
| 1273 |
+
|
| 1274 |
+
raise ArgumentIndexError(self, argindex)
|
| 1275 |
+
|
| 1276 |
+
def _latex(self, printer):
|
| 1277 |
+
"""Print a LaTeX representation of the function defining the curve.
|
| 1278 |
+
|
| 1279 |
+
Parameters
|
| 1280 |
+
==========
|
| 1281 |
+
|
| 1282 |
+
printer : Printer
|
| 1283 |
+
The printer to be used to print the LaTeX string representation.
|
| 1284 |
+
|
| 1285 |
+
"""
|
| 1286 |
+
l_M_tilde = self.args[0]
|
| 1287 |
+
_l_M_tilde = printer._print(l_M_tilde)
|
| 1288 |
+
return r'\operatorname{fl}^M_{act} \left( %s \right)' % _l_M_tilde
|
| 1289 |
+
|
| 1290 |
+
|
| 1291 |
+
class FiberForceVelocityDeGroote2016(CharacteristicCurveFunction):
|
| 1292 |
+
r"""Muscle fiber force-velocity curve based on De Groote et al., 2016 [1]_.
|
| 1293 |
+
|
| 1294 |
+
Explanation
|
| 1295 |
+
===========
|
| 1296 |
+
|
| 1297 |
+
Gives the normalized muscle fiber force produced as a function of
|
| 1298 |
+
normalized tendon velocity.
|
| 1299 |
+
|
| 1300 |
+
The function is defined by the equation:
|
| 1301 |
+
|
| 1302 |
+
$fv^M = c_0 \log{\left(c_1 \tilde{v}_m + c_2\right) + \sqrt{\left(c_1 \tilde{v}_m + c_2\right)^2 + 1}} + c_3$
|
| 1303 |
+
|
| 1304 |
+
with constant values of $c_0 = -0.318$, $c_1 = -8.149$, $c_2 = -0.374$, and
|
| 1305 |
+
$c_3 = 0.886$.
|
| 1306 |
+
|
| 1307 |
+
While it is possible to change the constant values, these were carefully
|
| 1308 |
+
selected in the original publication to give the characteristic curve
|
| 1309 |
+
specific and required properties. For example, the function produces a
|
| 1310 |
+
normalized muscle fiber force of 1 when the muscle fibers are contracting
|
| 1311 |
+
isometrically (they have an extension rate of 0).
|
| 1312 |
+
|
| 1313 |
+
Examples
|
| 1314 |
+
========
|
| 1315 |
+
|
| 1316 |
+
The preferred way to instantiate :class:`FiberForceVelocityDeGroote2016` is using
|
| 1317 |
+
the :meth:`~.with_defaults` constructor because this will automatically populate
|
| 1318 |
+
the constants within the characteristic curve equation with the floating
|
| 1319 |
+
point values from the original publication. This constructor takes a single
|
| 1320 |
+
argument corresponding to normalized muscle fiber extension velocity. We'll
|
| 1321 |
+
create a :class:`~.Symbol` called ``v_M_tilde`` to represent this.
|
| 1322 |
+
|
| 1323 |
+
>>> from sympy import Symbol
|
| 1324 |
+
>>> from sympy.physics.biomechanics import FiberForceVelocityDeGroote2016
|
| 1325 |
+
>>> v_M_tilde = Symbol('v_M_tilde')
|
| 1326 |
+
>>> fv_M = FiberForceVelocityDeGroote2016.with_defaults(v_M_tilde)
|
| 1327 |
+
>>> fv_M
|
| 1328 |
+
FiberForceVelocityDeGroote2016(v_M_tilde, -0.318, -8.149, -0.374, 0.886)
|
| 1329 |
+
|
| 1330 |
+
It's also possible to populate the four constants with your own values too.
|
| 1331 |
+
|
| 1332 |
+
>>> from sympy import symbols
|
| 1333 |
+
>>> c0, c1, c2, c3 = symbols('c0 c1 c2 c3')
|
| 1334 |
+
>>> fv_M = FiberForceVelocityDeGroote2016(v_M_tilde, c0, c1, c2, c3)
|
| 1335 |
+
>>> fv_M
|
| 1336 |
+
FiberForceVelocityDeGroote2016(v_M_tilde, c0, c1, c2, c3)
|
| 1337 |
+
|
| 1338 |
+
You don't just have to use symbols as the arguments, it's also possible to
|
| 1339 |
+
use expressions. Let's create a new pair of symbols, ``v_M`` and
|
| 1340 |
+
``v_M_max``, representing muscle fiber extension velocity and maximum
|
| 1341 |
+
muscle fiber extension velocity respectively. We can then represent
|
| 1342 |
+
``v_M_tilde`` as an expression, the ratio of these.
|
| 1343 |
+
|
| 1344 |
+
>>> v_M, v_M_max = symbols('v_M v_M_max')
|
| 1345 |
+
>>> v_M_tilde = v_M/v_M_max
|
| 1346 |
+
>>> fv_M = FiberForceVelocityDeGroote2016.with_defaults(v_M_tilde)
|
| 1347 |
+
>>> fv_M
|
| 1348 |
+
FiberForceVelocityDeGroote2016(v_M/v_M_max, -0.318, -8.149, -0.374, 0.886)
|
| 1349 |
+
|
| 1350 |
+
To inspect the actual symbolic expression that this function represents,
|
| 1351 |
+
we can call the :meth:`~.doit` method on an instance. We'll use the keyword
|
| 1352 |
+
argument ``evaluate=False`` as this will keep the expression in its
|
| 1353 |
+
canonical form and won't simplify any constants.
|
| 1354 |
+
|
| 1355 |
+
>>> fv_M.doit(evaluate=False)
|
| 1356 |
+
0.886 - 0.318*log(-8.149*v_M/v_M_max - 0.374 + sqrt(1 + (-8.149*v_M/v_M_max
|
| 1357 |
+
- 0.374)**2))
|
| 1358 |
+
|
| 1359 |
+
The function can also be differentiated. We'll differentiate with respect
|
| 1360 |
+
to v_M using the ``diff`` method on an instance with the single positional
|
| 1361 |
+
argument ``v_M``.
|
| 1362 |
+
|
| 1363 |
+
>>> fv_M.diff(v_M)
|
| 1364 |
+
2.591382*(1 + (-8.149*v_M/v_M_max - 0.374)**2)**(-1/2)/v_M_max
|
| 1365 |
+
|
| 1366 |
+
References
|
| 1367 |
+
==========
|
| 1368 |
+
|
| 1369 |
+
.. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation
|
| 1370 |
+
of direct collocation optimal control problem formulations for
|
| 1371 |
+
solving the muscle redundancy problem, Annals of biomedical
|
| 1372 |
+
engineering, 44(10), (2016) pp. 2922-2936
|
| 1373 |
+
|
| 1374 |
+
"""
|
| 1375 |
+
|
| 1376 |
+
@classmethod
|
| 1377 |
+
def with_defaults(cls, v_M_tilde):
|
| 1378 |
+
r"""Recommended constructor that will use the published constants.
|
| 1379 |
+
|
| 1380 |
+
Explanation
|
| 1381 |
+
===========
|
| 1382 |
+
|
| 1383 |
+
Returns a new instance of the muscle fiber force-velocity function
|
| 1384 |
+
using the four constant values specified in the original publication.
|
| 1385 |
+
|
| 1386 |
+
These have the values:
|
| 1387 |
+
|
| 1388 |
+
$c_0 = -0.318$
|
| 1389 |
+
$c_1 = -8.149$
|
| 1390 |
+
$c_2 = -0.374$
|
| 1391 |
+
$c_3 = 0.886$
|
| 1392 |
+
|
| 1393 |
+
Parameters
|
| 1394 |
+
==========
|
| 1395 |
+
|
| 1396 |
+
v_M_tilde : Any (sympifiable)
|
| 1397 |
+
Normalized muscle fiber extension velocity.
|
| 1398 |
+
|
| 1399 |
+
"""
|
| 1400 |
+
c0 = Float('-0.318')
|
| 1401 |
+
c1 = Float('-8.149')
|
| 1402 |
+
c2 = Float('-0.374')
|
| 1403 |
+
c3 = Float('0.886')
|
| 1404 |
+
return cls(v_M_tilde, c0, c1, c2, c3)
|
| 1405 |
+
|
| 1406 |
+
@classmethod
|
| 1407 |
+
def eval(cls, v_M_tilde, c0, c1, c2, c3):
|
| 1408 |
+
"""Evaluation of basic inputs.
|
| 1409 |
+
|
| 1410 |
+
Parameters
|
| 1411 |
+
==========
|
| 1412 |
+
|
| 1413 |
+
v_M_tilde : Any (sympifiable)
|
| 1414 |
+
Normalized muscle fiber extension velocity.
|
| 1415 |
+
c0 : Any (sympifiable)
|
| 1416 |
+
The first constant in the characteristic equation. The published
|
| 1417 |
+
value is ``-0.318``.
|
| 1418 |
+
c1 : Any (sympifiable)
|
| 1419 |
+
The second constant in the characteristic equation. The published
|
| 1420 |
+
value is ``-8.149``.
|
| 1421 |
+
c2 : Any (sympifiable)
|
| 1422 |
+
The third constant in the characteristic equation. The published
|
| 1423 |
+
value is ``-0.374``.
|
| 1424 |
+
c3 : Any (sympifiable)
|
| 1425 |
+
The fourth constant in the characteristic equation. The published
|
| 1426 |
+
value is ``0.886``.
|
| 1427 |
+
|
| 1428 |
+
"""
|
| 1429 |
+
pass
|
| 1430 |
+
|
| 1431 |
+
def _eval_evalf(self, prec):
|
| 1432 |
+
"""Evaluate the expression numerically using ``evalf``."""
|
| 1433 |
+
return self.doit(deep=False, evaluate=False)._eval_evalf(prec)
|
| 1434 |
+
|
| 1435 |
+
def doit(self, deep=True, evaluate=True, **hints):
|
| 1436 |
+
"""Evaluate the expression defining the function.
|
| 1437 |
+
|
| 1438 |
+
Parameters
|
| 1439 |
+
==========
|
| 1440 |
+
|
| 1441 |
+
deep : bool
|
| 1442 |
+
Whether ``doit`` should be recursively called. Default is ``True``.
|
| 1443 |
+
evaluate : bool.
|
| 1444 |
+
Whether the SymPy expression should be evaluated as it is
|
| 1445 |
+
constructed. If ``False``, then no constant folding will be
|
| 1446 |
+
conducted which will leave the expression in a more numerically-
|
| 1447 |
+
stable for values of ``v_M_tilde`` that correspond to a sensible
|
| 1448 |
+
operating range for a musculotendon. Default is ``True``.
|
| 1449 |
+
**kwargs : dict[str, Any]
|
| 1450 |
+
Additional keyword argument pairs to be recursively passed to
|
| 1451 |
+
``doit``.
|
| 1452 |
+
|
| 1453 |
+
"""
|
| 1454 |
+
v_M_tilde, *constants = self.args
|
| 1455 |
+
if deep:
|
| 1456 |
+
hints['evaluate'] = evaluate
|
| 1457 |
+
v_M_tilde = v_M_tilde.doit(deep=deep, **hints)
|
| 1458 |
+
c0, c1, c2, c3 = [c.doit(deep=deep, **hints) for c in constants]
|
| 1459 |
+
else:
|
| 1460 |
+
c0, c1, c2, c3 = constants
|
| 1461 |
+
|
| 1462 |
+
if evaluate:
|
| 1463 |
+
return c0*log(c1*v_M_tilde + c2 + sqrt((c1*v_M_tilde + c2)**2 + 1)) + c3
|
| 1464 |
+
|
| 1465 |
+
return c0*log(c1*v_M_tilde + c2 + sqrt(UnevaluatedExpr(c1*v_M_tilde + c2)**2 + 1)) + c3
|
| 1466 |
+
|
| 1467 |
+
def fdiff(self, argindex=1):
|
| 1468 |
+
"""Derivative of the function with respect to a single argument.
|
| 1469 |
+
|
| 1470 |
+
Parameters
|
| 1471 |
+
==========
|
| 1472 |
+
|
| 1473 |
+
argindex : int
|
| 1474 |
+
The index of the function's arguments with respect to which the
|
| 1475 |
+
derivative should be taken. Argument indexes start at ``1``.
|
| 1476 |
+
Default is ``1``.
|
| 1477 |
+
|
| 1478 |
+
"""
|
| 1479 |
+
v_M_tilde, c0, c1, c2, c3 = self.args
|
| 1480 |
+
if argindex == 1:
|
| 1481 |
+
return c0*c1/sqrt(UnevaluatedExpr(c1*v_M_tilde + c2)**2 + 1)
|
| 1482 |
+
elif argindex == 2:
|
| 1483 |
+
return log(
|
| 1484 |
+
c1*v_M_tilde + c2
|
| 1485 |
+
+ sqrt(UnevaluatedExpr(c1*v_M_tilde + c2)**2 + 1)
|
| 1486 |
+
)
|
| 1487 |
+
elif argindex == 3:
|
| 1488 |
+
return c0*v_M_tilde/sqrt(UnevaluatedExpr(c1*v_M_tilde + c2)**2 + 1)
|
| 1489 |
+
elif argindex == 4:
|
| 1490 |
+
return c0/sqrt(UnevaluatedExpr(c1*v_M_tilde + c2)**2 + 1)
|
| 1491 |
+
elif argindex == 5:
|
| 1492 |
+
return Integer(1)
|
| 1493 |
+
|
| 1494 |
+
raise ArgumentIndexError(self, argindex)
|
| 1495 |
+
|
| 1496 |
+
def inverse(self, argindex=1):
|
| 1497 |
+
"""Inverse function.
|
| 1498 |
+
|
| 1499 |
+
Parameters
|
| 1500 |
+
==========
|
| 1501 |
+
|
| 1502 |
+
argindex : int
|
| 1503 |
+
Value to start indexing the arguments at. Default is ``1``.
|
| 1504 |
+
|
| 1505 |
+
"""
|
| 1506 |
+
return FiberForceVelocityInverseDeGroote2016
|
| 1507 |
+
|
| 1508 |
+
def _latex(self, printer):
|
| 1509 |
+
"""Print a LaTeX representation of the function defining the curve.
|
| 1510 |
+
|
| 1511 |
+
Parameters
|
| 1512 |
+
==========
|
| 1513 |
+
|
| 1514 |
+
printer : Printer
|
| 1515 |
+
The printer to be used to print the LaTeX string representation.
|
| 1516 |
+
|
| 1517 |
+
"""
|
| 1518 |
+
v_M_tilde = self.args[0]
|
| 1519 |
+
_v_M_tilde = printer._print(v_M_tilde)
|
| 1520 |
+
return r'\operatorname{fv}^M \left( %s \right)' % _v_M_tilde
|
| 1521 |
+
|
| 1522 |
+
|
| 1523 |
+
class FiberForceVelocityInverseDeGroote2016(CharacteristicCurveFunction):
|
| 1524 |
+
r"""Inverse muscle fiber force-velocity curve based on De Groote et al.,
|
| 1525 |
+
2016 [1]_.
|
| 1526 |
+
|
| 1527 |
+
Explanation
|
| 1528 |
+
===========
|
| 1529 |
+
|
| 1530 |
+
Gives the normalized muscle fiber velocity that produces a specific
|
| 1531 |
+
normalized muscle fiber force.
|
| 1532 |
+
|
| 1533 |
+
The function is defined by the equation:
|
| 1534 |
+
|
| 1535 |
+
${fv^M}^{-1} = \frac{\sinh{\frac{fv^M - c_3}{c_0}} - c_2}{c_1}$
|
| 1536 |
+
|
| 1537 |
+
with constant values of $c_0 = -0.318$, $c_1 = -8.149$, $c_2 = -0.374$, and
|
| 1538 |
+
$c_3 = 0.886$. This function is the exact analytical inverse of the related
|
| 1539 |
+
muscle fiber force-velocity curve ``FiberForceVelocityDeGroote2016``.
|
| 1540 |
+
|
| 1541 |
+
While it is possible to change the constant values, these were carefully
|
| 1542 |
+
selected in the original publication to give the characteristic curve
|
| 1543 |
+
specific and required properties. For example, the function produces a
|
| 1544 |
+
normalized muscle fiber force of 1 when the muscle fibers are contracting
|
| 1545 |
+
isometrically (they have an extension rate of 0).
|
| 1546 |
+
|
| 1547 |
+
Examples
|
| 1548 |
+
========
|
| 1549 |
+
|
| 1550 |
+
The preferred way to instantiate :class:`FiberForceVelocityInverseDeGroote2016`
|
| 1551 |
+
is using the :meth:`~.with_defaults` constructor because this will automatically
|
| 1552 |
+
populate the constants within the characteristic curve equation with the
|
| 1553 |
+
floating point values from the original publication. This constructor takes
|
| 1554 |
+
a single argument corresponding to normalized muscle fiber force-velocity
|
| 1555 |
+
component of the muscle fiber force. We'll create a :class:`~.Symbol` called
|
| 1556 |
+
``fv_M`` to represent this.
|
| 1557 |
+
|
| 1558 |
+
>>> from sympy import Symbol
|
| 1559 |
+
>>> from sympy.physics.biomechanics import FiberForceVelocityInverseDeGroote2016
|
| 1560 |
+
>>> fv_M = Symbol('fv_M')
|
| 1561 |
+
>>> v_M_tilde = FiberForceVelocityInverseDeGroote2016.with_defaults(fv_M)
|
| 1562 |
+
>>> v_M_tilde
|
| 1563 |
+
FiberForceVelocityInverseDeGroote2016(fv_M, -0.318, -8.149, -0.374, 0.886)
|
| 1564 |
+
|
| 1565 |
+
It's also possible to populate the four constants with your own values too.
|
| 1566 |
+
|
| 1567 |
+
>>> from sympy import symbols
|
| 1568 |
+
>>> c0, c1, c2, c3 = symbols('c0 c1 c2 c3')
|
| 1569 |
+
>>> v_M_tilde = FiberForceVelocityInverseDeGroote2016(fv_M, c0, c1, c2, c3)
|
| 1570 |
+
>>> v_M_tilde
|
| 1571 |
+
FiberForceVelocityInverseDeGroote2016(fv_M, c0, c1, c2, c3)
|
| 1572 |
+
|
| 1573 |
+
To inspect the actual symbolic expression that this function represents,
|
| 1574 |
+
we can call the :meth:`~.doit` method on an instance. We'll use the keyword
|
| 1575 |
+
argument ``evaluate=False`` as this will keep the expression in its
|
| 1576 |
+
canonical form and won't simplify any constants.
|
| 1577 |
+
|
| 1578 |
+
>>> v_M_tilde.doit(evaluate=False)
|
| 1579 |
+
(-c2 + sinh((-c3 + fv_M)/c0))/c1
|
| 1580 |
+
|
| 1581 |
+
The function can also be differentiated. We'll differentiate with respect
|
| 1582 |
+
to fv_M using the ``diff`` method on an instance with the single positional
|
| 1583 |
+
argument ``fv_M``.
|
| 1584 |
+
|
| 1585 |
+
>>> v_M_tilde.diff(fv_M)
|
| 1586 |
+
cosh((-c3 + fv_M)/c0)/(c0*c1)
|
| 1587 |
+
|
| 1588 |
+
References
|
| 1589 |
+
==========
|
| 1590 |
+
|
| 1591 |
+
.. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation
|
| 1592 |
+
of direct collocation optimal control problem formulations for
|
| 1593 |
+
solving the muscle redundancy problem, Annals of biomedical
|
| 1594 |
+
engineering, 44(10), (2016) pp. 2922-2936
|
| 1595 |
+
|
| 1596 |
+
"""
|
| 1597 |
+
|
| 1598 |
+
@classmethod
|
| 1599 |
+
def with_defaults(cls, fv_M):
|
| 1600 |
+
r"""Recommended constructor that will use the published constants.
|
| 1601 |
+
|
| 1602 |
+
Explanation
|
| 1603 |
+
===========
|
| 1604 |
+
|
| 1605 |
+
Returns a new instance of the inverse muscle fiber force-velocity
|
| 1606 |
+
function using the four constant values specified in the original
|
| 1607 |
+
publication.
|
| 1608 |
+
|
| 1609 |
+
These have the values:
|
| 1610 |
+
|
| 1611 |
+
$c_0 = -0.318$
|
| 1612 |
+
$c_1 = -8.149$
|
| 1613 |
+
$c_2 = -0.374$
|
| 1614 |
+
$c_3 = 0.886$
|
| 1615 |
+
|
| 1616 |
+
Parameters
|
| 1617 |
+
==========
|
| 1618 |
+
|
| 1619 |
+
fv_M : Any (sympifiable)
|
| 1620 |
+
Normalized muscle fiber extension velocity.
|
| 1621 |
+
|
| 1622 |
+
"""
|
| 1623 |
+
c0 = Float('-0.318')
|
| 1624 |
+
c1 = Float('-8.149')
|
| 1625 |
+
c2 = Float('-0.374')
|
| 1626 |
+
c3 = Float('0.886')
|
| 1627 |
+
return cls(fv_M, c0, c1, c2, c3)
|
| 1628 |
+
|
| 1629 |
+
@classmethod
|
| 1630 |
+
def eval(cls, fv_M, c0, c1, c2, c3):
|
| 1631 |
+
"""Evaluation of basic inputs.
|
| 1632 |
+
|
| 1633 |
+
Parameters
|
| 1634 |
+
==========
|
| 1635 |
+
|
| 1636 |
+
fv_M : Any (sympifiable)
|
| 1637 |
+
Normalized muscle fiber force as a function of muscle fiber
|
| 1638 |
+
extension velocity.
|
| 1639 |
+
c0 : Any (sympifiable)
|
| 1640 |
+
The first constant in the characteristic equation. The published
|
| 1641 |
+
value is ``-0.318``.
|
| 1642 |
+
c1 : Any (sympifiable)
|
| 1643 |
+
The second constant in the characteristic equation. The published
|
| 1644 |
+
value is ``-8.149``.
|
| 1645 |
+
c2 : Any (sympifiable)
|
| 1646 |
+
The third constant in the characteristic equation. The published
|
| 1647 |
+
value is ``-0.374``.
|
| 1648 |
+
c3 : Any (sympifiable)
|
| 1649 |
+
The fourth constant in the characteristic equation. The published
|
| 1650 |
+
value is ``0.886``.
|
| 1651 |
+
|
| 1652 |
+
"""
|
| 1653 |
+
pass
|
| 1654 |
+
|
| 1655 |
+
def _eval_evalf(self, prec):
|
| 1656 |
+
"""Evaluate the expression numerically using ``evalf``."""
|
| 1657 |
+
return self.doit(deep=False, evaluate=False)._eval_evalf(prec)
|
| 1658 |
+
|
| 1659 |
+
def doit(self, deep=True, evaluate=True, **hints):
|
| 1660 |
+
"""Evaluate the expression defining the function.
|
| 1661 |
+
|
| 1662 |
+
Parameters
|
| 1663 |
+
==========
|
| 1664 |
+
|
| 1665 |
+
deep : bool
|
| 1666 |
+
Whether ``doit`` should be recursively called. Default is ``True``.
|
| 1667 |
+
evaluate : bool.
|
| 1668 |
+
Whether the SymPy expression should be evaluated as it is
|
| 1669 |
+
constructed. If ``False``, then no constant folding will be
|
| 1670 |
+
conducted which will leave the expression in a more numerically-
|
| 1671 |
+
stable for values of ``fv_M`` that correspond to a sensible
|
| 1672 |
+
operating range for a musculotendon. Default is ``True``.
|
| 1673 |
+
**kwargs : dict[str, Any]
|
| 1674 |
+
Additional keyword argument pairs to be recursively passed to
|
| 1675 |
+
``doit``.
|
| 1676 |
+
|
| 1677 |
+
"""
|
| 1678 |
+
fv_M, *constants = self.args
|
| 1679 |
+
if deep:
|
| 1680 |
+
hints['evaluate'] = evaluate
|
| 1681 |
+
fv_M = fv_M.doit(deep=deep, **hints)
|
| 1682 |
+
c0, c1, c2, c3 = [c.doit(deep=deep, **hints) for c in constants]
|
| 1683 |
+
else:
|
| 1684 |
+
c0, c1, c2, c3 = constants
|
| 1685 |
+
|
| 1686 |
+
if evaluate:
|
| 1687 |
+
return (sinh((fv_M - c3)/c0) - c2)/c1
|
| 1688 |
+
|
| 1689 |
+
return (sinh(UnevaluatedExpr(fv_M - c3)/c0) - c2)/c1
|
| 1690 |
+
|
| 1691 |
+
def fdiff(self, argindex=1):
|
| 1692 |
+
"""Derivative of the function with respect to a single argument.
|
| 1693 |
+
|
| 1694 |
+
Parameters
|
| 1695 |
+
==========
|
| 1696 |
+
|
| 1697 |
+
argindex : int
|
| 1698 |
+
The index of the function's arguments with respect to which the
|
| 1699 |
+
derivative should be taken. Argument indexes start at ``1``.
|
| 1700 |
+
Default is ``1``.
|
| 1701 |
+
|
| 1702 |
+
"""
|
| 1703 |
+
fv_M, c0, c1, c2, c3 = self.args
|
| 1704 |
+
if argindex == 1:
|
| 1705 |
+
return cosh((fv_M - c3)/c0)/(c0*c1)
|
| 1706 |
+
elif argindex == 2:
|
| 1707 |
+
return (c3 - fv_M)*cosh((fv_M - c3)/c0)/(c0**2*c1)
|
| 1708 |
+
elif argindex == 3:
|
| 1709 |
+
return (c2 - sinh((fv_M - c3)/c0))/c1**2
|
| 1710 |
+
elif argindex == 4:
|
| 1711 |
+
return -1/c1
|
| 1712 |
+
elif argindex == 5:
|
| 1713 |
+
return -cosh((fv_M - c3)/c0)/(c0*c1)
|
| 1714 |
+
|
| 1715 |
+
raise ArgumentIndexError(self, argindex)
|
| 1716 |
+
|
| 1717 |
+
def inverse(self, argindex=1):
|
| 1718 |
+
"""Inverse function.
|
| 1719 |
+
|
| 1720 |
+
Parameters
|
| 1721 |
+
==========
|
| 1722 |
+
|
| 1723 |
+
argindex : int
|
| 1724 |
+
Value to start indexing the arguments at. Default is ``1``.
|
| 1725 |
+
|
| 1726 |
+
"""
|
| 1727 |
+
return FiberForceVelocityDeGroote2016
|
| 1728 |
+
|
| 1729 |
+
def _latex(self, printer):
|
| 1730 |
+
"""Print a LaTeX representation of the function defining the curve.
|
| 1731 |
+
|
| 1732 |
+
Parameters
|
| 1733 |
+
==========
|
| 1734 |
+
|
| 1735 |
+
printer : Printer
|
| 1736 |
+
The printer to be used to print the LaTeX string representation.
|
| 1737 |
+
|
| 1738 |
+
"""
|
| 1739 |
+
fv_M = self.args[0]
|
| 1740 |
+
_fv_M = printer._print(fv_M)
|
| 1741 |
+
return r'\left( \operatorname{fv}^M \right)^{-1} \left( %s \right)' % _fv_M
|
| 1742 |
+
|
| 1743 |
+
|
| 1744 |
+
@dataclass(frozen=True)
|
| 1745 |
+
class CharacteristicCurveCollection:
|
| 1746 |
+
"""Simple data container to group together related characteristic curves."""
|
| 1747 |
+
tendon_force_length: CharacteristicCurveFunction
|
| 1748 |
+
tendon_force_length_inverse: CharacteristicCurveFunction
|
| 1749 |
+
fiber_force_length_passive: CharacteristicCurveFunction
|
| 1750 |
+
fiber_force_length_passive_inverse: CharacteristicCurveFunction
|
| 1751 |
+
fiber_force_length_active: CharacteristicCurveFunction
|
| 1752 |
+
fiber_force_velocity: CharacteristicCurveFunction
|
| 1753 |
+
fiber_force_velocity_inverse: CharacteristicCurveFunction
|
| 1754 |
+
|
| 1755 |
+
def __iter__(self):
|
| 1756 |
+
"""Iterator support for ``CharacteristicCurveCollection``."""
|
| 1757 |
+
yield self.tendon_force_length
|
| 1758 |
+
yield self.tendon_force_length_inverse
|
| 1759 |
+
yield self.fiber_force_length_passive
|
| 1760 |
+
yield self.fiber_force_length_passive_inverse
|
| 1761 |
+
yield self.fiber_force_length_active
|
| 1762 |
+
yield self.fiber_force_velocity
|
| 1763 |
+
yield self.fiber_force_velocity_inverse
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/tests/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (233 Bytes). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/tests/__pycache__/test_mixin.cpython-311.pyc
ADDED
|
Binary file (4.28 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/tests/test_activation.py
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Tests for the ``sympy.physics.biomechanics.activation.py`` module."""
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
|
| 5 |
+
from sympy import Symbol
|
| 6 |
+
from sympy.core.numbers import Float, Integer, Rational
|
| 7 |
+
from sympy.functions.elementary.hyperbolic import tanh
|
| 8 |
+
from sympy.matrices import Matrix
|
| 9 |
+
from sympy.matrices.dense import zeros
|
| 10 |
+
from sympy.physics.mechanics import dynamicsymbols
|
| 11 |
+
from sympy.physics.biomechanics import (
|
| 12 |
+
ActivationBase,
|
| 13 |
+
FirstOrderActivationDeGroote2016,
|
| 14 |
+
ZerothOrderActivation,
|
| 15 |
+
)
|
| 16 |
+
from sympy.physics.biomechanics._mixin import _NamedMixin
|
| 17 |
+
from sympy.simplify.simplify import simplify
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class TestZerothOrderActivation:
|
| 21 |
+
|
| 22 |
+
@staticmethod
|
| 23 |
+
def test_class():
|
| 24 |
+
assert issubclass(ZerothOrderActivation, ActivationBase)
|
| 25 |
+
assert issubclass(ZerothOrderActivation, _NamedMixin)
|
| 26 |
+
assert ZerothOrderActivation.__name__ == 'ZerothOrderActivation'
|
| 27 |
+
|
| 28 |
+
@pytest.fixture(autouse=True)
|
| 29 |
+
def _zeroth_order_activation_fixture(self):
|
| 30 |
+
self.name = 'name'
|
| 31 |
+
self.e = dynamicsymbols('e_name')
|
| 32 |
+
self.instance = ZerothOrderActivation(self.name)
|
| 33 |
+
|
| 34 |
+
def test_instance(self):
|
| 35 |
+
instance = ZerothOrderActivation(self.name)
|
| 36 |
+
assert isinstance(instance, ZerothOrderActivation)
|
| 37 |
+
|
| 38 |
+
def test_with_defaults(self):
|
| 39 |
+
instance = ZerothOrderActivation.with_defaults(self.name)
|
| 40 |
+
assert isinstance(instance, ZerothOrderActivation)
|
| 41 |
+
assert instance == ZerothOrderActivation(self.name)
|
| 42 |
+
|
| 43 |
+
def test_name(self):
|
| 44 |
+
assert hasattr(self.instance, 'name')
|
| 45 |
+
assert self.instance.name == self.name
|
| 46 |
+
|
| 47 |
+
def test_order(self):
|
| 48 |
+
assert hasattr(self.instance, 'order')
|
| 49 |
+
assert self.instance.order == 0
|
| 50 |
+
|
| 51 |
+
def test_excitation_attribute(self):
|
| 52 |
+
assert hasattr(self.instance, 'e')
|
| 53 |
+
assert hasattr(self.instance, 'excitation')
|
| 54 |
+
e_expected = dynamicsymbols('e_name')
|
| 55 |
+
assert self.instance.e == e_expected
|
| 56 |
+
assert self.instance.excitation == e_expected
|
| 57 |
+
assert self.instance.e is self.instance.excitation
|
| 58 |
+
|
| 59 |
+
def test_activation_attribute(self):
|
| 60 |
+
assert hasattr(self.instance, 'a')
|
| 61 |
+
assert hasattr(self.instance, 'activation')
|
| 62 |
+
a_expected = dynamicsymbols('e_name')
|
| 63 |
+
assert self.instance.a == a_expected
|
| 64 |
+
assert self.instance.activation == a_expected
|
| 65 |
+
assert self.instance.a is self.instance.activation is self.instance.e
|
| 66 |
+
|
| 67 |
+
def test_state_vars_attribute(self):
|
| 68 |
+
assert hasattr(self.instance, 'x')
|
| 69 |
+
assert hasattr(self.instance, 'state_vars')
|
| 70 |
+
assert self.instance.x == self.instance.state_vars
|
| 71 |
+
x_expected = zeros(0, 1)
|
| 72 |
+
assert self.instance.x == x_expected
|
| 73 |
+
assert self.instance.state_vars == x_expected
|
| 74 |
+
assert isinstance(self.instance.x, Matrix)
|
| 75 |
+
assert isinstance(self.instance.state_vars, Matrix)
|
| 76 |
+
assert self.instance.x.shape == (0, 1)
|
| 77 |
+
assert self.instance.state_vars.shape == (0, 1)
|
| 78 |
+
|
| 79 |
+
def test_input_vars_attribute(self):
|
| 80 |
+
assert hasattr(self.instance, 'r')
|
| 81 |
+
assert hasattr(self.instance, 'input_vars')
|
| 82 |
+
assert self.instance.r == self.instance.input_vars
|
| 83 |
+
r_expected = Matrix([self.e])
|
| 84 |
+
assert self.instance.r == r_expected
|
| 85 |
+
assert self.instance.input_vars == r_expected
|
| 86 |
+
assert isinstance(self.instance.r, Matrix)
|
| 87 |
+
assert isinstance(self.instance.input_vars, Matrix)
|
| 88 |
+
assert self.instance.r.shape == (1, 1)
|
| 89 |
+
assert self.instance.input_vars.shape == (1, 1)
|
| 90 |
+
|
| 91 |
+
def test_constants_attribute(self):
|
| 92 |
+
assert hasattr(self.instance, 'p')
|
| 93 |
+
assert hasattr(self.instance, 'constants')
|
| 94 |
+
assert self.instance.p == self.instance.constants
|
| 95 |
+
p_expected = zeros(0, 1)
|
| 96 |
+
assert self.instance.p == p_expected
|
| 97 |
+
assert self.instance.constants == p_expected
|
| 98 |
+
assert isinstance(self.instance.p, Matrix)
|
| 99 |
+
assert isinstance(self.instance.constants, Matrix)
|
| 100 |
+
assert self.instance.p.shape == (0, 1)
|
| 101 |
+
assert self.instance.constants.shape == (0, 1)
|
| 102 |
+
|
| 103 |
+
def test_M_attribute(self):
|
| 104 |
+
assert hasattr(self.instance, 'M')
|
| 105 |
+
M_expected = Matrix([])
|
| 106 |
+
assert self.instance.M == M_expected
|
| 107 |
+
assert isinstance(self.instance.M, Matrix)
|
| 108 |
+
assert self.instance.M.shape == (0, 0)
|
| 109 |
+
|
| 110 |
+
def test_F(self):
|
| 111 |
+
assert hasattr(self.instance, 'F')
|
| 112 |
+
F_expected = zeros(0, 1)
|
| 113 |
+
assert self.instance.F == F_expected
|
| 114 |
+
assert isinstance(self.instance.F, Matrix)
|
| 115 |
+
assert self.instance.F.shape == (0, 1)
|
| 116 |
+
|
| 117 |
+
def test_rhs(self):
|
| 118 |
+
assert hasattr(self.instance, 'rhs')
|
| 119 |
+
rhs_expected = zeros(0, 1)
|
| 120 |
+
rhs = self.instance.rhs()
|
| 121 |
+
assert rhs == rhs_expected
|
| 122 |
+
assert isinstance(rhs, Matrix)
|
| 123 |
+
assert rhs.shape == (0, 1)
|
| 124 |
+
|
| 125 |
+
def test_repr(self):
|
| 126 |
+
expected = 'ZerothOrderActivation(\'name\')'
|
| 127 |
+
assert repr(self.instance) == expected
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
class TestFirstOrderActivationDeGroote2016:
|
| 131 |
+
|
| 132 |
+
@staticmethod
|
| 133 |
+
def test_class():
|
| 134 |
+
assert issubclass(FirstOrderActivationDeGroote2016, ActivationBase)
|
| 135 |
+
assert issubclass(FirstOrderActivationDeGroote2016, _NamedMixin)
|
| 136 |
+
assert FirstOrderActivationDeGroote2016.__name__ == 'FirstOrderActivationDeGroote2016'
|
| 137 |
+
|
| 138 |
+
@pytest.fixture(autouse=True)
|
| 139 |
+
def _first_order_activation_de_groote_2016_fixture(self):
|
| 140 |
+
self.name = 'name'
|
| 141 |
+
self.e = dynamicsymbols('e_name')
|
| 142 |
+
self.a = dynamicsymbols('a_name')
|
| 143 |
+
self.tau_a = Symbol('tau_a')
|
| 144 |
+
self.tau_d = Symbol('tau_d')
|
| 145 |
+
self.b = Symbol('b')
|
| 146 |
+
self.instance = FirstOrderActivationDeGroote2016(
|
| 147 |
+
self.name,
|
| 148 |
+
self.tau_a,
|
| 149 |
+
self.tau_d,
|
| 150 |
+
self.b,
|
| 151 |
+
)
|
| 152 |
+
|
| 153 |
+
def test_instance(self):
|
| 154 |
+
instance = FirstOrderActivationDeGroote2016(self.name)
|
| 155 |
+
assert isinstance(instance, FirstOrderActivationDeGroote2016)
|
| 156 |
+
|
| 157 |
+
def test_with_defaults(self):
|
| 158 |
+
instance = FirstOrderActivationDeGroote2016.with_defaults(self.name)
|
| 159 |
+
assert isinstance(instance, FirstOrderActivationDeGroote2016)
|
| 160 |
+
assert instance.tau_a == Float('0.015')
|
| 161 |
+
assert instance.activation_time_constant == Float('0.015')
|
| 162 |
+
assert instance.tau_d == Float('0.060')
|
| 163 |
+
assert instance.deactivation_time_constant == Float('0.060')
|
| 164 |
+
assert instance.b == Float('10.0')
|
| 165 |
+
assert instance.smoothing_rate == Float('10.0')
|
| 166 |
+
|
| 167 |
+
def test_name(self):
|
| 168 |
+
assert hasattr(self.instance, 'name')
|
| 169 |
+
assert self.instance.name == self.name
|
| 170 |
+
|
| 171 |
+
def test_order(self):
|
| 172 |
+
assert hasattr(self.instance, 'order')
|
| 173 |
+
assert self.instance.order == 1
|
| 174 |
+
|
| 175 |
+
def test_excitation(self):
|
| 176 |
+
assert hasattr(self.instance, 'e')
|
| 177 |
+
assert hasattr(self.instance, 'excitation')
|
| 178 |
+
e_expected = dynamicsymbols('e_name')
|
| 179 |
+
assert self.instance.e == e_expected
|
| 180 |
+
assert self.instance.excitation == e_expected
|
| 181 |
+
assert self.instance.e is self.instance.excitation
|
| 182 |
+
|
| 183 |
+
def test_excitation_is_immutable(self):
|
| 184 |
+
with pytest.raises(AttributeError):
|
| 185 |
+
self.instance.e = None
|
| 186 |
+
with pytest.raises(AttributeError):
|
| 187 |
+
self.instance.excitation = None
|
| 188 |
+
|
| 189 |
+
def test_activation(self):
|
| 190 |
+
assert hasattr(self.instance, 'a')
|
| 191 |
+
assert hasattr(self.instance, 'activation')
|
| 192 |
+
a_expected = dynamicsymbols('a_name')
|
| 193 |
+
assert self.instance.a == a_expected
|
| 194 |
+
assert self.instance.activation == a_expected
|
| 195 |
+
|
| 196 |
+
def test_activation_is_immutable(self):
|
| 197 |
+
with pytest.raises(AttributeError):
|
| 198 |
+
self.instance.a = None
|
| 199 |
+
with pytest.raises(AttributeError):
|
| 200 |
+
self.instance.activation = None
|
| 201 |
+
|
| 202 |
+
@pytest.mark.parametrize(
|
| 203 |
+
'tau_a, expected',
|
| 204 |
+
[
|
| 205 |
+
(None, Symbol('tau_a_name')),
|
| 206 |
+
(Symbol('tau_a'), Symbol('tau_a')),
|
| 207 |
+
(Float('0.015'), Float('0.015')),
|
| 208 |
+
]
|
| 209 |
+
)
|
| 210 |
+
def test_activation_time_constant(self, tau_a, expected):
|
| 211 |
+
instance = FirstOrderActivationDeGroote2016(
|
| 212 |
+
'name', activation_time_constant=tau_a,
|
| 213 |
+
)
|
| 214 |
+
assert instance.tau_a == expected
|
| 215 |
+
assert instance.activation_time_constant == expected
|
| 216 |
+
assert instance.tau_a is instance.activation_time_constant
|
| 217 |
+
|
| 218 |
+
def test_activation_time_constant_is_immutable(self):
|
| 219 |
+
with pytest.raises(AttributeError):
|
| 220 |
+
self.instance.tau_a = None
|
| 221 |
+
with pytest.raises(AttributeError):
|
| 222 |
+
self.instance.activation_time_constant = None
|
| 223 |
+
|
| 224 |
+
@pytest.mark.parametrize(
|
| 225 |
+
'tau_d, expected',
|
| 226 |
+
[
|
| 227 |
+
(None, Symbol('tau_d_name')),
|
| 228 |
+
(Symbol('tau_d'), Symbol('tau_d')),
|
| 229 |
+
(Float('0.060'), Float('0.060')),
|
| 230 |
+
]
|
| 231 |
+
)
|
| 232 |
+
def test_deactivation_time_constant(self, tau_d, expected):
|
| 233 |
+
instance = FirstOrderActivationDeGroote2016(
|
| 234 |
+
'name', deactivation_time_constant=tau_d,
|
| 235 |
+
)
|
| 236 |
+
assert instance.tau_d == expected
|
| 237 |
+
assert instance.deactivation_time_constant == expected
|
| 238 |
+
assert instance.tau_d is instance.deactivation_time_constant
|
| 239 |
+
|
| 240 |
+
def test_deactivation_time_constant_is_immutable(self):
|
| 241 |
+
with pytest.raises(AttributeError):
|
| 242 |
+
self.instance.tau_d = None
|
| 243 |
+
with pytest.raises(AttributeError):
|
| 244 |
+
self.instance.deactivation_time_constant = None
|
| 245 |
+
|
| 246 |
+
@pytest.mark.parametrize(
|
| 247 |
+
'b, expected',
|
| 248 |
+
[
|
| 249 |
+
(None, Symbol('b_name')),
|
| 250 |
+
(Symbol('b'), Symbol('b')),
|
| 251 |
+
(Integer('10'), Integer('10')),
|
| 252 |
+
]
|
| 253 |
+
)
|
| 254 |
+
def test_smoothing_rate(self, b, expected):
|
| 255 |
+
instance = FirstOrderActivationDeGroote2016(
|
| 256 |
+
'name', smoothing_rate=b,
|
| 257 |
+
)
|
| 258 |
+
assert instance.b == expected
|
| 259 |
+
assert instance.smoothing_rate == expected
|
| 260 |
+
assert instance.b is instance.smoothing_rate
|
| 261 |
+
|
| 262 |
+
def test_smoothing_rate_is_immutable(self):
|
| 263 |
+
with pytest.raises(AttributeError):
|
| 264 |
+
self.instance.b = None
|
| 265 |
+
with pytest.raises(AttributeError):
|
| 266 |
+
self.instance.smoothing_rate = None
|
| 267 |
+
|
| 268 |
+
def test_state_vars(self):
|
| 269 |
+
assert hasattr(self.instance, 'x')
|
| 270 |
+
assert hasattr(self.instance, 'state_vars')
|
| 271 |
+
assert self.instance.x == self.instance.state_vars
|
| 272 |
+
x_expected = Matrix([self.a])
|
| 273 |
+
assert self.instance.x == x_expected
|
| 274 |
+
assert self.instance.state_vars == x_expected
|
| 275 |
+
assert isinstance(self.instance.x, Matrix)
|
| 276 |
+
assert isinstance(self.instance.state_vars, Matrix)
|
| 277 |
+
assert self.instance.x.shape == (1, 1)
|
| 278 |
+
assert self.instance.state_vars.shape == (1, 1)
|
| 279 |
+
|
| 280 |
+
def test_input_vars(self):
|
| 281 |
+
assert hasattr(self.instance, 'r')
|
| 282 |
+
assert hasattr(self.instance, 'input_vars')
|
| 283 |
+
assert self.instance.r == self.instance.input_vars
|
| 284 |
+
r_expected = Matrix([self.e])
|
| 285 |
+
assert self.instance.r == r_expected
|
| 286 |
+
assert self.instance.input_vars == r_expected
|
| 287 |
+
assert isinstance(self.instance.r, Matrix)
|
| 288 |
+
assert isinstance(self.instance.input_vars, Matrix)
|
| 289 |
+
assert self.instance.r.shape == (1, 1)
|
| 290 |
+
assert self.instance.input_vars.shape == (1, 1)
|
| 291 |
+
|
| 292 |
+
def test_constants(self):
|
| 293 |
+
assert hasattr(self.instance, 'p')
|
| 294 |
+
assert hasattr(self.instance, 'constants')
|
| 295 |
+
assert self.instance.p == self.instance.constants
|
| 296 |
+
p_expected = Matrix([self.tau_a, self.tau_d, self.b])
|
| 297 |
+
assert self.instance.p == p_expected
|
| 298 |
+
assert self.instance.constants == p_expected
|
| 299 |
+
assert isinstance(self.instance.p, Matrix)
|
| 300 |
+
assert isinstance(self.instance.constants, Matrix)
|
| 301 |
+
assert self.instance.p.shape == (3, 1)
|
| 302 |
+
assert self.instance.constants.shape == (3, 1)
|
| 303 |
+
|
| 304 |
+
def test_M(self):
|
| 305 |
+
assert hasattr(self.instance, 'M')
|
| 306 |
+
M_expected = Matrix([1])
|
| 307 |
+
assert self.instance.M == M_expected
|
| 308 |
+
assert isinstance(self.instance.M, Matrix)
|
| 309 |
+
assert self.instance.M.shape == (1, 1)
|
| 310 |
+
|
| 311 |
+
def test_F(self):
|
| 312 |
+
assert hasattr(self.instance, 'F')
|
| 313 |
+
da_expr = (
|
| 314 |
+
((1/(self.tau_a*(Rational(1, 2) + Rational(3, 2)*self.a)))
|
| 315 |
+
*(Rational(1, 2) + Rational(1, 2)*tanh(self.b*(self.e - self.a)))
|
| 316 |
+
+ ((Rational(1, 2) + Rational(3, 2)*self.a)/self.tau_d)
|
| 317 |
+
*(Rational(1, 2) - Rational(1, 2)*tanh(self.b*(self.e - self.a))))
|
| 318 |
+
*(self.e - self.a)
|
| 319 |
+
)
|
| 320 |
+
F_expected = Matrix([da_expr])
|
| 321 |
+
assert self.instance.F == F_expected
|
| 322 |
+
assert isinstance(self.instance.F, Matrix)
|
| 323 |
+
assert self.instance.F.shape == (1, 1)
|
| 324 |
+
|
| 325 |
+
def test_rhs(self):
|
| 326 |
+
assert hasattr(self.instance, 'rhs')
|
| 327 |
+
da_expr = (
|
| 328 |
+
((1/(self.tau_a*(Rational(1, 2) + Rational(3, 2)*self.a)))
|
| 329 |
+
*(Rational(1, 2) + Rational(1, 2)*tanh(self.b*(self.e - self.a)))
|
| 330 |
+
+ ((Rational(1, 2) + Rational(3, 2)*self.a)/self.tau_d)
|
| 331 |
+
*(Rational(1, 2) - Rational(1, 2)*tanh(self.b*(self.e - self.a))))
|
| 332 |
+
*(self.e - self.a)
|
| 333 |
+
)
|
| 334 |
+
rhs_expected = Matrix([da_expr])
|
| 335 |
+
rhs = self.instance.rhs()
|
| 336 |
+
assert rhs == rhs_expected
|
| 337 |
+
assert isinstance(rhs, Matrix)
|
| 338 |
+
assert rhs.shape == (1, 1)
|
| 339 |
+
assert simplify(self.instance.M.solve(self.instance.F) - rhs) == zeros(1)
|
| 340 |
+
|
| 341 |
+
def test_repr(self):
|
| 342 |
+
expected = (
|
| 343 |
+
'FirstOrderActivationDeGroote2016(\'name\', '
|
| 344 |
+
'activation_time_constant=tau_a, '
|
| 345 |
+
'deactivation_time_constant=tau_d, '
|
| 346 |
+
'smoothing_rate=b)'
|
| 347 |
+
)
|
| 348 |
+
assert repr(self.instance) == expected
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/control/__init__.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .lti import (TransferFunction, Series, MIMOSeries, Parallel, MIMOParallel,
|
| 2 |
+
Feedback, MIMOFeedback, TransferFunctionMatrix, StateSpace, gbt, bilinear, forward_diff,
|
| 3 |
+
backward_diff, phase_margin, gain_margin)
|
| 4 |
+
from .control_plots import (pole_zero_numerical_data, pole_zero_plot, step_response_numerical_data,
|
| 5 |
+
step_response_plot, impulse_response_numerical_data, impulse_response_plot, ramp_response_numerical_data,
|
| 6 |
+
ramp_response_plot, bode_magnitude_numerical_data, bode_phase_numerical_data, bode_magnitude_plot,
|
| 7 |
+
bode_phase_plot, bode_plot)
|
| 8 |
+
|
| 9 |
+
__all__ = ['TransferFunction', 'Series', 'MIMOSeries', 'Parallel',
|
| 10 |
+
'MIMOParallel', 'Feedback', 'MIMOFeedback', 'TransferFunctionMatrix', 'StateSpace',
|
| 11 |
+
'gbt', 'bilinear', 'forward_diff', 'backward_diff', 'phase_margin', 'gain_margin',
|
| 12 |
+
'pole_zero_numerical_data', 'pole_zero_plot', 'step_response_numerical_data',
|
| 13 |
+
'step_response_plot', 'impulse_response_numerical_data', 'impulse_response_plot',
|
| 14 |
+
'ramp_response_numerical_data', 'ramp_response_plot',
|
| 15 |
+
'bode_magnitude_numerical_data', 'bode_phase_numerical_data',
|
| 16 |
+
'bode_magnitude_plot', 'bode_phase_plot', 'bode_plot']
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/control/control_plots.py
ADDED
|
@@ -0,0 +1,978 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.numbers import I, pi
|
| 2 |
+
from sympy.functions.elementary.exponential import (exp, log)
|
| 3 |
+
from sympy.polys.partfrac import apart
|
| 4 |
+
from sympy.core.symbol import Dummy
|
| 5 |
+
from sympy.external import import_module
|
| 6 |
+
from sympy.functions import arg, Abs
|
| 7 |
+
from sympy.integrals.laplace import _fast_inverse_laplace
|
| 8 |
+
from sympy.physics.control.lti import SISOLinearTimeInvariant
|
| 9 |
+
from sympy.plotting.series import LineOver1DRangeSeries
|
| 10 |
+
from sympy.polys.polytools import Poly
|
| 11 |
+
from sympy.printing.latex import latex
|
| 12 |
+
|
| 13 |
+
__all__ = ['pole_zero_numerical_data', 'pole_zero_plot',
|
| 14 |
+
'step_response_numerical_data', 'step_response_plot',
|
| 15 |
+
'impulse_response_numerical_data', 'impulse_response_plot',
|
| 16 |
+
'ramp_response_numerical_data', 'ramp_response_plot',
|
| 17 |
+
'bode_magnitude_numerical_data', 'bode_phase_numerical_data',
|
| 18 |
+
'bode_magnitude_plot', 'bode_phase_plot', 'bode_plot']
|
| 19 |
+
|
| 20 |
+
matplotlib = import_module(
|
| 21 |
+
'matplotlib', import_kwargs={'fromlist': ['pyplot']},
|
| 22 |
+
catch=(RuntimeError,))
|
| 23 |
+
|
| 24 |
+
numpy = import_module('numpy')
|
| 25 |
+
|
| 26 |
+
if matplotlib:
|
| 27 |
+
plt = matplotlib.pyplot
|
| 28 |
+
|
| 29 |
+
if numpy:
|
| 30 |
+
np = numpy # Matplotlib already has numpy as a compulsory dependency. No need to install it separately.
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def _check_system(system):
|
| 34 |
+
"""Function to check whether the dynamical system passed for plots is
|
| 35 |
+
compatible or not."""
|
| 36 |
+
if not isinstance(system, SISOLinearTimeInvariant):
|
| 37 |
+
raise NotImplementedError("Only SISO LTI systems are currently supported.")
|
| 38 |
+
sys = system.to_expr()
|
| 39 |
+
len_free_symbols = len(sys.free_symbols)
|
| 40 |
+
if len_free_symbols > 1:
|
| 41 |
+
raise ValueError("Extra degree of freedom found. Make sure"
|
| 42 |
+
" that there are no free symbols in the dynamical system other"
|
| 43 |
+
" than the variable of Laplace transform.")
|
| 44 |
+
if sys.has(exp):
|
| 45 |
+
# Should test that exp is not part of a constant, in which case
|
| 46 |
+
# no exception is required, compare exp(s) with s*exp(1)
|
| 47 |
+
raise NotImplementedError("Time delay terms are not supported.")
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def pole_zero_numerical_data(system):
|
| 51 |
+
"""
|
| 52 |
+
Returns the numerical data of poles and zeros of the system.
|
| 53 |
+
It is internally used by ``pole_zero_plot`` to get the data
|
| 54 |
+
for plotting poles and zeros. Users can use this data to further
|
| 55 |
+
analyse the dynamics of the system or plot using a different
|
| 56 |
+
backend/plotting-module.
|
| 57 |
+
|
| 58 |
+
Parameters
|
| 59 |
+
==========
|
| 60 |
+
|
| 61 |
+
system : SISOLinearTimeInvariant
|
| 62 |
+
The system for which the pole-zero data is to be computed.
|
| 63 |
+
|
| 64 |
+
Returns
|
| 65 |
+
=======
|
| 66 |
+
|
| 67 |
+
tuple : (zeros, poles)
|
| 68 |
+
zeros = Zeros of the system. NumPy array of complex numbers.
|
| 69 |
+
poles = Poles of the system. NumPy array of complex numbers.
|
| 70 |
+
|
| 71 |
+
Raises
|
| 72 |
+
======
|
| 73 |
+
|
| 74 |
+
NotImplementedError
|
| 75 |
+
When a SISO LTI system is not passed.
|
| 76 |
+
|
| 77 |
+
When time delay terms are present in the system.
|
| 78 |
+
|
| 79 |
+
ValueError
|
| 80 |
+
When more than one free symbol is present in the system.
|
| 81 |
+
The only variable in the transfer function should be
|
| 82 |
+
the variable of the Laplace transform.
|
| 83 |
+
|
| 84 |
+
Examples
|
| 85 |
+
========
|
| 86 |
+
|
| 87 |
+
>>> from sympy.abc import s
|
| 88 |
+
>>> from sympy.physics.control.lti import TransferFunction
|
| 89 |
+
>>> from sympy.physics.control.control_plots import pole_zero_numerical_data
|
| 90 |
+
>>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s)
|
| 91 |
+
>>> pole_zero_numerical_data(tf1) # doctest: +SKIP
|
| 92 |
+
([-0.+1.j 0.-1.j], [-2. +0.j -0.5+0.8660254j -0.5-0.8660254j -1. +0.j ])
|
| 93 |
+
|
| 94 |
+
See Also
|
| 95 |
+
========
|
| 96 |
+
|
| 97 |
+
pole_zero_plot
|
| 98 |
+
|
| 99 |
+
"""
|
| 100 |
+
_check_system(system)
|
| 101 |
+
system = system.doit() # Get the equivalent TransferFunction object.
|
| 102 |
+
|
| 103 |
+
num_poly = Poly(system.num, system.var).all_coeffs()
|
| 104 |
+
den_poly = Poly(system.den, system.var).all_coeffs()
|
| 105 |
+
|
| 106 |
+
num_poly = np.array(num_poly, dtype=np.complex128)
|
| 107 |
+
den_poly = np.array(den_poly, dtype=np.complex128)
|
| 108 |
+
|
| 109 |
+
zeros = np.roots(num_poly)
|
| 110 |
+
poles = np.roots(den_poly)
|
| 111 |
+
|
| 112 |
+
return zeros, poles
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
def pole_zero_plot(system, pole_color='blue', pole_markersize=10,
|
| 116 |
+
zero_color='orange', zero_markersize=7, grid=True, show_axes=True,
|
| 117 |
+
show=True, **kwargs):
|
| 118 |
+
r"""
|
| 119 |
+
Returns the Pole-Zero plot (also known as PZ Plot or PZ Map) of a system.
|
| 120 |
+
|
| 121 |
+
A Pole-Zero plot is a graphical representation of a system's poles and
|
| 122 |
+
zeros. It is plotted on a complex plane, with circular markers representing
|
| 123 |
+
the system's zeros and 'x' shaped markers representing the system's poles.
|
| 124 |
+
|
| 125 |
+
Parameters
|
| 126 |
+
==========
|
| 127 |
+
|
| 128 |
+
system : SISOLinearTimeInvariant type systems
|
| 129 |
+
The system for which the pole-zero plot is to be computed.
|
| 130 |
+
pole_color : str, tuple, optional
|
| 131 |
+
The color of the pole points on the plot. Default color
|
| 132 |
+
is blue. The color can be provided as a matplotlib color string,
|
| 133 |
+
or a 3-tuple of floats each in the 0-1 range.
|
| 134 |
+
pole_markersize : Number, optional
|
| 135 |
+
The size of the markers used to mark the poles in the plot.
|
| 136 |
+
Default pole markersize is 10.
|
| 137 |
+
zero_color : str, tuple, optional
|
| 138 |
+
The color of the zero points on the plot. Default color
|
| 139 |
+
is orange. The color can be provided as a matplotlib color string,
|
| 140 |
+
or a 3-tuple of floats each in the 0-1 range.
|
| 141 |
+
zero_markersize : Number, optional
|
| 142 |
+
The size of the markers used to mark the zeros in the plot.
|
| 143 |
+
Default zero markersize is 7.
|
| 144 |
+
grid : boolean, optional
|
| 145 |
+
If ``True``, the plot will have a grid. Defaults to True.
|
| 146 |
+
show_axes : boolean, optional
|
| 147 |
+
If ``True``, the coordinate axes will be shown. Defaults to False.
|
| 148 |
+
show : boolean, optional
|
| 149 |
+
If ``True``, the plot will be displayed otherwise
|
| 150 |
+
the equivalent matplotlib ``plot`` object will be returned.
|
| 151 |
+
Defaults to True.
|
| 152 |
+
|
| 153 |
+
Examples
|
| 154 |
+
========
|
| 155 |
+
|
| 156 |
+
.. plot::
|
| 157 |
+
:context: close-figs
|
| 158 |
+
:format: doctest
|
| 159 |
+
:include-source: True
|
| 160 |
+
|
| 161 |
+
>>> from sympy.abc import s
|
| 162 |
+
>>> from sympy.physics.control.lti import TransferFunction
|
| 163 |
+
>>> from sympy.physics.control.control_plots import pole_zero_plot
|
| 164 |
+
>>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s)
|
| 165 |
+
>>> pole_zero_plot(tf1) # doctest: +SKIP
|
| 166 |
+
|
| 167 |
+
See Also
|
| 168 |
+
========
|
| 169 |
+
|
| 170 |
+
pole_zero_numerical_data
|
| 171 |
+
|
| 172 |
+
References
|
| 173 |
+
==========
|
| 174 |
+
|
| 175 |
+
.. [1] https://en.wikipedia.org/wiki/Pole%E2%80%93zero_plot
|
| 176 |
+
|
| 177 |
+
"""
|
| 178 |
+
zeros, poles = pole_zero_numerical_data(system)
|
| 179 |
+
|
| 180 |
+
zero_real = np.real(zeros)
|
| 181 |
+
zero_imag = np.imag(zeros)
|
| 182 |
+
|
| 183 |
+
pole_real = np.real(poles)
|
| 184 |
+
pole_imag = np.imag(poles)
|
| 185 |
+
|
| 186 |
+
plt.plot(pole_real, pole_imag, 'x', mfc='none',
|
| 187 |
+
markersize=pole_markersize, color=pole_color)
|
| 188 |
+
plt.plot(zero_real, zero_imag, 'o', markersize=zero_markersize,
|
| 189 |
+
color=zero_color)
|
| 190 |
+
plt.xlabel('Real Axis')
|
| 191 |
+
plt.ylabel('Imaginary Axis')
|
| 192 |
+
plt.title(f'Poles and Zeros of ${latex(system)}$', pad=20)
|
| 193 |
+
|
| 194 |
+
if grid:
|
| 195 |
+
plt.grid()
|
| 196 |
+
if show_axes:
|
| 197 |
+
plt.axhline(0, color='black')
|
| 198 |
+
plt.axvline(0, color='black')
|
| 199 |
+
if show:
|
| 200 |
+
plt.show()
|
| 201 |
+
return
|
| 202 |
+
|
| 203 |
+
return plt
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
def step_response_numerical_data(system, prec=8, lower_limit=0,
|
| 207 |
+
upper_limit=10, **kwargs):
|
| 208 |
+
"""
|
| 209 |
+
Returns the numerical values of the points in the step response plot
|
| 210 |
+
of a SISO continuous-time system. By default, adaptive sampling
|
| 211 |
+
is used. If the user wants to instead get an uniformly
|
| 212 |
+
sampled response, then ``adaptive`` kwarg should be passed ``False``
|
| 213 |
+
and ``n`` must be passed as additional kwargs.
|
| 214 |
+
Refer to the parameters of class :class:`sympy.plotting.series.LineOver1DRangeSeries`
|
| 215 |
+
for more details.
|
| 216 |
+
|
| 217 |
+
Parameters
|
| 218 |
+
==========
|
| 219 |
+
|
| 220 |
+
system : SISOLinearTimeInvariant
|
| 221 |
+
The system for which the unit step response data is to be computed.
|
| 222 |
+
prec : int, optional
|
| 223 |
+
The decimal point precision for the point coordinate values.
|
| 224 |
+
Defaults to 8.
|
| 225 |
+
lower_limit : Number, optional
|
| 226 |
+
The lower limit of the plot range. Defaults to 0.
|
| 227 |
+
upper_limit : Number, optional
|
| 228 |
+
The upper limit of the plot range. Defaults to 10.
|
| 229 |
+
kwargs :
|
| 230 |
+
Additional keyword arguments are passed to the underlying
|
| 231 |
+
:class:`sympy.plotting.series.LineOver1DRangeSeries` class.
|
| 232 |
+
|
| 233 |
+
Returns
|
| 234 |
+
=======
|
| 235 |
+
|
| 236 |
+
tuple : (x, y)
|
| 237 |
+
x = Time-axis values of the points in the step response. NumPy array.
|
| 238 |
+
y = Amplitude-axis values of the points in the step response. NumPy array.
|
| 239 |
+
|
| 240 |
+
Raises
|
| 241 |
+
======
|
| 242 |
+
|
| 243 |
+
NotImplementedError
|
| 244 |
+
When a SISO LTI system is not passed.
|
| 245 |
+
|
| 246 |
+
When time delay terms are present in the system.
|
| 247 |
+
|
| 248 |
+
ValueError
|
| 249 |
+
When more than one free symbol is present in the system.
|
| 250 |
+
The only variable in the transfer function should be
|
| 251 |
+
the variable of the Laplace transform.
|
| 252 |
+
|
| 253 |
+
When ``lower_limit`` parameter is less than 0.
|
| 254 |
+
|
| 255 |
+
Examples
|
| 256 |
+
========
|
| 257 |
+
|
| 258 |
+
>>> from sympy.abc import s
|
| 259 |
+
>>> from sympy.physics.control.lti import TransferFunction
|
| 260 |
+
>>> from sympy.physics.control.control_plots import step_response_numerical_data
|
| 261 |
+
>>> tf1 = TransferFunction(s, s**2 + 5*s + 8, s)
|
| 262 |
+
>>> step_response_numerical_data(tf1) # doctest: +SKIP
|
| 263 |
+
([0.0, 0.025413462339411542, 0.0484508722725343, ... , 9.670250533855183, 9.844291913708725, 10.0],
|
| 264 |
+
[0.0, 0.023844582399907256, 0.042894276802320226, ..., 6.828770759094287e-12, 6.456457160755703e-12])
|
| 265 |
+
|
| 266 |
+
See Also
|
| 267 |
+
========
|
| 268 |
+
|
| 269 |
+
step_response_plot
|
| 270 |
+
|
| 271 |
+
"""
|
| 272 |
+
if lower_limit < 0:
|
| 273 |
+
raise ValueError("Lower limit of time must be greater "
|
| 274 |
+
"than or equal to zero.")
|
| 275 |
+
_check_system(system)
|
| 276 |
+
_x = Dummy("x")
|
| 277 |
+
expr = system.to_expr()/(system.var)
|
| 278 |
+
expr = apart(expr, system.var, full=True)
|
| 279 |
+
_y = _fast_inverse_laplace(expr, system.var, _x).evalf(prec)
|
| 280 |
+
return LineOver1DRangeSeries(_y, (_x, lower_limit, upper_limit),
|
| 281 |
+
**kwargs).get_points()
|
| 282 |
+
|
| 283 |
+
|
| 284 |
+
def step_response_plot(system, color='b', prec=8, lower_limit=0,
|
| 285 |
+
upper_limit=10, show_axes=False, grid=True, show=True, **kwargs):
|
| 286 |
+
r"""
|
| 287 |
+
Returns the unit step response of a continuous-time system. It is
|
| 288 |
+
the response of the system when the input signal is a step function.
|
| 289 |
+
|
| 290 |
+
Parameters
|
| 291 |
+
==========
|
| 292 |
+
|
| 293 |
+
system : SISOLinearTimeInvariant type
|
| 294 |
+
The LTI SISO system for which the Step Response is to be computed.
|
| 295 |
+
color : str, tuple, optional
|
| 296 |
+
The color of the line. Default is Blue.
|
| 297 |
+
show : boolean, optional
|
| 298 |
+
If ``True``, the plot will be displayed otherwise
|
| 299 |
+
the equivalent matplotlib ``plot`` object will be returned.
|
| 300 |
+
Defaults to True.
|
| 301 |
+
lower_limit : Number, optional
|
| 302 |
+
The lower limit of the plot range. Defaults to 0.
|
| 303 |
+
upper_limit : Number, optional
|
| 304 |
+
The upper limit of the plot range. Defaults to 10.
|
| 305 |
+
prec : int, optional
|
| 306 |
+
The decimal point precision for the point coordinate values.
|
| 307 |
+
Defaults to 8.
|
| 308 |
+
show_axes : boolean, optional
|
| 309 |
+
If ``True``, the coordinate axes will be shown. Defaults to False.
|
| 310 |
+
grid : boolean, optional
|
| 311 |
+
If ``True``, the plot will have a grid. Defaults to True.
|
| 312 |
+
|
| 313 |
+
Examples
|
| 314 |
+
========
|
| 315 |
+
|
| 316 |
+
.. plot::
|
| 317 |
+
:context: close-figs
|
| 318 |
+
:format: doctest
|
| 319 |
+
:include-source: True
|
| 320 |
+
|
| 321 |
+
>>> from sympy.abc import s
|
| 322 |
+
>>> from sympy.physics.control.lti import TransferFunction
|
| 323 |
+
>>> from sympy.physics.control.control_plots import step_response_plot
|
| 324 |
+
>>> tf1 = TransferFunction(8*s**2 + 18*s + 32, s**3 + 6*s**2 + 14*s + 24, s)
|
| 325 |
+
>>> step_response_plot(tf1) # doctest: +SKIP
|
| 326 |
+
|
| 327 |
+
See Also
|
| 328 |
+
========
|
| 329 |
+
|
| 330 |
+
impulse_response_plot, ramp_response_plot
|
| 331 |
+
|
| 332 |
+
References
|
| 333 |
+
==========
|
| 334 |
+
|
| 335 |
+
.. [1] https://www.mathworks.com/help/control/ref/lti.step.html
|
| 336 |
+
|
| 337 |
+
"""
|
| 338 |
+
x, y = step_response_numerical_data(system, prec=prec,
|
| 339 |
+
lower_limit=lower_limit, upper_limit=upper_limit, **kwargs)
|
| 340 |
+
plt.plot(x, y, color=color)
|
| 341 |
+
plt.xlabel('Time (s)')
|
| 342 |
+
plt.ylabel('Amplitude')
|
| 343 |
+
plt.title(f'Unit Step Response of ${latex(system)}$', pad=20)
|
| 344 |
+
|
| 345 |
+
if grid:
|
| 346 |
+
plt.grid()
|
| 347 |
+
if show_axes:
|
| 348 |
+
plt.axhline(0, color='black')
|
| 349 |
+
plt.axvline(0, color='black')
|
| 350 |
+
if show:
|
| 351 |
+
plt.show()
|
| 352 |
+
return
|
| 353 |
+
|
| 354 |
+
return plt
|
| 355 |
+
|
| 356 |
+
|
| 357 |
+
def impulse_response_numerical_data(system, prec=8, lower_limit=0,
|
| 358 |
+
upper_limit=10, **kwargs):
|
| 359 |
+
"""
|
| 360 |
+
Returns the numerical values of the points in the impulse response plot
|
| 361 |
+
of a SISO continuous-time system. By default, adaptive sampling
|
| 362 |
+
is used. If the user wants to instead get an uniformly
|
| 363 |
+
sampled response, then ``adaptive`` kwarg should be passed ``False``
|
| 364 |
+
and ``n`` must be passed as additional kwargs.
|
| 365 |
+
Refer to the parameters of class :class:`sympy.plotting.series.LineOver1DRangeSeries`
|
| 366 |
+
for more details.
|
| 367 |
+
|
| 368 |
+
Parameters
|
| 369 |
+
==========
|
| 370 |
+
|
| 371 |
+
system : SISOLinearTimeInvariant
|
| 372 |
+
The system for which the impulse response data is to be computed.
|
| 373 |
+
prec : int, optional
|
| 374 |
+
The decimal point precision for the point coordinate values.
|
| 375 |
+
Defaults to 8.
|
| 376 |
+
lower_limit : Number, optional
|
| 377 |
+
The lower limit of the plot range. Defaults to 0.
|
| 378 |
+
upper_limit : Number, optional
|
| 379 |
+
The upper limit of the plot range. Defaults to 10.
|
| 380 |
+
kwargs :
|
| 381 |
+
Additional keyword arguments are passed to the underlying
|
| 382 |
+
:class:`sympy.plotting.series.LineOver1DRangeSeries` class.
|
| 383 |
+
|
| 384 |
+
Returns
|
| 385 |
+
=======
|
| 386 |
+
|
| 387 |
+
tuple : (x, y)
|
| 388 |
+
x = Time-axis values of the points in the impulse response. NumPy array.
|
| 389 |
+
y = Amplitude-axis values of the points in the impulse response. NumPy array.
|
| 390 |
+
|
| 391 |
+
Raises
|
| 392 |
+
======
|
| 393 |
+
|
| 394 |
+
NotImplementedError
|
| 395 |
+
When a SISO LTI system is not passed.
|
| 396 |
+
|
| 397 |
+
When time delay terms are present in the system.
|
| 398 |
+
|
| 399 |
+
ValueError
|
| 400 |
+
When more than one free symbol is present in the system.
|
| 401 |
+
The only variable in the transfer function should be
|
| 402 |
+
the variable of the Laplace transform.
|
| 403 |
+
|
| 404 |
+
When ``lower_limit`` parameter is less than 0.
|
| 405 |
+
|
| 406 |
+
Examples
|
| 407 |
+
========
|
| 408 |
+
|
| 409 |
+
>>> from sympy.abc import s
|
| 410 |
+
>>> from sympy.physics.control.lti import TransferFunction
|
| 411 |
+
>>> from sympy.physics.control.control_plots import impulse_response_numerical_data
|
| 412 |
+
>>> tf1 = TransferFunction(s, s**2 + 5*s + 8, s)
|
| 413 |
+
>>> impulse_response_numerical_data(tf1) # doctest: +SKIP
|
| 414 |
+
([0.0, 0.06616480200395854,... , 9.854500743565858, 10.0],
|
| 415 |
+
[0.9999999799999999, 0.7042848373025861,...,7.170748906965121e-13, -5.1901263495547205e-12])
|
| 416 |
+
|
| 417 |
+
See Also
|
| 418 |
+
========
|
| 419 |
+
|
| 420 |
+
impulse_response_plot
|
| 421 |
+
|
| 422 |
+
"""
|
| 423 |
+
if lower_limit < 0:
|
| 424 |
+
raise ValueError("Lower limit of time must be greater "
|
| 425 |
+
"than or equal to zero.")
|
| 426 |
+
_check_system(system)
|
| 427 |
+
_x = Dummy("x")
|
| 428 |
+
expr = system.to_expr()
|
| 429 |
+
expr = apart(expr, system.var, full=True)
|
| 430 |
+
_y = _fast_inverse_laplace(expr, system.var, _x).evalf(prec)
|
| 431 |
+
return LineOver1DRangeSeries(_y, (_x, lower_limit, upper_limit),
|
| 432 |
+
**kwargs).get_points()
|
| 433 |
+
|
| 434 |
+
|
| 435 |
+
def impulse_response_plot(system, color='b', prec=8, lower_limit=0,
|
| 436 |
+
upper_limit=10, show_axes=False, grid=True, show=True, **kwargs):
|
| 437 |
+
r"""
|
| 438 |
+
Returns the unit impulse response (Input is the Dirac-Delta Function) of a
|
| 439 |
+
continuous-time system.
|
| 440 |
+
|
| 441 |
+
Parameters
|
| 442 |
+
==========
|
| 443 |
+
|
| 444 |
+
system : SISOLinearTimeInvariant type
|
| 445 |
+
The LTI SISO system for which the Impulse Response is to be computed.
|
| 446 |
+
color : str, tuple, optional
|
| 447 |
+
The color of the line. Default is Blue.
|
| 448 |
+
show : boolean, optional
|
| 449 |
+
If ``True``, the plot will be displayed otherwise
|
| 450 |
+
the equivalent matplotlib ``plot`` object will be returned.
|
| 451 |
+
Defaults to True.
|
| 452 |
+
lower_limit : Number, optional
|
| 453 |
+
The lower limit of the plot range. Defaults to 0.
|
| 454 |
+
upper_limit : Number, optional
|
| 455 |
+
The upper limit of the plot range. Defaults to 10.
|
| 456 |
+
prec : int, optional
|
| 457 |
+
The decimal point precision for the point coordinate values.
|
| 458 |
+
Defaults to 8.
|
| 459 |
+
show_axes : boolean, optional
|
| 460 |
+
If ``True``, the coordinate axes will be shown. Defaults to False.
|
| 461 |
+
grid : boolean, optional
|
| 462 |
+
If ``True``, the plot will have a grid. Defaults to True.
|
| 463 |
+
|
| 464 |
+
Examples
|
| 465 |
+
========
|
| 466 |
+
|
| 467 |
+
.. plot::
|
| 468 |
+
:context: close-figs
|
| 469 |
+
:format: doctest
|
| 470 |
+
:include-source: True
|
| 471 |
+
|
| 472 |
+
>>> from sympy.abc import s
|
| 473 |
+
>>> from sympy.physics.control.lti import TransferFunction
|
| 474 |
+
>>> from sympy.physics.control.control_plots import impulse_response_plot
|
| 475 |
+
>>> tf1 = TransferFunction(8*s**2 + 18*s + 32, s**3 + 6*s**2 + 14*s + 24, s)
|
| 476 |
+
>>> impulse_response_plot(tf1) # doctest: +SKIP
|
| 477 |
+
|
| 478 |
+
See Also
|
| 479 |
+
========
|
| 480 |
+
|
| 481 |
+
step_response_plot, ramp_response_plot
|
| 482 |
+
|
| 483 |
+
References
|
| 484 |
+
==========
|
| 485 |
+
|
| 486 |
+
.. [1] https://www.mathworks.com/help/control/ref/dynamicsystem.impulse.html
|
| 487 |
+
|
| 488 |
+
"""
|
| 489 |
+
x, y = impulse_response_numerical_data(system, prec=prec,
|
| 490 |
+
lower_limit=lower_limit, upper_limit=upper_limit, **kwargs)
|
| 491 |
+
plt.plot(x, y, color=color)
|
| 492 |
+
plt.xlabel('Time (s)')
|
| 493 |
+
plt.ylabel('Amplitude')
|
| 494 |
+
plt.title(f'Impulse Response of ${latex(system)}$', pad=20)
|
| 495 |
+
|
| 496 |
+
if grid:
|
| 497 |
+
plt.grid()
|
| 498 |
+
if show_axes:
|
| 499 |
+
plt.axhline(0, color='black')
|
| 500 |
+
plt.axvline(0, color='black')
|
| 501 |
+
if show:
|
| 502 |
+
plt.show()
|
| 503 |
+
return
|
| 504 |
+
|
| 505 |
+
return plt
|
| 506 |
+
|
| 507 |
+
|
| 508 |
+
def ramp_response_numerical_data(system, slope=1, prec=8,
|
| 509 |
+
lower_limit=0, upper_limit=10, **kwargs):
|
| 510 |
+
"""
|
| 511 |
+
Returns the numerical values of the points in the ramp response plot
|
| 512 |
+
of a SISO continuous-time system. By default, adaptive sampling
|
| 513 |
+
is used. If the user wants to instead get an uniformly
|
| 514 |
+
sampled response, then ``adaptive`` kwarg should be passed ``False``
|
| 515 |
+
and ``n`` must be passed as additional kwargs.
|
| 516 |
+
Refer to the parameters of class :class:`sympy.plotting.series.LineOver1DRangeSeries`
|
| 517 |
+
for more details.
|
| 518 |
+
|
| 519 |
+
Parameters
|
| 520 |
+
==========
|
| 521 |
+
|
| 522 |
+
system : SISOLinearTimeInvariant
|
| 523 |
+
The system for which the ramp response data is to be computed.
|
| 524 |
+
slope : Number, optional
|
| 525 |
+
The slope of the input ramp function. Defaults to 1.
|
| 526 |
+
prec : int, optional
|
| 527 |
+
The decimal point precision for the point coordinate values.
|
| 528 |
+
Defaults to 8.
|
| 529 |
+
lower_limit : Number, optional
|
| 530 |
+
The lower limit of the plot range. Defaults to 0.
|
| 531 |
+
upper_limit : Number, optional
|
| 532 |
+
The upper limit of the plot range. Defaults to 10.
|
| 533 |
+
kwargs :
|
| 534 |
+
Additional keyword arguments are passed to the underlying
|
| 535 |
+
:class:`sympy.plotting.series.LineOver1DRangeSeries` class.
|
| 536 |
+
|
| 537 |
+
Returns
|
| 538 |
+
=======
|
| 539 |
+
|
| 540 |
+
tuple : (x, y)
|
| 541 |
+
x = Time-axis values of the points in the ramp response plot. NumPy array.
|
| 542 |
+
y = Amplitude-axis values of the points in the ramp response plot. NumPy array.
|
| 543 |
+
|
| 544 |
+
Raises
|
| 545 |
+
======
|
| 546 |
+
|
| 547 |
+
NotImplementedError
|
| 548 |
+
When a SISO LTI system is not passed.
|
| 549 |
+
|
| 550 |
+
When time delay terms are present in the system.
|
| 551 |
+
|
| 552 |
+
ValueError
|
| 553 |
+
When more than one free symbol is present in the system.
|
| 554 |
+
The only variable in the transfer function should be
|
| 555 |
+
the variable of the Laplace transform.
|
| 556 |
+
|
| 557 |
+
When ``lower_limit`` parameter is less than 0.
|
| 558 |
+
|
| 559 |
+
When ``slope`` is negative.
|
| 560 |
+
|
| 561 |
+
Examples
|
| 562 |
+
========
|
| 563 |
+
|
| 564 |
+
>>> from sympy.abc import s
|
| 565 |
+
>>> from sympy.physics.control.lti import TransferFunction
|
| 566 |
+
>>> from sympy.physics.control.control_plots import ramp_response_numerical_data
|
| 567 |
+
>>> tf1 = TransferFunction(s, s**2 + 5*s + 8, s)
|
| 568 |
+
>>> ramp_response_numerical_data(tf1) # doctest: +SKIP
|
| 569 |
+
(([0.0, 0.12166980856813935,..., 9.861246379582118, 10.0],
|
| 570 |
+
[1.4504508011325967e-09, 0.006046440489058766,..., 0.12499999999568202, 0.12499999999661349]))
|
| 571 |
+
|
| 572 |
+
See Also
|
| 573 |
+
========
|
| 574 |
+
|
| 575 |
+
ramp_response_plot
|
| 576 |
+
|
| 577 |
+
"""
|
| 578 |
+
if slope < 0:
|
| 579 |
+
raise ValueError("Slope must be greater than or equal"
|
| 580 |
+
" to zero.")
|
| 581 |
+
if lower_limit < 0:
|
| 582 |
+
raise ValueError("Lower limit of time must be greater "
|
| 583 |
+
"than or equal to zero.")
|
| 584 |
+
_check_system(system)
|
| 585 |
+
_x = Dummy("x")
|
| 586 |
+
expr = (slope*system.to_expr())/((system.var)**2)
|
| 587 |
+
expr = apart(expr, system.var, full=True)
|
| 588 |
+
_y = _fast_inverse_laplace(expr, system.var, _x).evalf(prec)
|
| 589 |
+
return LineOver1DRangeSeries(_y, (_x, lower_limit, upper_limit),
|
| 590 |
+
**kwargs).get_points()
|
| 591 |
+
|
| 592 |
+
|
| 593 |
+
def ramp_response_plot(system, slope=1, color='b', prec=8, lower_limit=0,
|
| 594 |
+
upper_limit=10, show_axes=False, grid=True, show=True, **kwargs):
|
| 595 |
+
r"""
|
| 596 |
+
Returns the ramp response of a continuous-time system.
|
| 597 |
+
|
| 598 |
+
Ramp function is defined as the straight line
|
| 599 |
+
passing through origin ($f(x) = mx$). The slope of
|
| 600 |
+
the ramp function can be varied by the user and
|
| 601 |
+
the default value is 1.
|
| 602 |
+
|
| 603 |
+
Parameters
|
| 604 |
+
==========
|
| 605 |
+
|
| 606 |
+
system : SISOLinearTimeInvariant type
|
| 607 |
+
The LTI SISO system for which the Ramp Response is to be computed.
|
| 608 |
+
slope : Number, optional
|
| 609 |
+
The slope of the input ramp function. Defaults to 1.
|
| 610 |
+
color : str, tuple, optional
|
| 611 |
+
The color of the line. Default is Blue.
|
| 612 |
+
show : boolean, optional
|
| 613 |
+
If ``True``, the plot will be displayed otherwise
|
| 614 |
+
the equivalent matplotlib ``plot`` object will be returned.
|
| 615 |
+
Defaults to True.
|
| 616 |
+
lower_limit : Number, optional
|
| 617 |
+
The lower limit of the plot range. Defaults to 0.
|
| 618 |
+
upper_limit : Number, optional
|
| 619 |
+
The upper limit of the plot range. Defaults to 10.
|
| 620 |
+
prec : int, optional
|
| 621 |
+
The decimal point precision for the point coordinate values.
|
| 622 |
+
Defaults to 8.
|
| 623 |
+
show_axes : boolean, optional
|
| 624 |
+
If ``True``, the coordinate axes will be shown. Defaults to False.
|
| 625 |
+
grid : boolean, optional
|
| 626 |
+
If ``True``, the plot will have a grid. Defaults to True.
|
| 627 |
+
|
| 628 |
+
Examples
|
| 629 |
+
========
|
| 630 |
+
|
| 631 |
+
.. plot::
|
| 632 |
+
:context: close-figs
|
| 633 |
+
:format: doctest
|
| 634 |
+
:include-source: True
|
| 635 |
+
|
| 636 |
+
>>> from sympy.abc import s
|
| 637 |
+
>>> from sympy.physics.control.lti import TransferFunction
|
| 638 |
+
>>> from sympy.physics.control.control_plots import ramp_response_plot
|
| 639 |
+
>>> tf1 = TransferFunction(s, (s+4)*(s+8), s)
|
| 640 |
+
>>> ramp_response_plot(tf1, upper_limit=2) # doctest: +SKIP
|
| 641 |
+
|
| 642 |
+
See Also
|
| 643 |
+
========
|
| 644 |
+
|
| 645 |
+
step_response_plot, impulse_response_plot
|
| 646 |
+
|
| 647 |
+
References
|
| 648 |
+
==========
|
| 649 |
+
|
| 650 |
+
.. [1] https://en.wikipedia.org/wiki/Ramp_function
|
| 651 |
+
|
| 652 |
+
"""
|
| 653 |
+
x, y = ramp_response_numerical_data(system, slope=slope, prec=prec,
|
| 654 |
+
lower_limit=lower_limit, upper_limit=upper_limit, **kwargs)
|
| 655 |
+
plt.plot(x, y, color=color)
|
| 656 |
+
plt.xlabel('Time (s)')
|
| 657 |
+
plt.ylabel('Amplitude')
|
| 658 |
+
plt.title(f'Ramp Response of ${latex(system)}$ [Slope = {slope}]', pad=20)
|
| 659 |
+
|
| 660 |
+
if grid:
|
| 661 |
+
plt.grid()
|
| 662 |
+
if show_axes:
|
| 663 |
+
plt.axhline(0, color='black')
|
| 664 |
+
plt.axvline(0, color='black')
|
| 665 |
+
if show:
|
| 666 |
+
plt.show()
|
| 667 |
+
return
|
| 668 |
+
|
| 669 |
+
return plt
|
| 670 |
+
|
| 671 |
+
|
| 672 |
+
def bode_magnitude_numerical_data(system, initial_exp=-5, final_exp=5, freq_unit='rad/sec', **kwargs):
|
| 673 |
+
"""
|
| 674 |
+
Returns the numerical data of the Bode magnitude plot of the system.
|
| 675 |
+
It is internally used by ``bode_magnitude_plot`` to get the data
|
| 676 |
+
for plotting Bode magnitude plot. Users can use this data to further
|
| 677 |
+
analyse the dynamics of the system or plot using a different
|
| 678 |
+
backend/plotting-module.
|
| 679 |
+
|
| 680 |
+
Parameters
|
| 681 |
+
==========
|
| 682 |
+
|
| 683 |
+
system : SISOLinearTimeInvariant
|
| 684 |
+
The system for which the data is to be computed.
|
| 685 |
+
initial_exp : Number, optional
|
| 686 |
+
The initial exponent of 10 of the semilog plot. Defaults to -5.
|
| 687 |
+
final_exp : Number, optional
|
| 688 |
+
The final exponent of 10 of the semilog plot. Defaults to 5.
|
| 689 |
+
freq_unit : string, optional
|
| 690 |
+
User can choose between ``'rad/sec'`` (radians/second) and ``'Hz'`` (Hertz) as frequency units.
|
| 691 |
+
|
| 692 |
+
Returns
|
| 693 |
+
=======
|
| 694 |
+
|
| 695 |
+
tuple : (x, y)
|
| 696 |
+
x = x-axis values of the Bode magnitude plot.
|
| 697 |
+
y = y-axis values of the Bode magnitude plot.
|
| 698 |
+
|
| 699 |
+
Raises
|
| 700 |
+
======
|
| 701 |
+
|
| 702 |
+
NotImplementedError
|
| 703 |
+
When a SISO LTI system is not passed.
|
| 704 |
+
|
| 705 |
+
When time delay terms are present in the system.
|
| 706 |
+
|
| 707 |
+
ValueError
|
| 708 |
+
When more than one free symbol is present in the system.
|
| 709 |
+
The only variable in the transfer function should be
|
| 710 |
+
the variable of the Laplace transform.
|
| 711 |
+
|
| 712 |
+
When incorrect frequency units are given as input.
|
| 713 |
+
|
| 714 |
+
Examples
|
| 715 |
+
========
|
| 716 |
+
|
| 717 |
+
>>> from sympy.abc import s
|
| 718 |
+
>>> from sympy.physics.control.lti import TransferFunction
|
| 719 |
+
>>> from sympy.physics.control.control_plots import bode_magnitude_numerical_data
|
| 720 |
+
>>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s)
|
| 721 |
+
>>> bode_magnitude_numerical_data(tf1) # doctest: +SKIP
|
| 722 |
+
([1e-05, 1.5148378120533502e-05,..., 68437.36188804005, 100000.0],
|
| 723 |
+
[-6.020599914256786, -6.0205999155219505,..., -193.4117304087953, -200.00000000260573])
|
| 724 |
+
|
| 725 |
+
See Also
|
| 726 |
+
========
|
| 727 |
+
|
| 728 |
+
bode_magnitude_plot, bode_phase_numerical_data
|
| 729 |
+
|
| 730 |
+
"""
|
| 731 |
+
_check_system(system)
|
| 732 |
+
expr = system.to_expr()
|
| 733 |
+
freq_units = ('rad/sec', 'Hz')
|
| 734 |
+
if freq_unit not in freq_units:
|
| 735 |
+
raise ValueError('Only "rad/sec" and "Hz" are accepted frequency units.')
|
| 736 |
+
|
| 737 |
+
_w = Dummy("w", real=True)
|
| 738 |
+
if freq_unit == 'Hz':
|
| 739 |
+
repl = I*_w*2*pi
|
| 740 |
+
else:
|
| 741 |
+
repl = I*_w
|
| 742 |
+
w_expr = expr.subs({system.var: repl})
|
| 743 |
+
|
| 744 |
+
mag = 20*log(Abs(w_expr), 10)
|
| 745 |
+
|
| 746 |
+
x, y = LineOver1DRangeSeries(mag,
|
| 747 |
+
(_w, 10**initial_exp, 10**final_exp), xscale='log', **kwargs).get_points()
|
| 748 |
+
|
| 749 |
+
return x, y
|
| 750 |
+
|
| 751 |
+
|
| 752 |
+
def bode_magnitude_plot(system, initial_exp=-5, final_exp=5,
|
| 753 |
+
color='b', show_axes=False, grid=True, show=True, freq_unit='rad/sec', **kwargs):
|
| 754 |
+
r"""
|
| 755 |
+
Returns the Bode magnitude plot of a continuous-time system.
|
| 756 |
+
|
| 757 |
+
See ``bode_plot`` for all the parameters.
|
| 758 |
+
"""
|
| 759 |
+
x, y = bode_magnitude_numerical_data(system, initial_exp=initial_exp,
|
| 760 |
+
final_exp=final_exp, freq_unit=freq_unit)
|
| 761 |
+
plt.plot(x, y, color=color, **kwargs)
|
| 762 |
+
plt.xscale('log')
|
| 763 |
+
|
| 764 |
+
|
| 765 |
+
plt.xlabel('Frequency (%s) [Log Scale]' % freq_unit)
|
| 766 |
+
plt.ylabel('Magnitude (dB)')
|
| 767 |
+
plt.title(f'Bode Plot (Magnitude) of ${latex(system)}$', pad=20)
|
| 768 |
+
|
| 769 |
+
if grid:
|
| 770 |
+
plt.grid(True)
|
| 771 |
+
if show_axes:
|
| 772 |
+
plt.axhline(0, color='black')
|
| 773 |
+
plt.axvline(0, color='black')
|
| 774 |
+
if show:
|
| 775 |
+
plt.show()
|
| 776 |
+
return
|
| 777 |
+
|
| 778 |
+
return plt
|
| 779 |
+
|
| 780 |
+
|
| 781 |
+
def bode_phase_numerical_data(system, initial_exp=-5, final_exp=5, freq_unit='rad/sec', phase_unit='rad', phase_unwrap = True, **kwargs):
|
| 782 |
+
"""
|
| 783 |
+
Returns the numerical data of the Bode phase plot of the system.
|
| 784 |
+
It is internally used by ``bode_phase_plot`` to get the data
|
| 785 |
+
for plotting Bode phase plot. Users can use this data to further
|
| 786 |
+
analyse the dynamics of the system or plot using a different
|
| 787 |
+
backend/plotting-module.
|
| 788 |
+
|
| 789 |
+
Parameters
|
| 790 |
+
==========
|
| 791 |
+
|
| 792 |
+
system : SISOLinearTimeInvariant
|
| 793 |
+
The system for which the Bode phase plot data is to be computed.
|
| 794 |
+
initial_exp : Number, optional
|
| 795 |
+
The initial exponent of 10 of the semilog plot. Defaults to -5.
|
| 796 |
+
final_exp : Number, optional
|
| 797 |
+
The final exponent of 10 of the semilog plot. Defaults to 5.
|
| 798 |
+
freq_unit : string, optional
|
| 799 |
+
User can choose between ``'rad/sec'`` (radians/second) and '``'Hz'`` (Hertz) as frequency units.
|
| 800 |
+
phase_unit : string, optional
|
| 801 |
+
User can choose between ``'rad'`` (radians) and ``'deg'`` (degree) as phase units.
|
| 802 |
+
phase_unwrap : bool, optional
|
| 803 |
+
Set to ``True`` by default.
|
| 804 |
+
|
| 805 |
+
Returns
|
| 806 |
+
=======
|
| 807 |
+
|
| 808 |
+
tuple : (x, y)
|
| 809 |
+
x = x-axis values of the Bode phase plot.
|
| 810 |
+
y = y-axis values of the Bode phase plot.
|
| 811 |
+
|
| 812 |
+
Raises
|
| 813 |
+
======
|
| 814 |
+
|
| 815 |
+
NotImplementedError
|
| 816 |
+
When a SISO LTI system is not passed.
|
| 817 |
+
|
| 818 |
+
When time delay terms are present in the system.
|
| 819 |
+
|
| 820 |
+
ValueError
|
| 821 |
+
When more than one free symbol is present in the system.
|
| 822 |
+
The only variable in the transfer function should be
|
| 823 |
+
the variable of the Laplace transform.
|
| 824 |
+
|
| 825 |
+
When incorrect frequency or phase units are given as input.
|
| 826 |
+
|
| 827 |
+
Examples
|
| 828 |
+
========
|
| 829 |
+
|
| 830 |
+
>>> from sympy.abc import s
|
| 831 |
+
>>> from sympy.physics.control.lti import TransferFunction
|
| 832 |
+
>>> from sympy.physics.control.control_plots import bode_phase_numerical_data
|
| 833 |
+
>>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s)
|
| 834 |
+
>>> bode_phase_numerical_data(tf1) # doctest: +SKIP
|
| 835 |
+
([1e-05, 1.4472354033813751e-05, 2.035581932165858e-05,..., 47577.3248186011, 67884.09326036123, 100000.0],
|
| 836 |
+
[-2.5000000000291665e-05, -3.6180885085e-05, -5.08895483066e-05,...,-3.1415085799262523, -3.14155265358979])
|
| 837 |
+
|
| 838 |
+
See Also
|
| 839 |
+
========
|
| 840 |
+
|
| 841 |
+
bode_magnitude_plot, bode_phase_numerical_data
|
| 842 |
+
|
| 843 |
+
"""
|
| 844 |
+
_check_system(system)
|
| 845 |
+
expr = system.to_expr()
|
| 846 |
+
freq_units = ('rad/sec', 'Hz')
|
| 847 |
+
phase_units = ('rad', 'deg')
|
| 848 |
+
if freq_unit not in freq_units:
|
| 849 |
+
raise ValueError('Only "rad/sec" and "Hz" are accepted frequency units.')
|
| 850 |
+
if phase_unit not in phase_units:
|
| 851 |
+
raise ValueError('Only "rad" and "deg" are accepted phase units.')
|
| 852 |
+
|
| 853 |
+
_w = Dummy("w", real=True)
|
| 854 |
+
if freq_unit == 'Hz':
|
| 855 |
+
repl = I*_w*2*pi
|
| 856 |
+
else:
|
| 857 |
+
repl = I*_w
|
| 858 |
+
w_expr = expr.subs({system.var: repl})
|
| 859 |
+
|
| 860 |
+
if phase_unit == 'deg':
|
| 861 |
+
phase = arg(w_expr)*180/pi
|
| 862 |
+
else:
|
| 863 |
+
phase = arg(w_expr)
|
| 864 |
+
|
| 865 |
+
x, y = LineOver1DRangeSeries(phase,
|
| 866 |
+
(_w, 10**initial_exp, 10**final_exp), xscale='log', **kwargs).get_points()
|
| 867 |
+
|
| 868 |
+
half = None
|
| 869 |
+
if phase_unwrap:
|
| 870 |
+
if(phase_unit == 'rad'):
|
| 871 |
+
half = pi
|
| 872 |
+
elif(phase_unit == 'deg'):
|
| 873 |
+
half = 180
|
| 874 |
+
if half:
|
| 875 |
+
unit = 2*half
|
| 876 |
+
for i in range(1, len(y)):
|
| 877 |
+
diff = y[i] - y[i - 1]
|
| 878 |
+
if diff > half: # Jump from -half to half
|
| 879 |
+
y[i] = (y[i] - unit)
|
| 880 |
+
elif diff < -half: # Jump from half to -half
|
| 881 |
+
y[i] = (y[i] + unit)
|
| 882 |
+
|
| 883 |
+
return x, y
|
| 884 |
+
|
| 885 |
+
|
| 886 |
+
def bode_phase_plot(system, initial_exp=-5, final_exp=5,
|
| 887 |
+
color='b', show_axes=False, grid=True, show=True, freq_unit='rad/sec', phase_unit='rad', phase_unwrap=True, **kwargs):
|
| 888 |
+
r"""
|
| 889 |
+
Returns the Bode phase plot of a continuous-time system.
|
| 890 |
+
|
| 891 |
+
See ``bode_plot`` for all the parameters.
|
| 892 |
+
"""
|
| 893 |
+
x, y = bode_phase_numerical_data(system, initial_exp=initial_exp,
|
| 894 |
+
final_exp=final_exp, freq_unit=freq_unit, phase_unit=phase_unit, phase_unwrap=phase_unwrap)
|
| 895 |
+
plt.plot(x, y, color=color, **kwargs)
|
| 896 |
+
plt.xscale('log')
|
| 897 |
+
|
| 898 |
+
plt.xlabel('Frequency (%s) [Log Scale]' % freq_unit)
|
| 899 |
+
plt.ylabel('Phase (%s)' % phase_unit)
|
| 900 |
+
plt.title(f'Bode Plot (Phase) of ${latex(system)}$', pad=20)
|
| 901 |
+
|
| 902 |
+
if grid:
|
| 903 |
+
plt.grid(True)
|
| 904 |
+
if show_axes:
|
| 905 |
+
plt.axhline(0, color='black')
|
| 906 |
+
plt.axvline(0, color='black')
|
| 907 |
+
if show:
|
| 908 |
+
plt.show()
|
| 909 |
+
return
|
| 910 |
+
|
| 911 |
+
return plt
|
| 912 |
+
|
| 913 |
+
|
| 914 |
+
def bode_plot(system, initial_exp=-5, final_exp=5,
|
| 915 |
+
grid=True, show_axes=False, show=True, freq_unit='rad/sec', phase_unit='rad', phase_unwrap=True, **kwargs):
|
| 916 |
+
r"""
|
| 917 |
+
Returns the Bode phase and magnitude plots of a continuous-time system.
|
| 918 |
+
|
| 919 |
+
Parameters
|
| 920 |
+
==========
|
| 921 |
+
|
| 922 |
+
system : SISOLinearTimeInvariant type
|
| 923 |
+
The LTI SISO system for which the Bode Plot is to be computed.
|
| 924 |
+
initial_exp : Number, optional
|
| 925 |
+
The initial exponent of 10 of the semilog plot. Defaults to -5.
|
| 926 |
+
final_exp : Number, optional
|
| 927 |
+
The final exponent of 10 of the semilog plot. Defaults to 5.
|
| 928 |
+
show : boolean, optional
|
| 929 |
+
If ``True``, the plot will be displayed otherwise
|
| 930 |
+
the equivalent matplotlib ``plot`` object will be returned.
|
| 931 |
+
Defaults to True.
|
| 932 |
+
prec : int, optional
|
| 933 |
+
The decimal point precision for the point coordinate values.
|
| 934 |
+
Defaults to 8.
|
| 935 |
+
grid : boolean, optional
|
| 936 |
+
If ``True``, the plot will have a grid. Defaults to True.
|
| 937 |
+
show_axes : boolean, optional
|
| 938 |
+
If ``True``, the coordinate axes will be shown. Defaults to False.
|
| 939 |
+
freq_unit : string, optional
|
| 940 |
+
User can choose between ``'rad/sec'`` (radians/second) and ``'Hz'`` (Hertz) as frequency units.
|
| 941 |
+
phase_unit : string, optional
|
| 942 |
+
User can choose between ``'rad'`` (radians) and ``'deg'`` (degree) as phase units.
|
| 943 |
+
|
| 944 |
+
Examples
|
| 945 |
+
========
|
| 946 |
+
|
| 947 |
+
.. plot::
|
| 948 |
+
:context: close-figs
|
| 949 |
+
:format: doctest
|
| 950 |
+
:include-source: True
|
| 951 |
+
|
| 952 |
+
>>> from sympy.abc import s
|
| 953 |
+
>>> from sympy.physics.control.lti import TransferFunction
|
| 954 |
+
>>> from sympy.physics.control.control_plots import bode_plot
|
| 955 |
+
>>> tf1 = TransferFunction(1*s**2 + 0.1*s + 7.5, 1*s**4 + 0.12*s**3 + 9*s**2, s)
|
| 956 |
+
>>> bode_plot(tf1, initial_exp=0.2, final_exp=0.7) # doctest: +SKIP
|
| 957 |
+
|
| 958 |
+
See Also
|
| 959 |
+
========
|
| 960 |
+
|
| 961 |
+
bode_magnitude_plot, bode_phase_plot
|
| 962 |
+
|
| 963 |
+
"""
|
| 964 |
+
plt.subplot(211)
|
| 965 |
+
mag = bode_magnitude_plot(system, initial_exp=initial_exp, final_exp=final_exp,
|
| 966 |
+
show=False, grid=grid, show_axes=show_axes,
|
| 967 |
+
freq_unit=freq_unit, **kwargs)
|
| 968 |
+
mag.title(f'Bode Plot of ${latex(system)}$', pad=20)
|
| 969 |
+
mag.xlabel(None)
|
| 970 |
+
plt.subplot(212)
|
| 971 |
+
bode_phase_plot(system, initial_exp=initial_exp, final_exp=final_exp,
|
| 972 |
+
show=False, grid=grid, show_axes=show_axes, freq_unit=freq_unit, phase_unit=phase_unit, phase_unwrap=phase_unwrap, **kwargs).title(None)
|
| 973 |
+
|
| 974 |
+
if show:
|
| 975 |
+
plt.show()
|
| 976 |
+
return
|
| 977 |
+
|
| 978 |
+
return plt
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/tests/test_physics_matrices.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.physics.matrices import msigma, mgamma, minkowski_tensor, pat_matrix, mdft
|
| 2 |
+
from sympy.core.numbers import (I, Rational)
|
| 3 |
+
from sympy.core.singleton import S
|
| 4 |
+
from sympy.functions.elementary.miscellaneous import sqrt
|
| 5 |
+
from sympy.matrices.dense import (Matrix, eye, zeros)
|
| 6 |
+
from sympy.testing.pytest import warns_deprecated_sympy
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def test_parallel_axis_theorem():
|
| 10 |
+
# This tests the parallel axis theorem matrix by comparing to test
|
| 11 |
+
# matrices.
|
| 12 |
+
|
| 13 |
+
# First case, 1 in all directions.
|
| 14 |
+
mat1 = Matrix(((2, -1, -1), (-1, 2, -1), (-1, -1, 2)))
|
| 15 |
+
assert pat_matrix(1, 1, 1, 1) == mat1
|
| 16 |
+
assert pat_matrix(2, 1, 1, 1) == 2*mat1
|
| 17 |
+
|
| 18 |
+
# Second case, 1 in x, 0 in all others
|
| 19 |
+
mat2 = Matrix(((0, 0, 0), (0, 1, 0), (0, 0, 1)))
|
| 20 |
+
assert pat_matrix(1, 1, 0, 0) == mat2
|
| 21 |
+
assert pat_matrix(2, 1, 0, 0) == 2*mat2
|
| 22 |
+
|
| 23 |
+
# Third case, 1 in y, 0 in all others
|
| 24 |
+
mat3 = Matrix(((1, 0, 0), (0, 0, 0), (0, 0, 1)))
|
| 25 |
+
assert pat_matrix(1, 0, 1, 0) == mat3
|
| 26 |
+
assert pat_matrix(2, 0, 1, 0) == 2*mat3
|
| 27 |
+
|
| 28 |
+
# Fourth case, 1 in z, 0 in all others
|
| 29 |
+
mat4 = Matrix(((1, 0, 0), (0, 1, 0), (0, 0, 0)))
|
| 30 |
+
assert pat_matrix(1, 0, 0, 1) == mat4
|
| 31 |
+
assert pat_matrix(2, 0, 0, 1) == 2*mat4
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def test_Pauli():
|
| 35 |
+
#this and the following test are testing both Pauli and Dirac matrices
|
| 36 |
+
#and also that the general Matrix class works correctly in a real world
|
| 37 |
+
#situation
|
| 38 |
+
sigma1 = msigma(1)
|
| 39 |
+
sigma2 = msigma(2)
|
| 40 |
+
sigma3 = msigma(3)
|
| 41 |
+
|
| 42 |
+
assert sigma1 == sigma1
|
| 43 |
+
assert sigma1 != sigma2
|
| 44 |
+
|
| 45 |
+
# sigma*I -> I*sigma (see #354)
|
| 46 |
+
assert sigma1*sigma2 == sigma3*I
|
| 47 |
+
assert sigma3*sigma1 == sigma2*I
|
| 48 |
+
assert sigma2*sigma3 == sigma1*I
|
| 49 |
+
|
| 50 |
+
assert sigma1*sigma1 == eye(2)
|
| 51 |
+
assert sigma2*sigma2 == eye(2)
|
| 52 |
+
assert sigma3*sigma3 == eye(2)
|
| 53 |
+
|
| 54 |
+
assert sigma1*2*sigma1 == 2*eye(2)
|
| 55 |
+
assert sigma1*sigma3*sigma1 == -sigma3
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def test_Dirac():
|
| 59 |
+
gamma0 = mgamma(0)
|
| 60 |
+
gamma1 = mgamma(1)
|
| 61 |
+
gamma2 = mgamma(2)
|
| 62 |
+
gamma3 = mgamma(3)
|
| 63 |
+
gamma5 = mgamma(5)
|
| 64 |
+
|
| 65 |
+
# gamma*I -> I*gamma (see #354)
|
| 66 |
+
assert gamma5 == gamma0 * gamma1 * gamma2 * gamma3 * I
|
| 67 |
+
assert gamma1 * gamma2 + gamma2 * gamma1 == zeros(4)
|
| 68 |
+
assert gamma0 * gamma0 == eye(4) * minkowski_tensor[0, 0]
|
| 69 |
+
assert gamma2 * gamma2 != eye(4) * minkowski_tensor[0, 0]
|
| 70 |
+
assert gamma2 * gamma2 == eye(4) * minkowski_tensor[2, 2]
|
| 71 |
+
|
| 72 |
+
assert mgamma(5, True) == \
|
| 73 |
+
mgamma(0, True)*mgamma(1, True)*mgamma(2, True)*mgamma(3, True)*I
|
| 74 |
+
|
| 75 |
+
def test_mdft():
|
| 76 |
+
with warns_deprecated_sympy():
|
| 77 |
+
assert mdft(1) == Matrix([[1]])
|
| 78 |
+
with warns_deprecated_sympy():
|
| 79 |
+
assert mdft(2) == 1/sqrt(2)*Matrix([[1,1],[1,-1]])
|
| 80 |
+
with warns_deprecated_sympy():
|
| 81 |
+
assert mdft(4) == Matrix([[S.Half, S.Half, S.Half, S.Half],
|
| 82 |
+
[S.Half, -I/2, Rational(-1,2), I/2],
|
| 83 |
+
[S.Half, Rational(-1,2), S.Half, Rational(-1,2)],
|
| 84 |
+
[S.Half, I/2, Rational(-1,2), -I/2]])
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__init__.py
ADDED
|
@@ -0,0 +1,453 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# isort:skip_file
|
| 2 |
+
"""
|
| 3 |
+
Dimensional analysis and unit systems.
|
| 4 |
+
|
| 5 |
+
This module defines dimension/unit systems and physical quantities. It is
|
| 6 |
+
based on a group-theoretical construction where dimensions are represented as
|
| 7 |
+
vectors (coefficients being the exponents), and units are defined as a dimension
|
| 8 |
+
to which we added a scale.
|
| 9 |
+
|
| 10 |
+
Quantities are built from a factor and a unit, and are the basic objects that
|
| 11 |
+
one will use when doing computations.
|
| 12 |
+
|
| 13 |
+
All objects except systems and prefixes can be used in SymPy expressions.
|
| 14 |
+
Note that as part of a CAS, various objects do not combine automatically
|
| 15 |
+
under operations.
|
| 16 |
+
|
| 17 |
+
Details about the implementation can be found in the documentation, and we
|
| 18 |
+
will not repeat all the explanations we gave there concerning our approach.
|
| 19 |
+
Ideas about future developments can be found on the `Github wiki
|
| 20 |
+
<https://github.com/sympy/sympy/wiki/Unit-systems>`_, and you should consult
|
| 21 |
+
this page if you are willing to help.
|
| 22 |
+
|
| 23 |
+
Useful functions:
|
| 24 |
+
|
| 25 |
+
- ``find_unit``: easily lookup pre-defined units.
|
| 26 |
+
- ``convert_to(expr, newunit)``: converts an expression into the same
|
| 27 |
+
expression expressed in another unit.
|
| 28 |
+
|
| 29 |
+
"""
|
| 30 |
+
|
| 31 |
+
from .dimensions import Dimension, DimensionSystem
|
| 32 |
+
from .unitsystem import UnitSystem
|
| 33 |
+
from .util import convert_to
|
| 34 |
+
from .quantities import Quantity
|
| 35 |
+
|
| 36 |
+
from .definitions.dimension_definitions import (
|
| 37 |
+
amount_of_substance, acceleration, action, area,
|
| 38 |
+
capacitance, charge, conductance, current, energy,
|
| 39 |
+
force, frequency, impedance, inductance, length,
|
| 40 |
+
luminous_intensity, magnetic_density,
|
| 41 |
+
magnetic_flux, mass, momentum, power, pressure, temperature, time,
|
| 42 |
+
velocity, voltage, volume
|
| 43 |
+
)
|
| 44 |
+
|
| 45 |
+
Unit = Quantity
|
| 46 |
+
|
| 47 |
+
speed = velocity
|
| 48 |
+
luminosity = luminous_intensity
|
| 49 |
+
magnetic_flux_density = magnetic_density
|
| 50 |
+
amount = amount_of_substance
|
| 51 |
+
|
| 52 |
+
from .prefixes import (
|
| 53 |
+
# 10-power based:
|
| 54 |
+
yotta,
|
| 55 |
+
zetta,
|
| 56 |
+
exa,
|
| 57 |
+
peta,
|
| 58 |
+
tera,
|
| 59 |
+
giga,
|
| 60 |
+
mega,
|
| 61 |
+
kilo,
|
| 62 |
+
hecto,
|
| 63 |
+
deca,
|
| 64 |
+
deci,
|
| 65 |
+
centi,
|
| 66 |
+
milli,
|
| 67 |
+
micro,
|
| 68 |
+
nano,
|
| 69 |
+
pico,
|
| 70 |
+
femto,
|
| 71 |
+
atto,
|
| 72 |
+
zepto,
|
| 73 |
+
yocto,
|
| 74 |
+
# 2-power based:
|
| 75 |
+
kibi,
|
| 76 |
+
mebi,
|
| 77 |
+
gibi,
|
| 78 |
+
tebi,
|
| 79 |
+
pebi,
|
| 80 |
+
exbi,
|
| 81 |
+
)
|
| 82 |
+
|
| 83 |
+
from .definitions import (
|
| 84 |
+
percent, percents,
|
| 85 |
+
permille,
|
| 86 |
+
rad, radian, radians,
|
| 87 |
+
deg, degree, degrees,
|
| 88 |
+
sr, steradian, steradians,
|
| 89 |
+
mil, angular_mil, angular_mils,
|
| 90 |
+
m, meter, meters,
|
| 91 |
+
kg, kilogram, kilograms,
|
| 92 |
+
s, second, seconds,
|
| 93 |
+
A, ampere, amperes,
|
| 94 |
+
K, kelvin, kelvins,
|
| 95 |
+
mol, mole, moles,
|
| 96 |
+
cd, candela, candelas,
|
| 97 |
+
g, gram, grams,
|
| 98 |
+
mg, milligram, milligrams,
|
| 99 |
+
ug, microgram, micrograms,
|
| 100 |
+
t, tonne, metric_ton,
|
| 101 |
+
newton, newtons, N,
|
| 102 |
+
joule, joules, J,
|
| 103 |
+
watt, watts, W,
|
| 104 |
+
pascal, pascals, Pa, pa,
|
| 105 |
+
hertz, hz, Hz,
|
| 106 |
+
coulomb, coulombs, C,
|
| 107 |
+
volt, volts, v, V,
|
| 108 |
+
ohm, ohms,
|
| 109 |
+
siemens, S, mho, mhos,
|
| 110 |
+
farad, farads, F,
|
| 111 |
+
henry, henrys, H,
|
| 112 |
+
tesla, teslas, T,
|
| 113 |
+
weber, webers, Wb, wb,
|
| 114 |
+
optical_power, dioptre, D,
|
| 115 |
+
lux, lx,
|
| 116 |
+
katal, kat,
|
| 117 |
+
gray, Gy,
|
| 118 |
+
becquerel, Bq,
|
| 119 |
+
km, kilometer, kilometers,
|
| 120 |
+
dm, decimeter, decimeters,
|
| 121 |
+
cm, centimeter, centimeters,
|
| 122 |
+
mm, millimeter, millimeters,
|
| 123 |
+
um, micrometer, micrometers, micron, microns,
|
| 124 |
+
nm, nanometer, nanometers,
|
| 125 |
+
pm, picometer, picometers,
|
| 126 |
+
ft, foot, feet,
|
| 127 |
+
inch, inches,
|
| 128 |
+
yd, yard, yards,
|
| 129 |
+
mi, mile, miles,
|
| 130 |
+
nmi, nautical_mile, nautical_miles,
|
| 131 |
+
angstrom, angstroms,
|
| 132 |
+
ha, hectare,
|
| 133 |
+
l, L, liter, liters,
|
| 134 |
+
dl, dL, deciliter, deciliters,
|
| 135 |
+
cl, cL, centiliter, centiliters,
|
| 136 |
+
ml, mL, milliliter, milliliters,
|
| 137 |
+
ms, millisecond, milliseconds,
|
| 138 |
+
us, microsecond, microseconds,
|
| 139 |
+
ns, nanosecond, nanoseconds,
|
| 140 |
+
ps, picosecond, picoseconds,
|
| 141 |
+
minute, minutes,
|
| 142 |
+
h, hour, hours,
|
| 143 |
+
day, days,
|
| 144 |
+
anomalistic_year, anomalistic_years,
|
| 145 |
+
sidereal_year, sidereal_years,
|
| 146 |
+
tropical_year, tropical_years,
|
| 147 |
+
common_year, common_years,
|
| 148 |
+
julian_year, julian_years,
|
| 149 |
+
draconic_year, draconic_years,
|
| 150 |
+
gaussian_year, gaussian_years,
|
| 151 |
+
full_moon_cycle, full_moon_cycles,
|
| 152 |
+
year, years,
|
| 153 |
+
G, gravitational_constant,
|
| 154 |
+
c, speed_of_light,
|
| 155 |
+
elementary_charge,
|
| 156 |
+
hbar,
|
| 157 |
+
planck,
|
| 158 |
+
eV, electronvolt, electronvolts,
|
| 159 |
+
avogadro_number,
|
| 160 |
+
avogadro, avogadro_constant,
|
| 161 |
+
boltzmann, boltzmann_constant,
|
| 162 |
+
stefan, stefan_boltzmann_constant,
|
| 163 |
+
R, molar_gas_constant,
|
| 164 |
+
faraday_constant,
|
| 165 |
+
josephson_constant,
|
| 166 |
+
von_klitzing_constant,
|
| 167 |
+
Da, dalton, amu, amus, atomic_mass_unit, atomic_mass_constant,
|
| 168 |
+
me, electron_rest_mass,
|
| 169 |
+
gee, gees, acceleration_due_to_gravity,
|
| 170 |
+
u0, magnetic_constant, vacuum_permeability,
|
| 171 |
+
e0, electric_constant, vacuum_permittivity,
|
| 172 |
+
Z0, vacuum_impedance,
|
| 173 |
+
coulomb_constant, electric_force_constant,
|
| 174 |
+
atmosphere, atmospheres, atm,
|
| 175 |
+
kPa,
|
| 176 |
+
bar, bars,
|
| 177 |
+
pound, pounds,
|
| 178 |
+
psi,
|
| 179 |
+
dHg0,
|
| 180 |
+
mmHg, torr,
|
| 181 |
+
mmu, mmus, milli_mass_unit,
|
| 182 |
+
quart, quarts,
|
| 183 |
+
ly, lightyear, lightyears,
|
| 184 |
+
au, astronomical_unit, astronomical_units,
|
| 185 |
+
planck_mass,
|
| 186 |
+
planck_time,
|
| 187 |
+
planck_temperature,
|
| 188 |
+
planck_length,
|
| 189 |
+
planck_charge,
|
| 190 |
+
planck_area,
|
| 191 |
+
planck_volume,
|
| 192 |
+
planck_momentum,
|
| 193 |
+
planck_energy,
|
| 194 |
+
planck_force,
|
| 195 |
+
planck_power,
|
| 196 |
+
planck_density,
|
| 197 |
+
planck_energy_density,
|
| 198 |
+
planck_intensity,
|
| 199 |
+
planck_angular_frequency,
|
| 200 |
+
planck_pressure,
|
| 201 |
+
planck_current,
|
| 202 |
+
planck_voltage,
|
| 203 |
+
planck_impedance,
|
| 204 |
+
planck_acceleration,
|
| 205 |
+
bit, bits,
|
| 206 |
+
byte,
|
| 207 |
+
kibibyte, kibibytes,
|
| 208 |
+
mebibyte, mebibytes,
|
| 209 |
+
gibibyte, gibibytes,
|
| 210 |
+
tebibyte, tebibytes,
|
| 211 |
+
pebibyte, pebibytes,
|
| 212 |
+
exbibyte, exbibytes,
|
| 213 |
+
)
|
| 214 |
+
|
| 215 |
+
from .systems import (
|
| 216 |
+
mks, mksa, si
|
| 217 |
+
)
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
def find_unit(quantity, unit_system="SI"):
|
| 221 |
+
"""
|
| 222 |
+
Return a list of matching units or dimension names.
|
| 223 |
+
|
| 224 |
+
- If ``quantity`` is a string -- units/dimensions containing the string
|
| 225 |
+
`quantity`.
|
| 226 |
+
- If ``quantity`` is a unit or dimension -- units having matching base
|
| 227 |
+
units or dimensions.
|
| 228 |
+
|
| 229 |
+
Examples
|
| 230 |
+
========
|
| 231 |
+
|
| 232 |
+
>>> from sympy.physics import units as u
|
| 233 |
+
>>> u.find_unit('charge')
|
| 234 |
+
['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge']
|
| 235 |
+
>>> u.find_unit(u.charge)
|
| 236 |
+
['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge']
|
| 237 |
+
>>> u.find_unit("ampere")
|
| 238 |
+
['ampere', 'amperes']
|
| 239 |
+
>>> u.find_unit('angstrom')
|
| 240 |
+
['angstrom', 'angstroms']
|
| 241 |
+
>>> u.find_unit('volt')
|
| 242 |
+
['volt', 'volts', 'electronvolt', 'electronvolts', 'planck_voltage']
|
| 243 |
+
>>> u.find_unit(u.inch**3)[:9]
|
| 244 |
+
['L', 'l', 'cL', 'cl', 'dL', 'dl', 'mL', 'ml', 'liter']
|
| 245 |
+
"""
|
| 246 |
+
unit_system = UnitSystem.get_unit_system(unit_system)
|
| 247 |
+
|
| 248 |
+
import sympy.physics.units as u
|
| 249 |
+
rv = []
|
| 250 |
+
if isinstance(quantity, str):
|
| 251 |
+
rv = [i for i in dir(u) if quantity in i and isinstance(getattr(u, i), Quantity)]
|
| 252 |
+
dim = getattr(u, quantity)
|
| 253 |
+
if isinstance(dim, Dimension):
|
| 254 |
+
rv.extend(find_unit(dim))
|
| 255 |
+
else:
|
| 256 |
+
for i in sorted(dir(u)):
|
| 257 |
+
other = getattr(u, i)
|
| 258 |
+
if not isinstance(other, Quantity):
|
| 259 |
+
continue
|
| 260 |
+
if isinstance(quantity, Quantity):
|
| 261 |
+
if quantity.dimension == other.dimension:
|
| 262 |
+
rv.append(str(i))
|
| 263 |
+
elif isinstance(quantity, Dimension):
|
| 264 |
+
if other.dimension == quantity:
|
| 265 |
+
rv.append(str(i))
|
| 266 |
+
elif other.dimension == Dimension(unit_system.get_dimensional_expr(quantity)):
|
| 267 |
+
rv.append(str(i))
|
| 268 |
+
return sorted(set(rv), key=lambda x: (len(x), x))
|
| 269 |
+
|
| 270 |
+
# NOTE: the old units module had additional variables:
|
| 271 |
+
# 'density', 'illuminance', 'resistance'.
|
| 272 |
+
# They were not dimensions, but units (old Unit class).
|
| 273 |
+
|
| 274 |
+
__all__ = [
|
| 275 |
+
'Dimension', 'DimensionSystem',
|
| 276 |
+
'UnitSystem',
|
| 277 |
+
'convert_to',
|
| 278 |
+
'Quantity',
|
| 279 |
+
|
| 280 |
+
'amount_of_substance', 'acceleration', 'action', 'area',
|
| 281 |
+
'capacitance', 'charge', 'conductance', 'current', 'energy',
|
| 282 |
+
'force', 'frequency', 'impedance', 'inductance', 'length',
|
| 283 |
+
'luminous_intensity', 'magnetic_density',
|
| 284 |
+
'magnetic_flux', 'mass', 'momentum', 'power', 'pressure', 'temperature', 'time',
|
| 285 |
+
'velocity', 'voltage', 'volume',
|
| 286 |
+
|
| 287 |
+
'Unit',
|
| 288 |
+
|
| 289 |
+
'speed',
|
| 290 |
+
'luminosity',
|
| 291 |
+
'magnetic_flux_density',
|
| 292 |
+
'amount',
|
| 293 |
+
|
| 294 |
+
'yotta',
|
| 295 |
+
'zetta',
|
| 296 |
+
'exa',
|
| 297 |
+
'peta',
|
| 298 |
+
'tera',
|
| 299 |
+
'giga',
|
| 300 |
+
'mega',
|
| 301 |
+
'kilo',
|
| 302 |
+
'hecto',
|
| 303 |
+
'deca',
|
| 304 |
+
'deci',
|
| 305 |
+
'centi',
|
| 306 |
+
'milli',
|
| 307 |
+
'micro',
|
| 308 |
+
'nano',
|
| 309 |
+
'pico',
|
| 310 |
+
'femto',
|
| 311 |
+
'atto',
|
| 312 |
+
'zepto',
|
| 313 |
+
'yocto',
|
| 314 |
+
|
| 315 |
+
'kibi',
|
| 316 |
+
'mebi',
|
| 317 |
+
'gibi',
|
| 318 |
+
'tebi',
|
| 319 |
+
'pebi',
|
| 320 |
+
'exbi',
|
| 321 |
+
|
| 322 |
+
'percent', 'percents',
|
| 323 |
+
'permille',
|
| 324 |
+
'rad', 'radian', 'radians',
|
| 325 |
+
'deg', 'degree', 'degrees',
|
| 326 |
+
'sr', 'steradian', 'steradians',
|
| 327 |
+
'mil', 'angular_mil', 'angular_mils',
|
| 328 |
+
'm', 'meter', 'meters',
|
| 329 |
+
'kg', 'kilogram', 'kilograms',
|
| 330 |
+
's', 'second', 'seconds',
|
| 331 |
+
'A', 'ampere', 'amperes',
|
| 332 |
+
'K', 'kelvin', 'kelvins',
|
| 333 |
+
'mol', 'mole', 'moles',
|
| 334 |
+
'cd', 'candela', 'candelas',
|
| 335 |
+
'g', 'gram', 'grams',
|
| 336 |
+
'mg', 'milligram', 'milligrams',
|
| 337 |
+
'ug', 'microgram', 'micrograms',
|
| 338 |
+
't', 'tonne', 'metric_ton',
|
| 339 |
+
'newton', 'newtons', 'N',
|
| 340 |
+
'joule', 'joules', 'J',
|
| 341 |
+
'watt', 'watts', 'W',
|
| 342 |
+
'pascal', 'pascals', 'Pa', 'pa',
|
| 343 |
+
'hertz', 'hz', 'Hz',
|
| 344 |
+
'coulomb', 'coulombs', 'C',
|
| 345 |
+
'volt', 'volts', 'v', 'V',
|
| 346 |
+
'ohm', 'ohms',
|
| 347 |
+
'siemens', 'S', 'mho', 'mhos',
|
| 348 |
+
'farad', 'farads', 'F',
|
| 349 |
+
'henry', 'henrys', 'H',
|
| 350 |
+
'tesla', 'teslas', 'T',
|
| 351 |
+
'weber', 'webers', 'Wb', 'wb',
|
| 352 |
+
'optical_power', 'dioptre', 'D',
|
| 353 |
+
'lux', 'lx',
|
| 354 |
+
'katal', 'kat',
|
| 355 |
+
'gray', 'Gy',
|
| 356 |
+
'becquerel', 'Bq',
|
| 357 |
+
'km', 'kilometer', 'kilometers',
|
| 358 |
+
'dm', 'decimeter', 'decimeters',
|
| 359 |
+
'cm', 'centimeter', 'centimeters',
|
| 360 |
+
'mm', 'millimeter', 'millimeters',
|
| 361 |
+
'um', 'micrometer', 'micrometers', 'micron', 'microns',
|
| 362 |
+
'nm', 'nanometer', 'nanometers',
|
| 363 |
+
'pm', 'picometer', 'picometers',
|
| 364 |
+
'ft', 'foot', 'feet',
|
| 365 |
+
'inch', 'inches',
|
| 366 |
+
'yd', 'yard', 'yards',
|
| 367 |
+
'mi', 'mile', 'miles',
|
| 368 |
+
'nmi', 'nautical_mile', 'nautical_miles',
|
| 369 |
+
'angstrom', 'angstroms',
|
| 370 |
+
'ha', 'hectare',
|
| 371 |
+
'l', 'L', 'liter', 'liters',
|
| 372 |
+
'dl', 'dL', 'deciliter', 'deciliters',
|
| 373 |
+
'cl', 'cL', 'centiliter', 'centiliters',
|
| 374 |
+
'ml', 'mL', 'milliliter', 'milliliters',
|
| 375 |
+
'ms', 'millisecond', 'milliseconds',
|
| 376 |
+
'us', 'microsecond', 'microseconds',
|
| 377 |
+
'ns', 'nanosecond', 'nanoseconds',
|
| 378 |
+
'ps', 'picosecond', 'picoseconds',
|
| 379 |
+
'minute', 'minutes',
|
| 380 |
+
'h', 'hour', 'hours',
|
| 381 |
+
'day', 'days',
|
| 382 |
+
'anomalistic_year', 'anomalistic_years',
|
| 383 |
+
'sidereal_year', 'sidereal_years',
|
| 384 |
+
'tropical_year', 'tropical_years',
|
| 385 |
+
'common_year', 'common_years',
|
| 386 |
+
'julian_year', 'julian_years',
|
| 387 |
+
'draconic_year', 'draconic_years',
|
| 388 |
+
'gaussian_year', 'gaussian_years',
|
| 389 |
+
'full_moon_cycle', 'full_moon_cycles',
|
| 390 |
+
'year', 'years',
|
| 391 |
+
'G', 'gravitational_constant',
|
| 392 |
+
'c', 'speed_of_light',
|
| 393 |
+
'elementary_charge',
|
| 394 |
+
'hbar',
|
| 395 |
+
'planck',
|
| 396 |
+
'eV', 'electronvolt', 'electronvolts',
|
| 397 |
+
'avogadro_number',
|
| 398 |
+
'avogadro', 'avogadro_constant',
|
| 399 |
+
'boltzmann', 'boltzmann_constant',
|
| 400 |
+
'stefan', 'stefan_boltzmann_constant',
|
| 401 |
+
'R', 'molar_gas_constant',
|
| 402 |
+
'faraday_constant',
|
| 403 |
+
'josephson_constant',
|
| 404 |
+
'von_klitzing_constant',
|
| 405 |
+
'Da', 'dalton', 'amu', 'amus', 'atomic_mass_unit', 'atomic_mass_constant',
|
| 406 |
+
'me', 'electron_rest_mass',
|
| 407 |
+
'gee', 'gees', 'acceleration_due_to_gravity',
|
| 408 |
+
'u0', 'magnetic_constant', 'vacuum_permeability',
|
| 409 |
+
'e0', 'electric_constant', 'vacuum_permittivity',
|
| 410 |
+
'Z0', 'vacuum_impedance',
|
| 411 |
+
'coulomb_constant', 'electric_force_constant',
|
| 412 |
+
'atmosphere', 'atmospheres', 'atm',
|
| 413 |
+
'kPa',
|
| 414 |
+
'bar', 'bars',
|
| 415 |
+
'pound', 'pounds',
|
| 416 |
+
'psi',
|
| 417 |
+
'dHg0',
|
| 418 |
+
'mmHg', 'torr',
|
| 419 |
+
'mmu', 'mmus', 'milli_mass_unit',
|
| 420 |
+
'quart', 'quarts',
|
| 421 |
+
'ly', 'lightyear', 'lightyears',
|
| 422 |
+
'au', 'astronomical_unit', 'astronomical_units',
|
| 423 |
+
'planck_mass',
|
| 424 |
+
'planck_time',
|
| 425 |
+
'planck_temperature',
|
| 426 |
+
'planck_length',
|
| 427 |
+
'planck_charge',
|
| 428 |
+
'planck_area',
|
| 429 |
+
'planck_volume',
|
| 430 |
+
'planck_momentum',
|
| 431 |
+
'planck_energy',
|
| 432 |
+
'planck_force',
|
| 433 |
+
'planck_power',
|
| 434 |
+
'planck_density',
|
| 435 |
+
'planck_energy_density',
|
| 436 |
+
'planck_intensity',
|
| 437 |
+
'planck_angular_frequency',
|
| 438 |
+
'planck_pressure',
|
| 439 |
+
'planck_current',
|
| 440 |
+
'planck_voltage',
|
| 441 |
+
'planck_impedance',
|
| 442 |
+
'planck_acceleration',
|
| 443 |
+
'bit', 'bits',
|
| 444 |
+
'byte',
|
| 445 |
+
'kibibyte', 'kibibytes',
|
| 446 |
+
'mebibyte', 'mebibytes',
|
| 447 |
+
'gibibyte', 'gibibytes',
|
| 448 |
+
'tebibyte', 'tebibytes',
|
| 449 |
+
'pebibyte', 'pebibytes',
|
| 450 |
+
'exbibyte', 'exbibytes',
|
| 451 |
+
|
| 452 |
+
'mks', 'mksa', 'si',
|
| 453 |
+
]
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (17.8 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__pycache__/prefixes.cpython-311.pyc
ADDED
|
Binary file (9.54 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__pycache__/quantities.cpython-311.pyc
ADDED
|
Binary file (7.38 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/definitions/__init__.py
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .unit_definitions import (
|
| 2 |
+
percent, percents,
|
| 3 |
+
permille,
|
| 4 |
+
rad, radian, radians,
|
| 5 |
+
deg, degree, degrees,
|
| 6 |
+
sr, steradian, steradians,
|
| 7 |
+
mil, angular_mil, angular_mils,
|
| 8 |
+
m, meter, meters,
|
| 9 |
+
kg, kilogram, kilograms,
|
| 10 |
+
s, second, seconds,
|
| 11 |
+
A, ampere, amperes,
|
| 12 |
+
K, kelvin, kelvins,
|
| 13 |
+
mol, mole, moles,
|
| 14 |
+
cd, candela, candelas,
|
| 15 |
+
g, gram, grams,
|
| 16 |
+
mg, milligram, milligrams,
|
| 17 |
+
ug, microgram, micrograms,
|
| 18 |
+
t, tonne, metric_ton,
|
| 19 |
+
newton, newtons, N,
|
| 20 |
+
joule, joules, J,
|
| 21 |
+
watt, watts, W,
|
| 22 |
+
pascal, pascals, Pa, pa,
|
| 23 |
+
hertz, hz, Hz,
|
| 24 |
+
coulomb, coulombs, C,
|
| 25 |
+
volt, volts, v, V,
|
| 26 |
+
ohm, ohms,
|
| 27 |
+
siemens, S, mho, mhos,
|
| 28 |
+
farad, farads, F,
|
| 29 |
+
henry, henrys, H,
|
| 30 |
+
tesla, teslas, T,
|
| 31 |
+
weber, webers, Wb, wb,
|
| 32 |
+
optical_power, dioptre, D,
|
| 33 |
+
lux, lx,
|
| 34 |
+
katal, kat,
|
| 35 |
+
gray, Gy,
|
| 36 |
+
becquerel, Bq,
|
| 37 |
+
km, kilometer, kilometers,
|
| 38 |
+
dm, decimeter, decimeters,
|
| 39 |
+
cm, centimeter, centimeters,
|
| 40 |
+
mm, millimeter, millimeters,
|
| 41 |
+
um, micrometer, micrometers, micron, microns,
|
| 42 |
+
nm, nanometer, nanometers,
|
| 43 |
+
pm, picometer, picometers,
|
| 44 |
+
ft, foot, feet,
|
| 45 |
+
inch, inches,
|
| 46 |
+
yd, yard, yards,
|
| 47 |
+
mi, mile, miles,
|
| 48 |
+
nmi, nautical_mile, nautical_miles,
|
| 49 |
+
ha, hectare,
|
| 50 |
+
l, L, liter, liters,
|
| 51 |
+
dl, dL, deciliter, deciliters,
|
| 52 |
+
cl, cL, centiliter, centiliters,
|
| 53 |
+
ml, mL, milliliter, milliliters,
|
| 54 |
+
ms, millisecond, milliseconds,
|
| 55 |
+
us, microsecond, microseconds,
|
| 56 |
+
ns, nanosecond, nanoseconds,
|
| 57 |
+
ps, picosecond, picoseconds,
|
| 58 |
+
minute, minutes,
|
| 59 |
+
h, hour, hours,
|
| 60 |
+
day, days,
|
| 61 |
+
anomalistic_year, anomalistic_years,
|
| 62 |
+
sidereal_year, sidereal_years,
|
| 63 |
+
tropical_year, tropical_years,
|
| 64 |
+
common_year, common_years,
|
| 65 |
+
julian_year, julian_years,
|
| 66 |
+
draconic_year, draconic_years,
|
| 67 |
+
gaussian_year, gaussian_years,
|
| 68 |
+
full_moon_cycle, full_moon_cycles,
|
| 69 |
+
year, years,
|
| 70 |
+
G, gravitational_constant,
|
| 71 |
+
c, speed_of_light,
|
| 72 |
+
elementary_charge,
|
| 73 |
+
hbar,
|
| 74 |
+
planck,
|
| 75 |
+
eV, electronvolt, electronvolts,
|
| 76 |
+
avogadro_number,
|
| 77 |
+
avogadro, avogadro_constant,
|
| 78 |
+
boltzmann, boltzmann_constant,
|
| 79 |
+
stefan, stefan_boltzmann_constant,
|
| 80 |
+
R, molar_gas_constant,
|
| 81 |
+
faraday_constant,
|
| 82 |
+
josephson_constant,
|
| 83 |
+
von_klitzing_constant,
|
| 84 |
+
Da, dalton, amu, amus, atomic_mass_unit, atomic_mass_constant,
|
| 85 |
+
me, electron_rest_mass,
|
| 86 |
+
gee, gees, acceleration_due_to_gravity,
|
| 87 |
+
u0, magnetic_constant, vacuum_permeability,
|
| 88 |
+
e0, electric_constant, vacuum_permittivity,
|
| 89 |
+
Z0, vacuum_impedance,
|
| 90 |
+
coulomb_constant, coulombs_constant, electric_force_constant,
|
| 91 |
+
atmosphere, atmospheres, atm,
|
| 92 |
+
kPa, kilopascal,
|
| 93 |
+
bar, bars,
|
| 94 |
+
pound, pounds,
|
| 95 |
+
psi,
|
| 96 |
+
dHg0,
|
| 97 |
+
mmHg, torr,
|
| 98 |
+
mmu, mmus, milli_mass_unit,
|
| 99 |
+
quart, quarts,
|
| 100 |
+
angstrom, angstroms,
|
| 101 |
+
ly, lightyear, lightyears,
|
| 102 |
+
au, astronomical_unit, astronomical_units,
|
| 103 |
+
planck_mass,
|
| 104 |
+
planck_time,
|
| 105 |
+
planck_temperature,
|
| 106 |
+
planck_length,
|
| 107 |
+
planck_charge,
|
| 108 |
+
planck_area,
|
| 109 |
+
planck_volume,
|
| 110 |
+
planck_momentum,
|
| 111 |
+
planck_energy,
|
| 112 |
+
planck_force,
|
| 113 |
+
planck_power,
|
| 114 |
+
planck_density,
|
| 115 |
+
planck_energy_density,
|
| 116 |
+
planck_intensity,
|
| 117 |
+
planck_angular_frequency,
|
| 118 |
+
planck_pressure,
|
| 119 |
+
planck_current,
|
| 120 |
+
planck_voltage,
|
| 121 |
+
planck_impedance,
|
| 122 |
+
planck_acceleration,
|
| 123 |
+
bit, bits,
|
| 124 |
+
byte,
|
| 125 |
+
kibibyte, kibibytes,
|
| 126 |
+
mebibyte, mebibytes,
|
| 127 |
+
gibibyte, gibibytes,
|
| 128 |
+
tebibyte, tebibytes,
|
| 129 |
+
pebibyte, pebibytes,
|
| 130 |
+
exbibyte, exbibytes,
|
| 131 |
+
curie, rutherford
|
| 132 |
+
)
|
| 133 |
+
|
| 134 |
+
__all__ = [
|
| 135 |
+
'percent', 'percents',
|
| 136 |
+
'permille',
|
| 137 |
+
'rad', 'radian', 'radians',
|
| 138 |
+
'deg', 'degree', 'degrees',
|
| 139 |
+
'sr', 'steradian', 'steradians',
|
| 140 |
+
'mil', 'angular_mil', 'angular_mils',
|
| 141 |
+
'm', 'meter', 'meters',
|
| 142 |
+
'kg', 'kilogram', 'kilograms',
|
| 143 |
+
's', 'second', 'seconds',
|
| 144 |
+
'A', 'ampere', 'amperes',
|
| 145 |
+
'K', 'kelvin', 'kelvins',
|
| 146 |
+
'mol', 'mole', 'moles',
|
| 147 |
+
'cd', 'candela', 'candelas',
|
| 148 |
+
'g', 'gram', 'grams',
|
| 149 |
+
'mg', 'milligram', 'milligrams',
|
| 150 |
+
'ug', 'microgram', 'micrograms',
|
| 151 |
+
't', 'tonne', 'metric_ton',
|
| 152 |
+
'newton', 'newtons', 'N',
|
| 153 |
+
'joule', 'joules', 'J',
|
| 154 |
+
'watt', 'watts', 'W',
|
| 155 |
+
'pascal', 'pascals', 'Pa', 'pa',
|
| 156 |
+
'hertz', 'hz', 'Hz',
|
| 157 |
+
'coulomb', 'coulombs', 'C',
|
| 158 |
+
'volt', 'volts', 'v', 'V',
|
| 159 |
+
'ohm', 'ohms',
|
| 160 |
+
'siemens', 'S', 'mho', 'mhos',
|
| 161 |
+
'farad', 'farads', 'F',
|
| 162 |
+
'henry', 'henrys', 'H',
|
| 163 |
+
'tesla', 'teslas', 'T',
|
| 164 |
+
'weber', 'webers', 'Wb', 'wb',
|
| 165 |
+
'optical_power', 'dioptre', 'D',
|
| 166 |
+
'lux', 'lx',
|
| 167 |
+
'katal', 'kat',
|
| 168 |
+
'gray', 'Gy',
|
| 169 |
+
'becquerel', 'Bq',
|
| 170 |
+
'km', 'kilometer', 'kilometers',
|
| 171 |
+
'dm', 'decimeter', 'decimeters',
|
| 172 |
+
'cm', 'centimeter', 'centimeters',
|
| 173 |
+
'mm', 'millimeter', 'millimeters',
|
| 174 |
+
'um', 'micrometer', 'micrometers', 'micron', 'microns',
|
| 175 |
+
'nm', 'nanometer', 'nanometers',
|
| 176 |
+
'pm', 'picometer', 'picometers',
|
| 177 |
+
'ft', 'foot', 'feet',
|
| 178 |
+
'inch', 'inches',
|
| 179 |
+
'yd', 'yard', 'yards',
|
| 180 |
+
'mi', 'mile', 'miles',
|
| 181 |
+
'nmi', 'nautical_mile', 'nautical_miles',
|
| 182 |
+
'ha', 'hectare',
|
| 183 |
+
'l', 'L', 'liter', 'liters',
|
| 184 |
+
'dl', 'dL', 'deciliter', 'deciliters',
|
| 185 |
+
'cl', 'cL', 'centiliter', 'centiliters',
|
| 186 |
+
'ml', 'mL', 'milliliter', 'milliliters',
|
| 187 |
+
'ms', 'millisecond', 'milliseconds',
|
| 188 |
+
'us', 'microsecond', 'microseconds',
|
| 189 |
+
'ns', 'nanosecond', 'nanoseconds',
|
| 190 |
+
'ps', 'picosecond', 'picoseconds',
|
| 191 |
+
'minute', 'minutes',
|
| 192 |
+
'h', 'hour', 'hours',
|
| 193 |
+
'day', 'days',
|
| 194 |
+
'anomalistic_year', 'anomalistic_years',
|
| 195 |
+
'sidereal_year', 'sidereal_years',
|
| 196 |
+
'tropical_year', 'tropical_years',
|
| 197 |
+
'common_year', 'common_years',
|
| 198 |
+
'julian_year', 'julian_years',
|
| 199 |
+
'draconic_year', 'draconic_years',
|
| 200 |
+
'gaussian_year', 'gaussian_years',
|
| 201 |
+
'full_moon_cycle', 'full_moon_cycles',
|
| 202 |
+
'year', 'years',
|
| 203 |
+
'G', 'gravitational_constant',
|
| 204 |
+
'c', 'speed_of_light',
|
| 205 |
+
'elementary_charge',
|
| 206 |
+
'hbar',
|
| 207 |
+
'planck',
|
| 208 |
+
'eV', 'electronvolt', 'electronvolts',
|
| 209 |
+
'avogadro_number',
|
| 210 |
+
'avogadro', 'avogadro_constant',
|
| 211 |
+
'boltzmann', 'boltzmann_constant',
|
| 212 |
+
'stefan', 'stefan_boltzmann_constant',
|
| 213 |
+
'R', 'molar_gas_constant',
|
| 214 |
+
'faraday_constant',
|
| 215 |
+
'josephson_constant',
|
| 216 |
+
'von_klitzing_constant',
|
| 217 |
+
'Da', 'dalton', 'amu', 'amus', 'atomic_mass_unit', 'atomic_mass_constant',
|
| 218 |
+
'me', 'electron_rest_mass',
|
| 219 |
+
'gee', 'gees', 'acceleration_due_to_gravity',
|
| 220 |
+
'u0', 'magnetic_constant', 'vacuum_permeability',
|
| 221 |
+
'e0', 'electric_constant', 'vacuum_permittivity',
|
| 222 |
+
'Z0', 'vacuum_impedance',
|
| 223 |
+
'coulomb_constant', 'coulombs_constant', 'electric_force_constant',
|
| 224 |
+
'atmosphere', 'atmospheres', 'atm',
|
| 225 |
+
'kPa', 'kilopascal',
|
| 226 |
+
'bar', 'bars',
|
| 227 |
+
'pound', 'pounds',
|
| 228 |
+
'psi',
|
| 229 |
+
'dHg0',
|
| 230 |
+
'mmHg', 'torr',
|
| 231 |
+
'mmu', 'mmus', 'milli_mass_unit',
|
| 232 |
+
'quart', 'quarts',
|
| 233 |
+
'angstrom', 'angstroms',
|
| 234 |
+
'ly', 'lightyear', 'lightyears',
|
| 235 |
+
'au', 'astronomical_unit', 'astronomical_units',
|
| 236 |
+
'planck_mass',
|
| 237 |
+
'planck_time',
|
| 238 |
+
'planck_temperature',
|
| 239 |
+
'planck_length',
|
| 240 |
+
'planck_charge',
|
| 241 |
+
'planck_area',
|
| 242 |
+
'planck_volume',
|
| 243 |
+
'planck_momentum',
|
| 244 |
+
'planck_energy',
|
| 245 |
+
'planck_force',
|
| 246 |
+
'planck_power',
|
| 247 |
+
'planck_density',
|
| 248 |
+
'planck_energy_density',
|
| 249 |
+
'planck_intensity',
|
| 250 |
+
'planck_angular_frequency',
|
| 251 |
+
'planck_pressure',
|
| 252 |
+
'planck_current',
|
| 253 |
+
'planck_voltage',
|
| 254 |
+
'planck_impedance',
|
| 255 |
+
'planck_acceleration',
|
| 256 |
+
'bit', 'bits',
|
| 257 |
+
'byte',
|
| 258 |
+
'kibibyte', 'kibibytes',
|
| 259 |
+
'mebibyte', 'mebibytes',
|
| 260 |
+
'gibibyte', 'gibibytes',
|
| 261 |
+
'tebibyte', 'tebibytes',
|
| 262 |
+
'pebibyte', 'pebibytes',
|
| 263 |
+
'exbibyte', 'exbibytes',
|
| 264 |
+
'curie', 'rutherford',
|
| 265 |
+
]
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/dimensions.py
ADDED
|
@@ -0,0 +1,590 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Definition of physical dimensions.
|
| 3 |
+
|
| 4 |
+
Unit systems will be constructed on top of these dimensions.
|
| 5 |
+
|
| 6 |
+
Most of the examples in the doc use MKS system and are presented from the
|
| 7 |
+
computer point of view: from a human point, adding length to time is not legal
|
| 8 |
+
in MKS but it is in natural system; for a computer in natural system there is
|
| 9 |
+
no time dimension (but a velocity dimension instead) - in the basis - so the
|
| 10 |
+
question of adding time to length has no meaning.
|
| 11 |
+
"""
|
| 12 |
+
|
| 13 |
+
from __future__ import annotations
|
| 14 |
+
|
| 15 |
+
import collections
|
| 16 |
+
from functools import reduce
|
| 17 |
+
|
| 18 |
+
from sympy.core.basic import Basic
|
| 19 |
+
from sympy.core.containers import (Dict, Tuple)
|
| 20 |
+
from sympy.core.singleton import S
|
| 21 |
+
from sympy.core.sorting import default_sort_key
|
| 22 |
+
from sympy.core.symbol import Symbol
|
| 23 |
+
from sympy.core.sympify import sympify
|
| 24 |
+
from sympy.matrices.dense import Matrix
|
| 25 |
+
from sympy.functions.elementary.trigonometric import TrigonometricFunction
|
| 26 |
+
from sympy.core.expr import Expr
|
| 27 |
+
from sympy.core.power import Pow
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
class _QuantityMapper:
|
| 31 |
+
|
| 32 |
+
_quantity_scale_factors_global: dict[Expr, Expr] = {}
|
| 33 |
+
_quantity_dimensional_equivalence_map_global: dict[Expr, Expr] = {}
|
| 34 |
+
_quantity_dimension_global: dict[Expr, Expr] = {}
|
| 35 |
+
|
| 36 |
+
def __init__(self, *args, **kwargs):
|
| 37 |
+
self._quantity_dimension_map = {}
|
| 38 |
+
self._quantity_scale_factors = {}
|
| 39 |
+
|
| 40 |
+
def set_quantity_dimension(self, quantity, dimension):
|
| 41 |
+
"""
|
| 42 |
+
Set the dimension for the quantity in a unit system.
|
| 43 |
+
|
| 44 |
+
If this relation is valid in every unit system, use
|
| 45 |
+
``quantity.set_global_dimension(dimension)`` instead.
|
| 46 |
+
"""
|
| 47 |
+
from sympy.physics.units import Quantity
|
| 48 |
+
dimension = sympify(dimension)
|
| 49 |
+
if not isinstance(dimension, Dimension):
|
| 50 |
+
if dimension == 1:
|
| 51 |
+
dimension = Dimension(1)
|
| 52 |
+
else:
|
| 53 |
+
raise ValueError("expected dimension or 1")
|
| 54 |
+
elif isinstance(dimension, Quantity):
|
| 55 |
+
dimension = self.get_quantity_dimension(dimension)
|
| 56 |
+
self._quantity_dimension_map[quantity] = dimension
|
| 57 |
+
|
| 58 |
+
def set_quantity_scale_factor(self, quantity, scale_factor):
|
| 59 |
+
"""
|
| 60 |
+
Set the scale factor of a quantity relative to another quantity.
|
| 61 |
+
|
| 62 |
+
It should be used only once per quantity to just one other quantity,
|
| 63 |
+
the algorithm will then be able to compute the scale factors to all
|
| 64 |
+
other quantities.
|
| 65 |
+
|
| 66 |
+
In case the scale factor is valid in every unit system, please use
|
| 67 |
+
``quantity.set_global_relative_scale_factor(scale_factor)`` instead.
|
| 68 |
+
"""
|
| 69 |
+
from sympy.physics.units import Quantity
|
| 70 |
+
from sympy.physics.units.prefixes import Prefix
|
| 71 |
+
scale_factor = sympify(scale_factor)
|
| 72 |
+
# replace all prefixes by their ratio to canonical units:
|
| 73 |
+
scale_factor = scale_factor.replace(
|
| 74 |
+
lambda x: isinstance(x, Prefix),
|
| 75 |
+
lambda x: x.scale_factor
|
| 76 |
+
)
|
| 77 |
+
# replace all quantities by their ratio to canonical units:
|
| 78 |
+
scale_factor = scale_factor.replace(
|
| 79 |
+
lambda x: isinstance(x, Quantity),
|
| 80 |
+
lambda x: self.get_quantity_scale_factor(x)
|
| 81 |
+
)
|
| 82 |
+
self._quantity_scale_factors[quantity] = scale_factor
|
| 83 |
+
|
| 84 |
+
def get_quantity_dimension(self, unit):
|
| 85 |
+
from sympy.physics.units import Quantity
|
| 86 |
+
# First look-up the local dimension map, then the global one:
|
| 87 |
+
if unit in self._quantity_dimension_map:
|
| 88 |
+
return self._quantity_dimension_map[unit]
|
| 89 |
+
if unit in self._quantity_dimension_global:
|
| 90 |
+
return self._quantity_dimension_global[unit]
|
| 91 |
+
if unit in self._quantity_dimensional_equivalence_map_global:
|
| 92 |
+
dep_unit = self._quantity_dimensional_equivalence_map_global[unit]
|
| 93 |
+
if isinstance(dep_unit, Quantity):
|
| 94 |
+
return self.get_quantity_dimension(dep_unit)
|
| 95 |
+
else:
|
| 96 |
+
return Dimension(self.get_dimensional_expr(dep_unit))
|
| 97 |
+
if isinstance(unit, Quantity):
|
| 98 |
+
return Dimension(unit.name)
|
| 99 |
+
else:
|
| 100 |
+
return Dimension(1)
|
| 101 |
+
|
| 102 |
+
def get_quantity_scale_factor(self, unit):
|
| 103 |
+
if unit in self._quantity_scale_factors:
|
| 104 |
+
return self._quantity_scale_factors[unit]
|
| 105 |
+
if unit in self._quantity_scale_factors_global:
|
| 106 |
+
mul_factor, other_unit = self._quantity_scale_factors_global[unit]
|
| 107 |
+
return mul_factor*self.get_quantity_scale_factor(other_unit)
|
| 108 |
+
return S.One
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
class Dimension(Expr):
|
| 112 |
+
"""
|
| 113 |
+
This class represent the dimension of a physical quantities.
|
| 114 |
+
|
| 115 |
+
The ``Dimension`` constructor takes as parameters a name and an optional
|
| 116 |
+
symbol.
|
| 117 |
+
|
| 118 |
+
For example, in classical mechanics we know that time is different from
|
| 119 |
+
temperature and dimensions make this difference (but they do not provide
|
| 120 |
+
any measure of these quantites.
|
| 121 |
+
|
| 122 |
+
>>> from sympy.physics.units import Dimension
|
| 123 |
+
>>> length = Dimension('length')
|
| 124 |
+
>>> length
|
| 125 |
+
Dimension(length)
|
| 126 |
+
>>> time = Dimension('time')
|
| 127 |
+
>>> time
|
| 128 |
+
Dimension(time)
|
| 129 |
+
|
| 130 |
+
Dimensions can be composed using multiplication, division and
|
| 131 |
+
exponentiation (by a number) to give new dimensions. Addition and
|
| 132 |
+
subtraction is defined only when the two objects are the same dimension.
|
| 133 |
+
|
| 134 |
+
>>> velocity = length / time
|
| 135 |
+
>>> velocity
|
| 136 |
+
Dimension(length/time)
|
| 137 |
+
|
| 138 |
+
It is possible to use a dimension system object to get the dimensionsal
|
| 139 |
+
dependencies of a dimension, for example the dimension system used by the
|
| 140 |
+
SI units convention can be used:
|
| 141 |
+
|
| 142 |
+
>>> from sympy.physics.units.systems.si import dimsys_SI
|
| 143 |
+
>>> dimsys_SI.get_dimensional_dependencies(velocity)
|
| 144 |
+
{Dimension(length, L): 1, Dimension(time, T): -1}
|
| 145 |
+
>>> length + length
|
| 146 |
+
Dimension(length)
|
| 147 |
+
>>> l2 = length**2
|
| 148 |
+
>>> l2
|
| 149 |
+
Dimension(length**2)
|
| 150 |
+
>>> dimsys_SI.get_dimensional_dependencies(l2)
|
| 151 |
+
{Dimension(length, L): 2}
|
| 152 |
+
|
| 153 |
+
"""
|
| 154 |
+
|
| 155 |
+
_op_priority = 13.0
|
| 156 |
+
|
| 157 |
+
# XXX: This doesn't seem to be used anywhere...
|
| 158 |
+
_dimensional_dependencies = {} # type: ignore
|
| 159 |
+
|
| 160 |
+
is_commutative = True
|
| 161 |
+
is_number = False
|
| 162 |
+
# make sqrt(M**2) --> M
|
| 163 |
+
is_positive = True
|
| 164 |
+
is_real = True
|
| 165 |
+
|
| 166 |
+
def __new__(cls, name, symbol=None):
|
| 167 |
+
|
| 168 |
+
if isinstance(name, str):
|
| 169 |
+
name = Symbol(name)
|
| 170 |
+
else:
|
| 171 |
+
name = sympify(name)
|
| 172 |
+
|
| 173 |
+
if not isinstance(name, Expr):
|
| 174 |
+
raise TypeError("Dimension name needs to be a valid math expression")
|
| 175 |
+
|
| 176 |
+
if isinstance(symbol, str):
|
| 177 |
+
symbol = Symbol(symbol)
|
| 178 |
+
elif symbol is not None:
|
| 179 |
+
assert isinstance(symbol, Symbol)
|
| 180 |
+
|
| 181 |
+
obj = Expr.__new__(cls, name)
|
| 182 |
+
|
| 183 |
+
obj._name = name
|
| 184 |
+
obj._symbol = symbol
|
| 185 |
+
return obj
|
| 186 |
+
|
| 187 |
+
@property
|
| 188 |
+
def name(self):
|
| 189 |
+
return self._name
|
| 190 |
+
|
| 191 |
+
@property
|
| 192 |
+
def symbol(self):
|
| 193 |
+
return self._symbol
|
| 194 |
+
|
| 195 |
+
def __str__(self):
|
| 196 |
+
"""
|
| 197 |
+
Display the string representation of the dimension.
|
| 198 |
+
"""
|
| 199 |
+
if self.symbol is None:
|
| 200 |
+
return "Dimension(%s)" % (self.name)
|
| 201 |
+
else:
|
| 202 |
+
return "Dimension(%s, %s)" % (self.name, self.symbol)
|
| 203 |
+
|
| 204 |
+
def __repr__(self):
|
| 205 |
+
return self.__str__()
|
| 206 |
+
|
| 207 |
+
def __neg__(self):
|
| 208 |
+
return self
|
| 209 |
+
|
| 210 |
+
def __add__(self, other):
|
| 211 |
+
from sympy.physics.units.quantities import Quantity
|
| 212 |
+
other = sympify(other)
|
| 213 |
+
if isinstance(other, Basic):
|
| 214 |
+
if other.has(Quantity):
|
| 215 |
+
raise TypeError("cannot sum dimension and quantity")
|
| 216 |
+
if isinstance(other, Dimension) and self == other:
|
| 217 |
+
return self
|
| 218 |
+
return super().__add__(other)
|
| 219 |
+
return self
|
| 220 |
+
|
| 221 |
+
def __radd__(self, other):
|
| 222 |
+
return self.__add__(other)
|
| 223 |
+
|
| 224 |
+
def __sub__(self, other):
|
| 225 |
+
# there is no notion of ordering (or magnitude) among dimension,
|
| 226 |
+
# subtraction is equivalent to addition when the operation is legal
|
| 227 |
+
return self + other
|
| 228 |
+
|
| 229 |
+
def __rsub__(self, other):
|
| 230 |
+
# there is no notion of ordering (or magnitude) among dimension,
|
| 231 |
+
# subtraction is equivalent to addition when the operation is legal
|
| 232 |
+
return self + other
|
| 233 |
+
|
| 234 |
+
def __pow__(self, other):
|
| 235 |
+
return self._eval_power(other)
|
| 236 |
+
|
| 237 |
+
def _eval_power(self, other):
|
| 238 |
+
other = sympify(other)
|
| 239 |
+
return Dimension(self.name**other)
|
| 240 |
+
|
| 241 |
+
def __mul__(self, other):
|
| 242 |
+
from sympy.physics.units.quantities import Quantity
|
| 243 |
+
if isinstance(other, Basic):
|
| 244 |
+
if other.has(Quantity):
|
| 245 |
+
raise TypeError("cannot sum dimension and quantity")
|
| 246 |
+
if isinstance(other, Dimension):
|
| 247 |
+
return Dimension(self.name*other.name)
|
| 248 |
+
if not other.free_symbols: # other.is_number cannot be used
|
| 249 |
+
return self
|
| 250 |
+
return super().__mul__(other)
|
| 251 |
+
return self
|
| 252 |
+
|
| 253 |
+
def __rmul__(self, other):
|
| 254 |
+
return self.__mul__(other)
|
| 255 |
+
|
| 256 |
+
def __truediv__(self, other):
|
| 257 |
+
return self*Pow(other, -1)
|
| 258 |
+
|
| 259 |
+
def __rtruediv__(self, other):
|
| 260 |
+
return other * pow(self, -1)
|
| 261 |
+
|
| 262 |
+
@classmethod
|
| 263 |
+
def _from_dimensional_dependencies(cls, dependencies):
|
| 264 |
+
return reduce(lambda x, y: x * y, (
|
| 265 |
+
d**e for d, e in dependencies.items()
|
| 266 |
+
), 1)
|
| 267 |
+
|
| 268 |
+
def has_integer_powers(self, dim_sys):
|
| 269 |
+
"""
|
| 270 |
+
Check if the dimension object has only integer powers.
|
| 271 |
+
|
| 272 |
+
All the dimension powers should be integers, but rational powers may
|
| 273 |
+
appear in intermediate steps. This method may be used to check that the
|
| 274 |
+
final result is well-defined.
|
| 275 |
+
"""
|
| 276 |
+
|
| 277 |
+
return all(dpow.is_Integer for dpow in dim_sys.get_dimensional_dependencies(self).values())
|
| 278 |
+
|
| 279 |
+
|
| 280 |
+
# Create dimensions according to the base units in MKSA.
|
| 281 |
+
# For other unit systems, they can be derived by transforming the base
|
| 282 |
+
# dimensional dependency dictionary.
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
class DimensionSystem(Basic, _QuantityMapper):
|
| 286 |
+
r"""
|
| 287 |
+
DimensionSystem represents a coherent set of dimensions.
|
| 288 |
+
|
| 289 |
+
The constructor takes three parameters:
|
| 290 |
+
|
| 291 |
+
- base dimensions;
|
| 292 |
+
- derived dimensions: these are defined in terms of the base dimensions
|
| 293 |
+
(for example velocity is defined from the division of length by time);
|
| 294 |
+
- dependency of dimensions: how the derived dimensions depend
|
| 295 |
+
on the base dimensions.
|
| 296 |
+
|
| 297 |
+
Optionally either the ``derived_dims`` or the ``dimensional_dependencies``
|
| 298 |
+
may be omitted.
|
| 299 |
+
"""
|
| 300 |
+
|
| 301 |
+
def __new__(cls, base_dims, derived_dims=(), dimensional_dependencies={}):
|
| 302 |
+
dimensional_dependencies = dict(dimensional_dependencies)
|
| 303 |
+
|
| 304 |
+
def parse_dim(dim):
|
| 305 |
+
if isinstance(dim, str):
|
| 306 |
+
dim = Dimension(Symbol(dim))
|
| 307 |
+
elif isinstance(dim, Dimension):
|
| 308 |
+
pass
|
| 309 |
+
elif isinstance(dim, Symbol):
|
| 310 |
+
dim = Dimension(dim)
|
| 311 |
+
else:
|
| 312 |
+
raise TypeError("%s wrong type" % dim)
|
| 313 |
+
return dim
|
| 314 |
+
|
| 315 |
+
base_dims = [parse_dim(i) for i in base_dims]
|
| 316 |
+
derived_dims = [parse_dim(i) for i in derived_dims]
|
| 317 |
+
|
| 318 |
+
for dim in base_dims:
|
| 319 |
+
if (dim in dimensional_dependencies
|
| 320 |
+
and (len(dimensional_dependencies[dim]) != 1 or
|
| 321 |
+
dimensional_dependencies[dim].get(dim, None) != 1)):
|
| 322 |
+
raise IndexError("Repeated value in base dimensions")
|
| 323 |
+
dimensional_dependencies[dim] = Dict({dim: 1})
|
| 324 |
+
|
| 325 |
+
def parse_dim_name(dim):
|
| 326 |
+
if isinstance(dim, Dimension):
|
| 327 |
+
return dim
|
| 328 |
+
elif isinstance(dim, str):
|
| 329 |
+
return Dimension(Symbol(dim))
|
| 330 |
+
elif isinstance(dim, Symbol):
|
| 331 |
+
return Dimension(dim)
|
| 332 |
+
else:
|
| 333 |
+
raise TypeError("unrecognized type %s for %s" % (type(dim), dim))
|
| 334 |
+
|
| 335 |
+
for dim in dimensional_dependencies.keys():
|
| 336 |
+
dim = parse_dim(dim)
|
| 337 |
+
if (dim not in derived_dims) and (dim not in base_dims):
|
| 338 |
+
derived_dims.append(dim)
|
| 339 |
+
|
| 340 |
+
def parse_dict(d):
|
| 341 |
+
return Dict({parse_dim_name(i): j for i, j in d.items()})
|
| 342 |
+
|
| 343 |
+
# Make sure everything is a SymPy type:
|
| 344 |
+
dimensional_dependencies = {parse_dim_name(i): parse_dict(j) for i, j in
|
| 345 |
+
dimensional_dependencies.items()}
|
| 346 |
+
|
| 347 |
+
for dim in derived_dims:
|
| 348 |
+
if dim in base_dims:
|
| 349 |
+
raise ValueError("Dimension %s both in base and derived" % dim)
|
| 350 |
+
if dim not in dimensional_dependencies:
|
| 351 |
+
# TODO: should this raise a warning?
|
| 352 |
+
dimensional_dependencies[dim] = Dict({dim: 1})
|
| 353 |
+
|
| 354 |
+
base_dims.sort(key=default_sort_key)
|
| 355 |
+
derived_dims.sort(key=default_sort_key)
|
| 356 |
+
|
| 357 |
+
base_dims = Tuple(*base_dims)
|
| 358 |
+
derived_dims = Tuple(*derived_dims)
|
| 359 |
+
dimensional_dependencies = Dict({i: Dict(j) for i, j in dimensional_dependencies.items()})
|
| 360 |
+
obj = Basic.__new__(cls, base_dims, derived_dims, dimensional_dependencies)
|
| 361 |
+
return obj
|
| 362 |
+
|
| 363 |
+
@property
|
| 364 |
+
def base_dims(self):
|
| 365 |
+
return self.args[0]
|
| 366 |
+
|
| 367 |
+
@property
|
| 368 |
+
def derived_dims(self):
|
| 369 |
+
return self.args[1]
|
| 370 |
+
|
| 371 |
+
@property
|
| 372 |
+
def dimensional_dependencies(self):
|
| 373 |
+
return self.args[2]
|
| 374 |
+
|
| 375 |
+
def _get_dimensional_dependencies_for_name(self, dimension):
|
| 376 |
+
if isinstance(dimension, str):
|
| 377 |
+
dimension = Dimension(Symbol(dimension))
|
| 378 |
+
elif not isinstance(dimension, Dimension):
|
| 379 |
+
dimension = Dimension(dimension)
|
| 380 |
+
|
| 381 |
+
if dimension.name.is_Symbol:
|
| 382 |
+
# Dimensions not included in the dependencies are considered
|
| 383 |
+
# as base dimensions:
|
| 384 |
+
return dict(self.dimensional_dependencies.get(dimension, {dimension: 1}))
|
| 385 |
+
|
| 386 |
+
if dimension.name.is_number or dimension.name.is_NumberSymbol:
|
| 387 |
+
return {}
|
| 388 |
+
|
| 389 |
+
get_for_name = self._get_dimensional_dependencies_for_name
|
| 390 |
+
|
| 391 |
+
if dimension.name.is_Mul:
|
| 392 |
+
ret = collections.defaultdict(int)
|
| 393 |
+
dicts = [get_for_name(i) for i in dimension.name.args]
|
| 394 |
+
for d in dicts:
|
| 395 |
+
for k, v in d.items():
|
| 396 |
+
ret[k] += v
|
| 397 |
+
return {k: v for (k, v) in ret.items() if v != 0}
|
| 398 |
+
|
| 399 |
+
if dimension.name.is_Add:
|
| 400 |
+
dicts = [get_for_name(i) for i in dimension.name.args]
|
| 401 |
+
if all(d == dicts[0] for d in dicts[1:]):
|
| 402 |
+
return dicts[0]
|
| 403 |
+
raise TypeError("Only equivalent dimensions can be added or subtracted.")
|
| 404 |
+
|
| 405 |
+
if dimension.name.is_Pow:
|
| 406 |
+
dim_base = get_for_name(dimension.name.base)
|
| 407 |
+
dim_exp = get_for_name(dimension.name.exp)
|
| 408 |
+
if dim_exp == {} or dimension.name.exp.is_Symbol:
|
| 409 |
+
return {k: v * dimension.name.exp for (k, v) in dim_base.items()}
|
| 410 |
+
else:
|
| 411 |
+
raise TypeError("The exponent for the power operator must be a Symbol or dimensionless.")
|
| 412 |
+
|
| 413 |
+
if dimension.name.is_Function:
|
| 414 |
+
args = (Dimension._from_dimensional_dependencies(
|
| 415 |
+
get_for_name(arg)) for arg in dimension.name.args)
|
| 416 |
+
result = dimension.name.func(*args)
|
| 417 |
+
|
| 418 |
+
dicts = [get_for_name(i) for i in dimension.name.args]
|
| 419 |
+
|
| 420 |
+
if isinstance(result, Dimension):
|
| 421 |
+
return self.get_dimensional_dependencies(result)
|
| 422 |
+
elif result.func == dimension.name.func:
|
| 423 |
+
if isinstance(dimension.name, TrigonometricFunction):
|
| 424 |
+
if dicts[0] in ({}, {Dimension('angle'): 1}):
|
| 425 |
+
return {}
|
| 426 |
+
else:
|
| 427 |
+
raise TypeError("The input argument for the function {} must be dimensionless or have dimensions of angle.".format(dimension.func))
|
| 428 |
+
else:
|
| 429 |
+
if all(item == {} for item in dicts):
|
| 430 |
+
return {}
|
| 431 |
+
else:
|
| 432 |
+
raise TypeError("The input arguments for the function {} must be dimensionless.".format(dimension.func))
|
| 433 |
+
else:
|
| 434 |
+
return get_for_name(result)
|
| 435 |
+
|
| 436 |
+
raise TypeError("Type {} not implemented for get_dimensional_dependencies".format(type(dimension.name)))
|
| 437 |
+
|
| 438 |
+
def get_dimensional_dependencies(self, name, mark_dimensionless=False):
|
| 439 |
+
dimdep = self._get_dimensional_dependencies_for_name(name)
|
| 440 |
+
if mark_dimensionless and dimdep == {}:
|
| 441 |
+
return {Dimension(1): 1}
|
| 442 |
+
return dict(dimdep.items())
|
| 443 |
+
|
| 444 |
+
def equivalent_dims(self, dim1, dim2):
|
| 445 |
+
deps1 = self.get_dimensional_dependencies(dim1)
|
| 446 |
+
deps2 = self.get_dimensional_dependencies(dim2)
|
| 447 |
+
return deps1 == deps2
|
| 448 |
+
|
| 449 |
+
def extend(self, new_base_dims, new_derived_dims=(), new_dim_deps=None):
|
| 450 |
+
deps = dict(self.dimensional_dependencies)
|
| 451 |
+
if new_dim_deps:
|
| 452 |
+
deps.update(new_dim_deps)
|
| 453 |
+
|
| 454 |
+
new_dim_sys = DimensionSystem(
|
| 455 |
+
tuple(self.base_dims) + tuple(new_base_dims),
|
| 456 |
+
tuple(self.derived_dims) + tuple(new_derived_dims),
|
| 457 |
+
deps
|
| 458 |
+
)
|
| 459 |
+
new_dim_sys._quantity_dimension_map.update(self._quantity_dimension_map)
|
| 460 |
+
new_dim_sys._quantity_scale_factors.update(self._quantity_scale_factors)
|
| 461 |
+
return new_dim_sys
|
| 462 |
+
|
| 463 |
+
def is_dimensionless(self, dimension):
|
| 464 |
+
"""
|
| 465 |
+
Check if the dimension object really has a dimension.
|
| 466 |
+
|
| 467 |
+
A dimension should have at least one component with non-zero power.
|
| 468 |
+
"""
|
| 469 |
+
if dimension.name == 1:
|
| 470 |
+
return True
|
| 471 |
+
return self.get_dimensional_dependencies(dimension) == {}
|
| 472 |
+
|
| 473 |
+
@property
|
| 474 |
+
def list_can_dims(self):
|
| 475 |
+
"""
|
| 476 |
+
Useless method, kept for compatibility with previous versions.
|
| 477 |
+
|
| 478 |
+
DO NOT USE.
|
| 479 |
+
|
| 480 |
+
List all canonical dimension names.
|
| 481 |
+
"""
|
| 482 |
+
dimset = set()
|
| 483 |
+
for i in self.base_dims:
|
| 484 |
+
dimset.update(set(self.get_dimensional_dependencies(i).keys()))
|
| 485 |
+
return tuple(sorted(dimset, key=str))
|
| 486 |
+
|
| 487 |
+
@property
|
| 488 |
+
def inv_can_transf_matrix(self):
|
| 489 |
+
"""
|
| 490 |
+
Useless method, kept for compatibility with previous versions.
|
| 491 |
+
|
| 492 |
+
DO NOT USE.
|
| 493 |
+
|
| 494 |
+
Compute the inverse transformation matrix from the base to the
|
| 495 |
+
canonical dimension basis.
|
| 496 |
+
|
| 497 |
+
It corresponds to the matrix where columns are the vector of base
|
| 498 |
+
dimensions in canonical basis.
|
| 499 |
+
|
| 500 |
+
This matrix will almost never be used because dimensions are always
|
| 501 |
+
defined with respect to the canonical basis, so no work has to be done
|
| 502 |
+
to get them in this basis. Nonetheless if this matrix is not square
|
| 503 |
+
(or not invertible) it means that we have chosen a bad basis.
|
| 504 |
+
"""
|
| 505 |
+
matrix = reduce(lambda x, y: x.row_join(y),
|
| 506 |
+
[self.dim_can_vector(d) for d in self.base_dims])
|
| 507 |
+
return matrix
|
| 508 |
+
|
| 509 |
+
@property
|
| 510 |
+
def can_transf_matrix(self):
|
| 511 |
+
"""
|
| 512 |
+
Useless method, kept for compatibility with previous versions.
|
| 513 |
+
|
| 514 |
+
DO NOT USE.
|
| 515 |
+
|
| 516 |
+
Return the canonical transformation matrix from the canonical to the
|
| 517 |
+
base dimension basis.
|
| 518 |
+
|
| 519 |
+
It is the inverse of the matrix computed with inv_can_transf_matrix().
|
| 520 |
+
"""
|
| 521 |
+
|
| 522 |
+
#TODO: the inversion will fail if the system is inconsistent, for
|
| 523 |
+
# example if the matrix is not a square
|
| 524 |
+
return reduce(lambda x, y: x.row_join(y),
|
| 525 |
+
[self.dim_can_vector(d) for d in sorted(self.base_dims, key=str)]
|
| 526 |
+
).inv()
|
| 527 |
+
|
| 528 |
+
def dim_can_vector(self, dim):
|
| 529 |
+
"""
|
| 530 |
+
Useless method, kept for compatibility with previous versions.
|
| 531 |
+
|
| 532 |
+
DO NOT USE.
|
| 533 |
+
|
| 534 |
+
Dimensional representation in terms of the canonical base dimensions.
|
| 535 |
+
"""
|
| 536 |
+
|
| 537 |
+
vec = []
|
| 538 |
+
for d in self.list_can_dims:
|
| 539 |
+
vec.append(self.get_dimensional_dependencies(dim).get(d, 0))
|
| 540 |
+
return Matrix(vec)
|
| 541 |
+
|
| 542 |
+
def dim_vector(self, dim):
|
| 543 |
+
"""
|
| 544 |
+
Useless method, kept for compatibility with previous versions.
|
| 545 |
+
|
| 546 |
+
DO NOT USE.
|
| 547 |
+
|
| 548 |
+
|
| 549 |
+
Vector representation in terms of the base dimensions.
|
| 550 |
+
"""
|
| 551 |
+
return self.can_transf_matrix * Matrix(self.dim_can_vector(dim))
|
| 552 |
+
|
| 553 |
+
def print_dim_base(self, dim):
|
| 554 |
+
"""
|
| 555 |
+
Give the string expression of a dimension in term of the basis symbols.
|
| 556 |
+
"""
|
| 557 |
+
dims = self.dim_vector(dim)
|
| 558 |
+
symbols = [i.symbol if i.symbol is not None else i.name for i in self.base_dims]
|
| 559 |
+
res = S.One
|
| 560 |
+
for (s, p) in zip(symbols, dims):
|
| 561 |
+
res *= s**p
|
| 562 |
+
return res
|
| 563 |
+
|
| 564 |
+
@property
|
| 565 |
+
def dim(self):
|
| 566 |
+
"""
|
| 567 |
+
Useless method, kept for compatibility with previous versions.
|
| 568 |
+
|
| 569 |
+
DO NOT USE.
|
| 570 |
+
|
| 571 |
+
Give the dimension of the system.
|
| 572 |
+
|
| 573 |
+
That is return the number of dimensions forming the basis.
|
| 574 |
+
"""
|
| 575 |
+
return len(self.base_dims)
|
| 576 |
+
|
| 577 |
+
@property
|
| 578 |
+
def is_consistent(self):
|
| 579 |
+
"""
|
| 580 |
+
Useless method, kept for compatibility with previous versions.
|
| 581 |
+
|
| 582 |
+
DO NOT USE.
|
| 583 |
+
|
| 584 |
+
Check if the system is well defined.
|
| 585 |
+
"""
|
| 586 |
+
|
| 587 |
+
# not enough or too many base dimensions compared to independent
|
| 588 |
+
# dimensions
|
| 589 |
+
# in vector language: the set of vectors do not form a basis
|
| 590 |
+
return self.inv_can_transf_matrix.is_square
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/quantities.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Physical quantities.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from sympy.core.expr import AtomicExpr
|
| 6 |
+
from sympy.core.symbol import Symbol
|
| 7 |
+
from sympy.core.sympify import sympify
|
| 8 |
+
from sympy.physics.units.dimensions import _QuantityMapper
|
| 9 |
+
from sympy.physics.units.prefixes import Prefix
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
class Quantity(AtomicExpr):
|
| 13 |
+
"""
|
| 14 |
+
Physical quantity: can be a unit of measure, a constant or a generic quantity.
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
is_commutative = True
|
| 18 |
+
is_real = True
|
| 19 |
+
is_number = False
|
| 20 |
+
is_nonzero = True
|
| 21 |
+
is_physical_constant = False
|
| 22 |
+
_diff_wrt = True
|
| 23 |
+
|
| 24 |
+
def __new__(cls, name, abbrev=None,
|
| 25 |
+
latex_repr=None, pretty_unicode_repr=None,
|
| 26 |
+
pretty_ascii_repr=None, mathml_presentation_repr=None,
|
| 27 |
+
is_prefixed=False,
|
| 28 |
+
**assumptions):
|
| 29 |
+
|
| 30 |
+
if not isinstance(name, Symbol):
|
| 31 |
+
name = Symbol(name)
|
| 32 |
+
|
| 33 |
+
if abbrev is None:
|
| 34 |
+
abbrev = name
|
| 35 |
+
elif isinstance(abbrev, str):
|
| 36 |
+
abbrev = Symbol(abbrev)
|
| 37 |
+
|
| 38 |
+
# HACK: These are here purely for type checking. They actually get assigned below.
|
| 39 |
+
cls._is_prefixed = is_prefixed
|
| 40 |
+
|
| 41 |
+
obj = AtomicExpr.__new__(cls, name, abbrev)
|
| 42 |
+
obj._name = name
|
| 43 |
+
obj._abbrev = abbrev
|
| 44 |
+
obj._latex_repr = latex_repr
|
| 45 |
+
obj._unicode_repr = pretty_unicode_repr
|
| 46 |
+
obj._ascii_repr = pretty_ascii_repr
|
| 47 |
+
obj._mathml_repr = mathml_presentation_repr
|
| 48 |
+
obj._is_prefixed = is_prefixed
|
| 49 |
+
return obj
|
| 50 |
+
|
| 51 |
+
def set_global_dimension(self, dimension):
|
| 52 |
+
_QuantityMapper._quantity_dimension_global[self] = dimension
|
| 53 |
+
|
| 54 |
+
def set_global_relative_scale_factor(self, scale_factor, reference_quantity):
|
| 55 |
+
"""
|
| 56 |
+
Setting a scale factor that is valid across all unit system.
|
| 57 |
+
"""
|
| 58 |
+
from sympy.physics.units import UnitSystem
|
| 59 |
+
scale_factor = sympify(scale_factor)
|
| 60 |
+
if isinstance(scale_factor, Prefix):
|
| 61 |
+
self._is_prefixed = True
|
| 62 |
+
# replace all prefixes by their ratio to canonical units:
|
| 63 |
+
scale_factor = scale_factor.replace(
|
| 64 |
+
lambda x: isinstance(x, Prefix),
|
| 65 |
+
lambda x: x.scale_factor
|
| 66 |
+
)
|
| 67 |
+
scale_factor = sympify(scale_factor)
|
| 68 |
+
UnitSystem._quantity_scale_factors_global[self] = (scale_factor, reference_quantity)
|
| 69 |
+
UnitSystem._quantity_dimensional_equivalence_map_global[self] = reference_quantity
|
| 70 |
+
|
| 71 |
+
@property
|
| 72 |
+
def name(self):
|
| 73 |
+
return self._name
|
| 74 |
+
|
| 75 |
+
@property
|
| 76 |
+
def dimension(self):
|
| 77 |
+
from sympy.physics.units import UnitSystem
|
| 78 |
+
unit_system = UnitSystem.get_default_unit_system()
|
| 79 |
+
return unit_system.get_quantity_dimension(self)
|
| 80 |
+
|
| 81 |
+
@property
|
| 82 |
+
def abbrev(self):
|
| 83 |
+
"""
|
| 84 |
+
Symbol representing the unit name.
|
| 85 |
+
|
| 86 |
+
Prepend the abbreviation with the prefix symbol if it is defines.
|
| 87 |
+
"""
|
| 88 |
+
return self._abbrev
|
| 89 |
+
|
| 90 |
+
@property
|
| 91 |
+
def scale_factor(self):
|
| 92 |
+
"""
|
| 93 |
+
Overall magnitude of the quantity as compared to the canonical units.
|
| 94 |
+
"""
|
| 95 |
+
from sympy.physics.units import UnitSystem
|
| 96 |
+
unit_system = UnitSystem.get_default_unit_system()
|
| 97 |
+
return unit_system.get_quantity_scale_factor(self)
|
| 98 |
+
|
| 99 |
+
def _eval_is_positive(self):
|
| 100 |
+
return True
|
| 101 |
+
|
| 102 |
+
def _eval_is_constant(self):
|
| 103 |
+
return True
|
| 104 |
+
|
| 105 |
+
def _eval_Abs(self):
|
| 106 |
+
return self
|
| 107 |
+
|
| 108 |
+
def _eval_subs(self, old, new):
|
| 109 |
+
if isinstance(new, Quantity) and self != old:
|
| 110 |
+
return self
|
| 111 |
+
|
| 112 |
+
def _latex(self, printer):
|
| 113 |
+
if self._latex_repr:
|
| 114 |
+
return self._latex_repr
|
| 115 |
+
else:
|
| 116 |
+
return r'\text{{{}}}'.format(self.args[1] \
|
| 117 |
+
if len(self.args) >= 2 else self.args[0])
|
| 118 |
+
|
| 119 |
+
def convert_to(self, other, unit_system="SI"):
|
| 120 |
+
"""
|
| 121 |
+
Convert the quantity to another quantity of same dimensions.
|
| 122 |
+
|
| 123 |
+
Examples
|
| 124 |
+
========
|
| 125 |
+
|
| 126 |
+
>>> from sympy.physics.units import speed_of_light, meter, second
|
| 127 |
+
>>> speed_of_light
|
| 128 |
+
speed_of_light
|
| 129 |
+
>>> speed_of_light.convert_to(meter/second)
|
| 130 |
+
299792458*meter/second
|
| 131 |
+
|
| 132 |
+
>>> from sympy.physics.units import liter
|
| 133 |
+
>>> liter.convert_to(meter**3)
|
| 134 |
+
meter**3/1000
|
| 135 |
+
"""
|
| 136 |
+
from .util import convert_to
|
| 137 |
+
return convert_to(self, other, unit_system)
|
| 138 |
+
|
| 139 |
+
@property
|
| 140 |
+
def free_symbols(self):
|
| 141 |
+
"""Return free symbols from quantity."""
|
| 142 |
+
return set()
|
| 143 |
+
|
| 144 |
+
@property
|
| 145 |
+
def is_prefixed(self):
|
| 146 |
+
"""Whether or not the quantity is prefixed. Eg. `kilogram` is prefixed, but `gram` is not."""
|
| 147 |
+
return self._is_prefixed
|
| 148 |
+
|
| 149 |
+
class PhysicalConstant(Quantity):
|
| 150 |
+
"""Represents a physical constant, eg. `speed_of_light` or `avogadro_constant`."""
|
| 151 |
+
|
| 152 |
+
is_physical_constant = True
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (582 Bytes). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/cgs.cpython-311.pyc
ADDED
|
Binary file (4.9 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/length_weight_time.cpython-311.pyc
ADDED
|
Binary file (8.33 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/mks.cpython-311.pyc
ADDED
|
Binary file (2.17 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/mksa.cpython-311.pyc
ADDED
|
Binary file (2.49 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/natural.cpython-311.pyc
ADDED
|
Binary file (1.51 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/si.cpython-311.pyc
ADDED
|
Binary file (17.3 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/cgs.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.singleton import S
|
| 2 |
+
from sympy.functions.elementary.miscellaneous import sqrt
|
| 3 |
+
from sympy.physics.units import UnitSystem, centimeter, gram, second, coulomb, charge, speed_of_light, current, mass, \
|
| 4 |
+
length, voltage, magnetic_density, magnetic_flux
|
| 5 |
+
from sympy.physics.units.definitions import coulombs_constant
|
| 6 |
+
from sympy.physics.units.definitions.unit_definitions import statcoulomb, statampere, statvolt, volt, tesla, gauss, \
|
| 7 |
+
weber, maxwell, debye, oersted, ohm, farad, henry, erg, ampere, coulomb_constant
|
| 8 |
+
from sympy.physics.units.systems.mks import dimsys_length_weight_time
|
| 9 |
+
|
| 10 |
+
One = S.One
|
| 11 |
+
|
| 12 |
+
dimsys_cgs = dimsys_length_weight_time.extend(
|
| 13 |
+
[],
|
| 14 |
+
new_dim_deps={
|
| 15 |
+
# Dimensional dependencies for derived dimensions
|
| 16 |
+
"impedance": {"time": 1, "length": -1},
|
| 17 |
+
"conductance": {"time": -1, "length": 1},
|
| 18 |
+
"capacitance": {"length": 1},
|
| 19 |
+
"inductance": {"time": 2, "length": -1},
|
| 20 |
+
"charge": {"mass": S.Half, "length": S(3)/2, "time": -1},
|
| 21 |
+
"current": {"mass": One/2, "length": 3*One/2, "time": -2},
|
| 22 |
+
"voltage": {"length": -One/2, "mass": One/2, "time": -1},
|
| 23 |
+
"magnetic_density": {"length": -One/2, "mass": One/2, "time": -1},
|
| 24 |
+
"magnetic_flux": {"length": 3*One/2, "mass": One/2, "time": -1},
|
| 25 |
+
}
|
| 26 |
+
)
|
| 27 |
+
|
| 28 |
+
cgs_gauss = UnitSystem(
|
| 29 |
+
base_units=[centimeter, gram, second],
|
| 30 |
+
units=[],
|
| 31 |
+
name="cgs_gauss",
|
| 32 |
+
dimension_system=dimsys_cgs)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
cgs_gauss.set_quantity_scale_factor(coulombs_constant, 1)
|
| 36 |
+
|
| 37 |
+
cgs_gauss.set_quantity_dimension(statcoulomb, charge)
|
| 38 |
+
cgs_gauss.set_quantity_scale_factor(statcoulomb, centimeter**(S(3)/2)*gram**(S.Half)/second)
|
| 39 |
+
|
| 40 |
+
cgs_gauss.set_quantity_dimension(coulomb, charge)
|
| 41 |
+
|
| 42 |
+
cgs_gauss.set_quantity_dimension(statampere, current)
|
| 43 |
+
cgs_gauss.set_quantity_scale_factor(statampere, statcoulomb/second)
|
| 44 |
+
|
| 45 |
+
cgs_gauss.set_quantity_dimension(statvolt, voltage)
|
| 46 |
+
cgs_gauss.set_quantity_scale_factor(statvolt, erg/statcoulomb)
|
| 47 |
+
|
| 48 |
+
cgs_gauss.set_quantity_dimension(volt, voltage)
|
| 49 |
+
|
| 50 |
+
cgs_gauss.set_quantity_dimension(gauss, magnetic_density)
|
| 51 |
+
cgs_gauss.set_quantity_scale_factor(gauss, sqrt(gram/centimeter)/second)
|
| 52 |
+
|
| 53 |
+
cgs_gauss.set_quantity_dimension(tesla, magnetic_density)
|
| 54 |
+
|
| 55 |
+
cgs_gauss.set_quantity_dimension(maxwell, magnetic_flux)
|
| 56 |
+
cgs_gauss.set_quantity_scale_factor(maxwell, sqrt(centimeter**3*gram)/second)
|
| 57 |
+
|
| 58 |
+
# SI units expressed in CGS-gaussian units:
|
| 59 |
+
cgs_gauss.set_quantity_scale_factor(coulomb, 10*speed_of_light*statcoulomb)
|
| 60 |
+
cgs_gauss.set_quantity_scale_factor(ampere, 10*speed_of_light*statcoulomb/second)
|
| 61 |
+
cgs_gauss.set_quantity_scale_factor(volt, 10**6/speed_of_light*statvolt)
|
| 62 |
+
cgs_gauss.set_quantity_scale_factor(weber, 10**8*maxwell)
|
| 63 |
+
cgs_gauss.set_quantity_scale_factor(tesla, 10**4*gauss)
|
| 64 |
+
cgs_gauss.set_quantity_scale_factor(debye, One/10**18*statcoulomb*centimeter)
|
| 65 |
+
cgs_gauss.set_quantity_scale_factor(oersted, sqrt(gram/centimeter)/second)
|
| 66 |
+
cgs_gauss.set_quantity_scale_factor(ohm, 10**5/speed_of_light**2*second/centimeter)
|
| 67 |
+
cgs_gauss.set_quantity_scale_factor(farad, One/10**5*speed_of_light**2*centimeter)
|
| 68 |
+
cgs_gauss.set_quantity_scale_factor(henry, 10**5/speed_of_light**2/centimeter*second**2)
|
| 69 |
+
|
| 70 |
+
# Coulomb's constant:
|
| 71 |
+
cgs_gauss.set_quantity_dimension(coulomb_constant, 1)
|
| 72 |
+
cgs_gauss.set_quantity_scale_factor(coulomb_constant, 1)
|
| 73 |
+
|
| 74 |
+
__all__ = [
|
| 75 |
+
'ohm', 'tesla', 'maxwell', 'speed_of_light', 'volt', 'second', 'voltage',
|
| 76 |
+
'debye', 'dimsys_length_weight_time', 'centimeter', 'coulomb_constant',
|
| 77 |
+
'farad', 'sqrt', 'UnitSystem', 'current', 'charge', 'weber', 'gram',
|
| 78 |
+
'statcoulomb', 'gauss', 'S', 'statvolt', 'oersted', 'statampere',
|
| 79 |
+
'dimsys_cgs', 'coulomb', 'magnetic_density', 'magnetic_flux', 'One',
|
| 80 |
+
'length', 'erg', 'mass', 'coulombs_constant', 'henry', 'ampere',
|
| 81 |
+
'cgs_gauss',
|
| 82 |
+
]
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/length_weight_time.py
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.singleton import S
|
| 2 |
+
|
| 3 |
+
from sympy.core.numbers import pi
|
| 4 |
+
|
| 5 |
+
from sympy.physics.units import DimensionSystem, hertz, kilogram
|
| 6 |
+
from sympy.physics.units.definitions import (
|
| 7 |
+
G, Hz, J, N, Pa, W, c, g, kg, m, s, meter, gram, second, newton,
|
| 8 |
+
joule, watt, pascal)
|
| 9 |
+
from sympy.physics.units.definitions.dimension_definitions import (
|
| 10 |
+
acceleration, action, energy, force, frequency, momentum,
|
| 11 |
+
power, pressure, velocity, length, mass, time)
|
| 12 |
+
from sympy.physics.units.prefixes import PREFIXES, prefix_unit
|
| 13 |
+
from sympy.physics.units.prefixes import (
|
| 14 |
+
kibi, mebi, gibi, tebi, pebi, exbi
|
| 15 |
+
)
|
| 16 |
+
from sympy.physics.units.definitions import (
|
| 17 |
+
cd, K, coulomb, volt, ohm, siemens, farad, henry, tesla, weber, dioptre,
|
| 18 |
+
lux, katal, gray, becquerel, inch, hectare, liter, julian_year,
|
| 19 |
+
gravitational_constant, speed_of_light, elementary_charge, planck, hbar,
|
| 20 |
+
electronvolt, avogadro_number, avogadro_constant, boltzmann_constant,
|
| 21 |
+
stefan_boltzmann_constant, atomic_mass_constant, molar_gas_constant,
|
| 22 |
+
faraday_constant, josephson_constant, von_klitzing_constant,
|
| 23 |
+
acceleration_due_to_gravity, magnetic_constant, vacuum_permittivity,
|
| 24 |
+
vacuum_impedance, coulomb_constant, atmosphere, bar, pound, psi, mmHg,
|
| 25 |
+
milli_mass_unit, quart, lightyear, astronomical_unit, planck_mass,
|
| 26 |
+
planck_time, planck_temperature, planck_length, planck_charge,
|
| 27 |
+
planck_area, planck_volume, planck_momentum, planck_energy, planck_force,
|
| 28 |
+
planck_power, planck_density, planck_energy_density, planck_intensity,
|
| 29 |
+
planck_angular_frequency, planck_pressure, planck_current, planck_voltage,
|
| 30 |
+
planck_impedance, planck_acceleration, bit, byte, kibibyte, mebibyte,
|
| 31 |
+
gibibyte, tebibyte, pebibyte, exbibyte, curie, rutherford, radian, degree,
|
| 32 |
+
steradian, angular_mil, atomic_mass_unit, gee, kPa, ampere, u0, kelvin,
|
| 33 |
+
mol, mole, candela, electric_constant, boltzmann, angstrom
|
| 34 |
+
)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
dimsys_length_weight_time = DimensionSystem([
|
| 38 |
+
# Dimensional dependencies for MKS base dimensions
|
| 39 |
+
length,
|
| 40 |
+
mass,
|
| 41 |
+
time,
|
| 42 |
+
], dimensional_dependencies={
|
| 43 |
+
# Dimensional dependencies for derived dimensions
|
| 44 |
+
"velocity": {"length": 1, "time": -1},
|
| 45 |
+
"acceleration": {"length": 1, "time": -2},
|
| 46 |
+
"momentum": {"mass": 1, "length": 1, "time": -1},
|
| 47 |
+
"force": {"mass": 1, "length": 1, "time": -2},
|
| 48 |
+
"energy": {"mass": 1, "length": 2, "time": -2},
|
| 49 |
+
"power": {"length": 2, "mass": 1, "time": -3},
|
| 50 |
+
"pressure": {"mass": 1, "length": -1, "time": -2},
|
| 51 |
+
"frequency": {"time": -1},
|
| 52 |
+
"action": {"length": 2, "mass": 1, "time": -1},
|
| 53 |
+
"area": {"length": 2},
|
| 54 |
+
"volume": {"length": 3},
|
| 55 |
+
})
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
One = S.One
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
# Base units:
|
| 62 |
+
dimsys_length_weight_time.set_quantity_dimension(meter, length)
|
| 63 |
+
dimsys_length_weight_time.set_quantity_scale_factor(meter, One)
|
| 64 |
+
|
| 65 |
+
# gram; used to define its prefixed units
|
| 66 |
+
dimsys_length_weight_time.set_quantity_dimension(gram, mass)
|
| 67 |
+
dimsys_length_weight_time.set_quantity_scale_factor(gram, One)
|
| 68 |
+
|
| 69 |
+
dimsys_length_weight_time.set_quantity_dimension(second, time)
|
| 70 |
+
dimsys_length_weight_time.set_quantity_scale_factor(second, One)
|
| 71 |
+
|
| 72 |
+
# derived units
|
| 73 |
+
|
| 74 |
+
dimsys_length_weight_time.set_quantity_dimension(newton, force)
|
| 75 |
+
dimsys_length_weight_time.set_quantity_scale_factor(newton, kilogram*meter/second**2)
|
| 76 |
+
|
| 77 |
+
dimsys_length_weight_time.set_quantity_dimension(joule, energy)
|
| 78 |
+
dimsys_length_weight_time.set_quantity_scale_factor(joule, newton*meter)
|
| 79 |
+
|
| 80 |
+
dimsys_length_weight_time.set_quantity_dimension(watt, power)
|
| 81 |
+
dimsys_length_weight_time.set_quantity_scale_factor(watt, joule/second)
|
| 82 |
+
|
| 83 |
+
dimsys_length_weight_time.set_quantity_dimension(pascal, pressure)
|
| 84 |
+
dimsys_length_weight_time.set_quantity_scale_factor(pascal, newton/meter**2)
|
| 85 |
+
|
| 86 |
+
dimsys_length_weight_time.set_quantity_dimension(hertz, frequency)
|
| 87 |
+
dimsys_length_weight_time.set_quantity_scale_factor(hertz, One)
|
| 88 |
+
|
| 89 |
+
# Other derived units:
|
| 90 |
+
|
| 91 |
+
dimsys_length_weight_time.set_quantity_dimension(dioptre, 1 / length)
|
| 92 |
+
dimsys_length_weight_time.set_quantity_scale_factor(dioptre, 1/meter)
|
| 93 |
+
|
| 94 |
+
# Common volume and area units
|
| 95 |
+
|
| 96 |
+
dimsys_length_weight_time.set_quantity_dimension(hectare, length**2)
|
| 97 |
+
dimsys_length_weight_time.set_quantity_scale_factor(hectare, (meter**2)*(10000))
|
| 98 |
+
|
| 99 |
+
dimsys_length_weight_time.set_quantity_dimension(liter, length**3)
|
| 100 |
+
dimsys_length_weight_time.set_quantity_scale_factor(liter, meter**3/1000)
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
# Newton constant
|
| 104 |
+
# REF: NIST SP 959 (June 2019)
|
| 105 |
+
|
| 106 |
+
dimsys_length_weight_time.set_quantity_dimension(gravitational_constant, length ** 3 * mass ** -1 * time ** -2)
|
| 107 |
+
dimsys_length_weight_time.set_quantity_scale_factor(gravitational_constant, 6.67430e-11*m**3/(kg*s**2))
|
| 108 |
+
|
| 109 |
+
# speed of light
|
| 110 |
+
|
| 111 |
+
dimsys_length_weight_time.set_quantity_dimension(speed_of_light, velocity)
|
| 112 |
+
dimsys_length_weight_time.set_quantity_scale_factor(speed_of_light, 299792458*meter/second)
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
# Planck constant
|
| 116 |
+
# REF: NIST SP 959 (June 2019)
|
| 117 |
+
|
| 118 |
+
dimsys_length_weight_time.set_quantity_dimension(planck, action)
|
| 119 |
+
dimsys_length_weight_time.set_quantity_scale_factor(planck, 6.62607015e-34*joule*second)
|
| 120 |
+
|
| 121 |
+
# Reduced Planck constant
|
| 122 |
+
# REF: NIST SP 959 (June 2019)
|
| 123 |
+
|
| 124 |
+
dimsys_length_weight_time.set_quantity_dimension(hbar, action)
|
| 125 |
+
dimsys_length_weight_time.set_quantity_scale_factor(hbar, planck / (2 * pi))
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
__all__ = [
|
| 129 |
+
'mmHg', 'atmosphere', 'newton', 'meter', 'vacuum_permittivity', 'pascal',
|
| 130 |
+
'magnetic_constant', 'angular_mil', 'julian_year', 'weber', 'exbibyte',
|
| 131 |
+
'liter', 'molar_gas_constant', 'faraday_constant', 'avogadro_constant',
|
| 132 |
+
'planck_momentum', 'planck_density', 'gee', 'mol', 'bit', 'gray', 'kibi',
|
| 133 |
+
'bar', 'curie', 'prefix_unit', 'PREFIXES', 'planck_time', 'gram',
|
| 134 |
+
'candela', 'force', 'planck_intensity', 'energy', 'becquerel',
|
| 135 |
+
'planck_acceleration', 'speed_of_light', 'dioptre', 'second', 'frequency',
|
| 136 |
+
'Hz', 'power', 'lux', 'planck_current', 'momentum', 'tebibyte',
|
| 137 |
+
'planck_power', 'degree', 'mebi', 'K', 'planck_volume',
|
| 138 |
+
'quart', 'pressure', 'W', 'joule', 'boltzmann_constant', 'c', 'g',
|
| 139 |
+
'planck_force', 'exbi', 's', 'watt', 'action', 'hbar', 'gibibyte',
|
| 140 |
+
'DimensionSystem', 'cd', 'volt', 'planck_charge', 'angstrom',
|
| 141 |
+
'dimsys_length_weight_time', 'pebi', 'vacuum_impedance', 'planck',
|
| 142 |
+
'farad', 'gravitational_constant', 'u0', 'hertz', 'tesla', 'steradian',
|
| 143 |
+
'josephson_constant', 'planck_area', 'stefan_boltzmann_constant',
|
| 144 |
+
'astronomical_unit', 'J', 'N', 'planck_voltage', 'planck_energy',
|
| 145 |
+
'atomic_mass_constant', 'rutherford', 'elementary_charge', 'Pa',
|
| 146 |
+
'planck_mass', 'henry', 'planck_angular_frequency', 'ohm', 'pound',
|
| 147 |
+
'planck_pressure', 'G', 'avogadro_number', 'psi', 'von_klitzing_constant',
|
| 148 |
+
'planck_length', 'radian', 'mole', 'acceleration',
|
| 149 |
+
'planck_energy_density', 'mebibyte', 'length',
|
| 150 |
+
'acceleration_due_to_gravity', 'planck_temperature', 'tebi', 'inch',
|
| 151 |
+
'electronvolt', 'coulomb_constant', 'kelvin', 'kPa', 'boltzmann',
|
| 152 |
+
'milli_mass_unit', 'gibi', 'planck_impedance', 'electric_constant', 'kg',
|
| 153 |
+
'coulomb', 'siemens', 'byte', 'atomic_mass_unit', 'm', 'kibibyte',
|
| 154 |
+
'kilogram', 'lightyear', 'mass', 'time', 'pebibyte', 'velocity',
|
| 155 |
+
'ampere', 'katal',
|
| 156 |
+
]
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/mks.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
MKS unit system.
|
| 3 |
+
|
| 4 |
+
MKS stands for "meter, kilogram, second".
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from sympy.physics.units import UnitSystem
|
| 8 |
+
from sympy.physics.units.definitions import gravitational_constant, hertz, joule, newton, pascal, watt, speed_of_light, gram, kilogram, meter, second
|
| 9 |
+
from sympy.physics.units.definitions.dimension_definitions import (
|
| 10 |
+
acceleration, action, energy, force, frequency, momentum,
|
| 11 |
+
power, pressure, velocity, length, mass, time)
|
| 12 |
+
from sympy.physics.units.prefixes import PREFIXES, prefix_unit
|
| 13 |
+
from sympy.physics.units.systems.length_weight_time import dimsys_length_weight_time
|
| 14 |
+
|
| 15 |
+
dims = (velocity, acceleration, momentum, force, energy, power, pressure,
|
| 16 |
+
frequency, action)
|
| 17 |
+
|
| 18 |
+
units = [meter, gram, second, joule, newton, watt, pascal, hertz]
|
| 19 |
+
all_units = []
|
| 20 |
+
|
| 21 |
+
# Prefixes of units like gram, joule, newton etc get added using `prefix_unit`
|
| 22 |
+
# in the for loop, but the actual units have to be added manually.
|
| 23 |
+
all_units.extend([gram, joule, newton, watt, pascal, hertz])
|
| 24 |
+
|
| 25 |
+
for u in units:
|
| 26 |
+
all_units.extend(prefix_unit(u, PREFIXES))
|
| 27 |
+
all_units.extend([gravitational_constant, speed_of_light])
|
| 28 |
+
|
| 29 |
+
# unit system
|
| 30 |
+
MKS = UnitSystem(base_units=(meter, kilogram, second), units=all_units, name="MKS", dimension_system=dimsys_length_weight_time, derived_units={
|
| 31 |
+
power: watt,
|
| 32 |
+
time: second,
|
| 33 |
+
pressure: pascal,
|
| 34 |
+
length: meter,
|
| 35 |
+
frequency: hertz,
|
| 36 |
+
mass: kilogram,
|
| 37 |
+
force: newton,
|
| 38 |
+
energy: joule,
|
| 39 |
+
velocity: meter/second,
|
| 40 |
+
acceleration: meter/(second**2),
|
| 41 |
+
})
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
__all__ = [
|
| 45 |
+
'MKS', 'units', 'all_units', 'dims',
|
| 46 |
+
]
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/mksa.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
MKS unit system.
|
| 3 |
+
|
| 4 |
+
MKS stands for "meter, kilogram, second, ampere".
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
from __future__ import annotations
|
| 8 |
+
|
| 9 |
+
from sympy.physics.units.definitions import Z0, ampere, coulomb, farad, henry, siemens, tesla, volt, weber, ohm
|
| 10 |
+
from sympy.physics.units.definitions.dimension_definitions import (
|
| 11 |
+
capacitance, charge, conductance, current, impedance, inductance,
|
| 12 |
+
magnetic_density, magnetic_flux, voltage)
|
| 13 |
+
from sympy.physics.units.prefixes import PREFIXES, prefix_unit
|
| 14 |
+
from sympy.physics.units.systems.mks import MKS, dimsys_length_weight_time
|
| 15 |
+
from sympy.physics.units.quantities import Quantity
|
| 16 |
+
|
| 17 |
+
dims = (voltage, impedance, conductance, current, capacitance, inductance, charge,
|
| 18 |
+
magnetic_density, magnetic_flux)
|
| 19 |
+
|
| 20 |
+
units = [ampere, volt, ohm, siemens, farad, henry, coulomb, tesla, weber]
|
| 21 |
+
|
| 22 |
+
all_units: list[Quantity] = []
|
| 23 |
+
for u in units:
|
| 24 |
+
all_units.extend(prefix_unit(u, PREFIXES))
|
| 25 |
+
all_units.extend(units)
|
| 26 |
+
|
| 27 |
+
all_units.append(Z0)
|
| 28 |
+
|
| 29 |
+
dimsys_MKSA = dimsys_length_weight_time.extend([
|
| 30 |
+
# Dimensional dependencies for base dimensions (MKSA not in MKS)
|
| 31 |
+
current,
|
| 32 |
+
], new_dim_deps={
|
| 33 |
+
# Dimensional dependencies for derived dimensions
|
| 34 |
+
"voltage": {"mass": 1, "length": 2, "current": -1, "time": -3},
|
| 35 |
+
"impedance": {"mass": 1, "length": 2, "current": -2, "time": -3},
|
| 36 |
+
"conductance": {"mass": -1, "length": -2, "current": 2, "time": 3},
|
| 37 |
+
"capacitance": {"mass": -1, "length": -2, "current": 2, "time": 4},
|
| 38 |
+
"inductance": {"mass": 1, "length": 2, "current": -2, "time": -2},
|
| 39 |
+
"charge": {"current": 1, "time": 1},
|
| 40 |
+
"magnetic_density": {"mass": 1, "current": -1, "time": -2},
|
| 41 |
+
"magnetic_flux": {"length": 2, "mass": 1, "current": -1, "time": -2},
|
| 42 |
+
})
|
| 43 |
+
|
| 44 |
+
MKSA = MKS.extend(base=(ampere,), units=all_units, name='MKSA', dimension_system=dimsys_MKSA, derived_units={
|
| 45 |
+
magnetic_flux: weber,
|
| 46 |
+
impedance: ohm,
|
| 47 |
+
current: ampere,
|
| 48 |
+
voltage: volt,
|
| 49 |
+
inductance: henry,
|
| 50 |
+
conductance: siemens,
|
| 51 |
+
magnetic_density: tesla,
|
| 52 |
+
charge: coulomb,
|
| 53 |
+
capacitance: farad,
|
| 54 |
+
})
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/natural.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Naturalunit system.
|
| 3 |
+
|
| 4 |
+
The natural system comes from "setting c = 1, hbar = 1". From the computer
|
| 5 |
+
point of view it means that we use velocity and action instead of length and
|
| 6 |
+
time. Moreover instead of mass we use energy.
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
from sympy.physics.units import DimensionSystem
|
| 10 |
+
from sympy.physics.units.definitions import c, eV, hbar
|
| 11 |
+
from sympy.physics.units.definitions.dimension_definitions import (
|
| 12 |
+
action, energy, force, frequency, length, mass, momentum,
|
| 13 |
+
power, time, velocity)
|
| 14 |
+
from sympy.physics.units.prefixes import PREFIXES, prefix_unit
|
| 15 |
+
from sympy.physics.units.unitsystem import UnitSystem
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
# dimension system
|
| 19 |
+
_natural_dim = DimensionSystem(
|
| 20 |
+
base_dims=(action, energy, velocity),
|
| 21 |
+
derived_dims=(length, mass, time, momentum, force, power, frequency)
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
units = prefix_unit(eV, PREFIXES)
|
| 25 |
+
|
| 26 |
+
# unit system
|
| 27 |
+
natural = UnitSystem(base_units=(hbar, eV, c), units=units, name="Natural system")
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/si.py
ADDED
|
@@ -0,0 +1,377 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
SI unit system.
|
| 3 |
+
Based on MKSA, which stands for "meter, kilogram, second, ampere".
|
| 4 |
+
Added kelvin, candela and mole.
|
| 5 |
+
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
from __future__ import annotations
|
| 9 |
+
|
| 10 |
+
from sympy.physics.units import DimensionSystem, Dimension, dHg0
|
| 11 |
+
|
| 12 |
+
from sympy.physics.units.quantities import Quantity
|
| 13 |
+
|
| 14 |
+
from sympy.core.numbers import (Rational, pi)
|
| 15 |
+
from sympy.core.singleton import S
|
| 16 |
+
from sympy.functions.elementary.miscellaneous import sqrt
|
| 17 |
+
from sympy.physics.units.definitions.dimension_definitions import (
|
| 18 |
+
acceleration, action, current, impedance, length, mass, time, velocity,
|
| 19 |
+
amount_of_substance, temperature, information, frequency, force, pressure,
|
| 20 |
+
energy, power, charge, voltage, capacitance, conductance, magnetic_flux,
|
| 21 |
+
magnetic_density, inductance, luminous_intensity
|
| 22 |
+
)
|
| 23 |
+
from sympy.physics.units.definitions import (
|
| 24 |
+
kilogram, newton, second, meter, gram, cd, K, joule, watt, pascal, hertz,
|
| 25 |
+
coulomb, volt, ohm, siemens, farad, henry, tesla, weber, dioptre, lux,
|
| 26 |
+
katal, gray, becquerel, inch, liter, julian_year, gravitational_constant,
|
| 27 |
+
speed_of_light, elementary_charge, planck, hbar, electronvolt,
|
| 28 |
+
avogadro_number, avogadro_constant, boltzmann_constant, electron_rest_mass,
|
| 29 |
+
stefan_boltzmann_constant, Da, atomic_mass_constant, molar_gas_constant,
|
| 30 |
+
faraday_constant, josephson_constant, von_klitzing_constant,
|
| 31 |
+
acceleration_due_to_gravity, magnetic_constant, vacuum_permittivity,
|
| 32 |
+
vacuum_impedance, coulomb_constant, atmosphere, bar, pound, psi, mmHg,
|
| 33 |
+
milli_mass_unit, quart, lightyear, astronomical_unit, planck_mass,
|
| 34 |
+
planck_time, planck_temperature, planck_length, planck_charge, planck_area,
|
| 35 |
+
planck_volume, planck_momentum, planck_energy, planck_force, planck_power,
|
| 36 |
+
planck_density, planck_energy_density, planck_intensity,
|
| 37 |
+
planck_angular_frequency, planck_pressure, planck_current, planck_voltage,
|
| 38 |
+
planck_impedance, planck_acceleration, bit, byte, kibibyte, mebibyte,
|
| 39 |
+
gibibyte, tebibyte, pebibyte, exbibyte, curie, rutherford, radian, degree,
|
| 40 |
+
steradian, angular_mil, atomic_mass_unit, gee, kPa, ampere, u0, c, kelvin,
|
| 41 |
+
mol, mole, candela, m, kg, s, electric_constant, G, boltzmann
|
| 42 |
+
)
|
| 43 |
+
from sympy.physics.units.prefixes import PREFIXES, prefix_unit
|
| 44 |
+
from sympy.physics.units.systems.mksa import MKSA, dimsys_MKSA
|
| 45 |
+
|
| 46 |
+
derived_dims = (frequency, force, pressure, energy, power, charge, voltage,
|
| 47 |
+
capacitance, conductance, magnetic_flux,
|
| 48 |
+
magnetic_density, inductance, luminous_intensity)
|
| 49 |
+
base_dims = (amount_of_substance, luminous_intensity, temperature)
|
| 50 |
+
|
| 51 |
+
units = [mol, cd, K, lux, hertz, newton, pascal, joule, watt, coulomb, volt,
|
| 52 |
+
farad, ohm, siemens, weber, tesla, henry, candela, lux, becquerel,
|
| 53 |
+
gray, katal]
|
| 54 |
+
|
| 55 |
+
all_units: list[Quantity] = []
|
| 56 |
+
for u in units:
|
| 57 |
+
all_units.extend(prefix_unit(u, PREFIXES))
|
| 58 |
+
|
| 59 |
+
all_units.extend(units)
|
| 60 |
+
all_units.extend([mol, cd, K, lux])
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
dimsys_SI = dimsys_MKSA.extend(
|
| 64 |
+
[
|
| 65 |
+
# Dimensional dependencies for other base dimensions:
|
| 66 |
+
temperature,
|
| 67 |
+
amount_of_substance,
|
| 68 |
+
luminous_intensity,
|
| 69 |
+
])
|
| 70 |
+
|
| 71 |
+
dimsys_default = dimsys_SI.extend(
|
| 72 |
+
[information],
|
| 73 |
+
)
|
| 74 |
+
|
| 75 |
+
SI = MKSA.extend(base=(mol, cd, K), units=all_units, name='SI', dimension_system=dimsys_SI, derived_units={
|
| 76 |
+
power: watt,
|
| 77 |
+
magnetic_flux: weber,
|
| 78 |
+
time: second,
|
| 79 |
+
impedance: ohm,
|
| 80 |
+
pressure: pascal,
|
| 81 |
+
current: ampere,
|
| 82 |
+
voltage: volt,
|
| 83 |
+
length: meter,
|
| 84 |
+
frequency: hertz,
|
| 85 |
+
inductance: henry,
|
| 86 |
+
temperature: kelvin,
|
| 87 |
+
amount_of_substance: mole,
|
| 88 |
+
luminous_intensity: candela,
|
| 89 |
+
conductance: siemens,
|
| 90 |
+
mass: kilogram,
|
| 91 |
+
magnetic_density: tesla,
|
| 92 |
+
charge: coulomb,
|
| 93 |
+
force: newton,
|
| 94 |
+
capacitance: farad,
|
| 95 |
+
energy: joule,
|
| 96 |
+
velocity: meter/second,
|
| 97 |
+
})
|
| 98 |
+
|
| 99 |
+
One = S.One
|
| 100 |
+
|
| 101 |
+
SI.set_quantity_dimension(radian, One)
|
| 102 |
+
|
| 103 |
+
SI.set_quantity_scale_factor(ampere, One)
|
| 104 |
+
|
| 105 |
+
SI.set_quantity_scale_factor(kelvin, One)
|
| 106 |
+
|
| 107 |
+
SI.set_quantity_scale_factor(mole, One)
|
| 108 |
+
|
| 109 |
+
SI.set_quantity_scale_factor(candela, One)
|
| 110 |
+
|
| 111 |
+
# MKSA extension to MKS: derived units
|
| 112 |
+
|
| 113 |
+
SI.set_quantity_scale_factor(coulomb, One)
|
| 114 |
+
|
| 115 |
+
SI.set_quantity_scale_factor(volt, joule/coulomb)
|
| 116 |
+
|
| 117 |
+
SI.set_quantity_scale_factor(ohm, volt/ampere)
|
| 118 |
+
|
| 119 |
+
SI.set_quantity_scale_factor(siemens, ampere/volt)
|
| 120 |
+
|
| 121 |
+
SI.set_quantity_scale_factor(farad, coulomb/volt)
|
| 122 |
+
|
| 123 |
+
SI.set_quantity_scale_factor(henry, volt*second/ampere)
|
| 124 |
+
|
| 125 |
+
SI.set_quantity_scale_factor(tesla, volt*second/meter**2)
|
| 126 |
+
|
| 127 |
+
SI.set_quantity_scale_factor(weber, joule/ampere)
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
SI.set_quantity_dimension(lux, luminous_intensity / length ** 2)
|
| 131 |
+
SI.set_quantity_scale_factor(lux, steradian*candela/meter**2)
|
| 132 |
+
|
| 133 |
+
# katal is the SI unit of catalytic activity
|
| 134 |
+
|
| 135 |
+
SI.set_quantity_dimension(katal, amount_of_substance / time)
|
| 136 |
+
SI.set_quantity_scale_factor(katal, mol/second)
|
| 137 |
+
|
| 138 |
+
# gray is the SI unit of absorbed dose
|
| 139 |
+
|
| 140 |
+
SI.set_quantity_dimension(gray, energy / mass)
|
| 141 |
+
SI.set_quantity_scale_factor(gray, meter**2/second**2)
|
| 142 |
+
|
| 143 |
+
# becquerel is the SI unit of radioactivity
|
| 144 |
+
|
| 145 |
+
SI.set_quantity_dimension(becquerel, 1 / time)
|
| 146 |
+
SI.set_quantity_scale_factor(becquerel, 1/second)
|
| 147 |
+
|
| 148 |
+
#### CONSTANTS ####
|
| 149 |
+
|
| 150 |
+
# elementary charge
|
| 151 |
+
# REF: NIST SP 959 (June 2019)
|
| 152 |
+
|
| 153 |
+
SI.set_quantity_dimension(elementary_charge, charge)
|
| 154 |
+
SI.set_quantity_scale_factor(elementary_charge, 1.602176634e-19*coulomb)
|
| 155 |
+
|
| 156 |
+
# Electronvolt
|
| 157 |
+
# REF: NIST SP 959 (June 2019)
|
| 158 |
+
|
| 159 |
+
SI.set_quantity_dimension(electronvolt, energy)
|
| 160 |
+
SI.set_quantity_scale_factor(electronvolt, 1.602176634e-19*joule)
|
| 161 |
+
|
| 162 |
+
# Avogadro number
|
| 163 |
+
# REF: NIST SP 959 (June 2019)
|
| 164 |
+
|
| 165 |
+
SI.set_quantity_dimension(avogadro_number, One)
|
| 166 |
+
SI.set_quantity_scale_factor(avogadro_number, 6.02214076e23)
|
| 167 |
+
|
| 168 |
+
# Avogadro constant
|
| 169 |
+
|
| 170 |
+
SI.set_quantity_dimension(avogadro_constant, amount_of_substance ** -1)
|
| 171 |
+
SI.set_quantity_scale_factor(avogadro_constant, avogadro_number / mol)
|
| 172 |
+
|
| 173 |
+
# Boltzmann constant
|
| 174 |
+
# REF: NIST SP 959 (June 2019)
|
| 175 |
+
|
| 176 |
+
SI.set_quantity_dimension(boltzmann_constant, energy / temperature)
|
| 177 |
+
SI.set_quantity_scale_factor(boltzmann_constant, 1.380649e-23*joule/kelvin)
|
| 178 |
+
|
| 179 |
+
# Stefan-Boltzmann constant
|
| 180 |
+
# REF: NIST SP 959 (June 2019)
|
| 181 |
+
|
| 182 |
+
SI.set_quantity_dimension(stefan_boltzmann_constant, energy * time ** -1 * length ** -2 * temperature ** -4)
|
| 183 |
+
SI.set_quantity_scale_factor(stefan_boltzmann_constant, pi**2 * boltzmann_constant**4 / (60 * hbar**3 * speed_of_light ** 2))
|
| 184 |
+
|
| 185 |
+
# Atomic mass
|
| 186 |
+
# REF: NIST SP 959 (June 2019)
|
| 187 |
+
|
| 188 |
+
SI.set_quantity_dimension(atomic_mass_constant, mass)
|
| 189 |
+
SI.set_quantity_scale_factor(atomic_mass_constant, 1.66053906660e-24*gram)
|
| 190 |
+
|
| 191 |
+
# Molar gas constant
|
| 192 |
+
# REF: NIST SP 959 (June 2019)
|
| 193 |
+
|
| 194 |
+
SI.set_quantity_dimension(molar_gas_constant, energy / (temperature * amount_of_substance))
|
| 195 |
+
SI.set_quantity_scale_factor(molar_gas_constant, boltzmann_constant * avogadro_constant)
|
| 196 |
+
|
| 197 |
+
# Faraday constant
|
| 198 |
+
|
| 199 |
+
SI.set_quantity_dimension(faraday_constant, charge / amount_of_substance)
|
| 200 |
+
SI.set_quantity_scale_factor(faraday_constant, elementary_charge * avogadro_constant)
|
| 201 |
+
|
| 202 |
+
# Josephson constant
|
| 203 |
+
|
| 204 |
+
SI.set_quantity_dimension(josephson_constant, frequency / voltage)
|
| 205 |
+
SI.set_quantity_scale_factor(josephson_constant, 0.5 * planck / elementary_charge)
|
| 206 |
+
|
| 207 |
+
# Von Klitzing constant
|
| 208 |
+
|
| 209 |
+
SI.set_quantity_dimension(von_klitzing_constant, voltage / current)
|
| 210 |
+
SI.set_quantity_scale_factor(von_klitzing_constant, hbar / elementary_charge ** 2)
|
| 211 |
+
|
| 212 |
+
# Acceleration due to gravity (on the Earth surface)
|
| 213 |
+
|
| 214 |
+
SI.set_quantity_dimension(acceleration_due_to_gravity, acceleration)
|
| 215 |
+
SI.set_quantity_scale_factor(acceleration_due_to_gravity, 9.80665*meter/second**2)
|
| 216 |
+
|
| 217 |
+
# magnetic constant:
|
| 218 |
+
|
| 219 |
+
SI.set_quantity_dimension(magnetic_constant, force / current ** 2)
|
| 220 |
+
SI.set_quantity_scale_factor(magnetic_constant, 4*pi/10**7 * newton/ampere**2)
|
| 221 |
+
|
| 222 |
+
# electric constant:
|
| 223 |
+
|
| 224 |
+
SI.set_quantity_dimension(vacuum_permittivity, capacitance / length)
|
| 225 |
+
SI.set_quantity_scale_factor(vacuum_permittivity, 1/(u0 * c**2))
|
| 226 |
+
|
| 227 |
+
# vacuum impedance:
|
| 228 |
+
|
| 229 |
+
SI.set_quantity_dimension(vacuum_impedance, impedance)
|
| 230 |
+
SI.set_quantity_scale_factor(vacuum_impedance, u0 * c)
|
| 231 |
+
|
| 232 |
+
# Electron rest mass
|
| 233 |
+
SI.set_quantity_dimension(electron_rest_mass, mass)
|
| 234 |
+
SI.set_quantity_scale_factor(electron_rest_mass, 9.1093837015e-31*kilogram)
|
| 235 |
+
|
| 236 |
+
# Coulomb's constant:
|
| 237 |
+
SI.set_quantity_dimension(coulomb_constant, force * length ** 2 / charge ** 2)
|
| 238 |
+
SI.set_quantity_scale_factor(coulomb_constant, 1/(4*pi*vacuum_permittivity))
|
| 239 |
+
|
| 240 |
+
SI.set_quantity_dimension(psi, pressure)
|
| 241 |
+
SI.set_quantity_scale_factor(psi, pound * gee / inch ** 2)
|
| 242 |
+
|
| 243 |
+
SI.set_quantity_dimension(mmHg, pressure)
|
| 244 |
+
SI.set_quantity_scale_factor(mmHg, dHg0 * acceleration_due_to_gravity * kilogram / meter**2)
|
| 245 |
+
|
| 246 |
+
SI.set_quantity_dimension(milli_mass_unit, mass)
|
| 247 |
+
SI.set_quantity_scale_factor(milli_mass_unit, atomic_mass_unit/1000)
|
| 248 |
+
|
| 249 |
+
SI.set_quantity_dimension(quart, length ** 3)
|
| 250 |
+
SI.set_quantity_scale_factor(quart, Rational(231, 4) * inch**3)
|
| 251 |
+
|
| 252 |
+
# Other convenient units and magnitudes
|
| 253 |
+
|
| 254 |
+
SI.set_quantity_dimension(lightyear, length)
|
| 255 |
+
SI.set_quantity_scale_factor(lightyear, speed_of_light*julian_year)
|
| 256 |
+
|
| 257 |
+
SI.set_quantity_dimension(astronomical_unit, length)
|
| 258 |
+
SI.set_quantity_scale_factor(astronomical_unit, 149597870691*meter)
|
| 259 |
+
|
| 260 |
+
# Fundamental Planck units:
|
| 261 |
+
|
| 262 |
+
SI.set_quantity_dimension(planck_mass, mass)
|
| 263 |
+
SI.set_quantity_scale_factor(planck_mass, sqrt(hbar*speed_of_light/G))
|
| 264 |
+
|
| 265 |
+
SI.set_quantity_dimension(planck_time, time)
|
| 266 |
+
SI.set_quantity_scale_factor(planck_time, sqrt(hbar*G/speed_of_light**5))
|
| 267 |
+
|
| 268 |
+
SI.set_quantity_dimension(planck_temperature, temperature)
|
| 269 |
+
SI.set_quantity_scale_factor(planck_temperature, sqrt(hbar*speed_of_light**5/G/boltzmann**2))
|
| 270 |
+
|
| 271 |
+
SI.set_quantity_dimension(planck_length, length)
|
| 272 |
+
SI.set_quantity_scale_factor(planck_length, sqrt(hbar*G/speed_of_light**3))
|
| 273 |
+
|
| 274 |
+
SI.set_quantity_dimension(planck_charge, charge)
|
| 275 |
+
SI.set_quantity_scale_factor(planck_charge, sqrt(4*pi*electric_constant*hbar*speed_of_light))
|
| 276 |
+
|
| 277 |
+
# Derived Planck units:
|
| 278 |
+
|
| 279 |
+
SI.set_quantity_dimension(planck_area, length ** 2)
|
| 280 |
+
SI.set_quantity_scale_factor(planck_area, planck_length**2)
|
| 281 |
+
|
| 282 |
+
SI.set_quantity_dimension(planck_volume, length ** 3)
|
| 283 |
+
SI.set_quantity_scale_factor(planck_volume, planck_length**3)
|
| 284 |
+
|
| 285 |
+
SI.set_quantity_dimension(planck_momentum, mass * velocity)
|
| 286 |
+
SI.set_quantity_scale_factor(planck_momentum, planck_mass * speed_of_light)
|
| 287 |
+
|
| 288 |
+
SI.set_quantity_dimension(planck_energy, energy)
|
| 289 |
+
SI.set_quantity_scale_factor(planck_energy, planck_mass * speed_of_light**2)
|
| 290 |
+
|
| 291 |
+
SI.set_quantity_dimension(planck_force, force)
|
| 292 |
+
SI.set_quantity_scale_factor(planck_force, planck_energy / planck_length)
|
| 293 |
+
|
| 294 |
+
SI.set_quantity_dimension(planck_power, power)
|
| 295 |
+
SI.set_quantity_scale_factor(planck_power, planck_energy / planck_time)
|
| 296 |
+
|
| 297 |
+
SI.set_quantity_dimension(planck_density, mass / length ** 3)
|
| 298 |
+
SI.set_quantity_scale_factor(planck_density, planck_mass / planck_length**3)
|
| 299 |
+
|
| 300 |
+
SI.set_quantity_dimension(planck_energy_density, energy / length ** 3)
|
| 301 |
+
SI.set_quantity_scale_factor(planck_energy_density, planck_energy / planck_length**3)
|
| 302 |
+
|
| 303 |
+
SI.set_quantity_dimension(planck_intensity, mass * time ** (-3))
|
| 304 |
+
SI.set_quantity_scale_factor(planck_intensity, planck_energy_density * speed_of_light)
|
| 305 |
+
|
| 306 |
+
SI.set_quantity_dimension(planck_angular_frequency, 1 / time)
|
| 307 |
+
SI.set_quantity_scale_factor(planck_angular_frequency, 1 / planck_time)
|
| 308 |
+
|
| 309 |
+
SI.set_quantity_dimension(planck_pressure, pressure)
|
| 310 |
+
SI.set_quantity_scale_factor(planck_pressure, planck_force / planck_length**2)
|
| 311 |
+
|
| 312 |
+
SI.set_quantity_dimension(planck_current, current)
|
| 313 |
+
SI.set_quantity_scale_factor(planck_current, planck_charge / planck_time)
|
| 314 |
+
|
| 315 |
+
SI.set_quantity_dimension(planck_voltage, voltage)
|
| 316 |
+
SI.set_quantity_scale_factor(planck_voltage, planck_energy / planck_charge)
|
| 317 |
+
|
| 318 |
+
SI.set_quantity_dimension(planck_impedance, impedance)
|
| 319 |
+
SI.set_quantity_scale_factor(planck_impedance, planck_voltage / planck_current)
|
| 320 |
+
|
| 321 |
+
SI.set_quantity_dimension(planck_acceleration, acceleration)
|
| 322 |
+
SI.set_quantity_scale_factor(planck_acceleration, speed_of_light / planck_time)
|
| 323 |
+
|
| 324 |
+
# Older units for radioactivity
|
| 325 |
+
|
| 326 |
+
SI.set_quantity_dimension(curie, 1 / time)
|
| 327 |
+
SI.set_quantity_scale_factor(curie, 37000000000*becquerel)
|
| 328 |
+
|
| 329 |
+
SI.set_quantity_dimension(rutherford, 1 / time)
|
| 330 |
+
SI.set_quantity_scale_factor(rutherford, 1000000*becquerel)
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
# check that scale factors are the right SI dimensions:
|
| 334 |
+
for _scale_factor, _dimension in zip(
|
| 335 |
+
SI._quantity_scale_factors.values(),
|
| 336 |
+
SI._quantity_dimension_map.values()
|
| 337 |
+
):
|
| 338 |
+
dimex = SI.get_dimensional_expr(_scale_factor)
|
| 339 |
+
if dimex != 1:
|
| 340 |
+
# XXX: equivalent_dims is an instance method taking two arguments in
|
| 341 |
+
# addition to self so this can not work:
|
| 342 |
+
if not DimensionSystem.equivalent_dims(_dimension, Dimension(dimex)): # type: ignore
|
| 343 |
+
raise ValueError("quantity value and dimension mismatch")
|
| 344 |
+
del _scale_factor, _dimension
|
| 345 |
+
|
| 346 |
+
__all__ = [
|
| 347 |
+
'mmHg', 'atmosphere', 'inductance', 'newton', 'meter',
|
| 348 |
+
'vacuum_permittivity', 'pascal', 'magnetic_constant', 'voltage',
|
| 349 |
+
'angular_mil', 'luminous_intensity', 'all_units',
|
| 350 |
+
'julian_year', 'weber', 'exbibyte', 'liter',
|
| 351 |
+
'molar_gas_constant', 'faraday_constant', 'avogadro_constant',
|
| 352 |
+
'lightyear', 'planck_density', 'gee', 'mol', 'bit', 'gray',
|
| 353 |
+
'planck_momentum', 'bar', 'magnetic_density', 'prefix_unit', 'PREFIXES',
|
| 354 |
+
'planck_time', 'dimex', 'gram', 'candela', 'force', 'planck_intensity',
|
| 355 |
+
'energy', 'becquerel', 'planck_acceleration', 'speed_of_light',
|
| 356 |
+
'conductance', 'frequency', 'coulomb_constant', 'degree', 'lux', 'planck',
|
| 357 |
+
'current', 'planck_current', 'tebibyte', 'planck_power', 'MKSA', 'power',
|
| 358 |
+
'K', 'planck_volume', 'quart', 'pressure', 'amount_of_substance',
|
| 359 |
+
'joule', 'boltzmann_constant', 'Dimension', 'c', 'planck_force', 'length',
|
| 360 |
+
'watt', 'action', 'hbar', 'gibibyte', 'DimensionSystem', 'cd', 'volt',
|
| 361 |
+
'planck_charge', 'dioptre', 'vacuum_impedance', 'dimsys_default', 'farad',
|
| 362 |
+
'charge', 'gravitational_constant', 'temperature', 'u0', 'hertz',
|
| 363 |
+
'capacitance', 'tesla', 'steradian', 'planck_mass', 'josephson_constant',
|
| 364 |
+
'planck_area', 'stefan_boltzmann_constant', 'base_dims',
|
| 365 |
+
'astronomical_unit', 'radian', 'planck_voltage', 'impedance',
|
| 366 |
+
'planck_energy', 'Da', 'atomic_mass_constant', 'rutherford', 'second', 'inch',
|
| 367 |
+
'elementary_charge', 'SI', 'electronvolt', 'dimsys_SI', 'henry',
|
| 368 |
+
'planck_angular_frequency', 'ohm', 'pound', 'planck_pressure', 'G', 'psi',
|
| 369 |
+
'dHg0', 'von_klitzing_constant', 'planck_length', 'avogadro_number',
|
| 370 |
+
'mole', 'acceleration', 'information', 'planck_energy_density',
|
| 371 |
+
'mebibyte', 's', 'acceleration_due_to_gravity', 'electron_rest_mass',
|
| 372 |
+
'planck_temperature', 'units', 'mass', 'dimsys_MKSA', 'kelvin', 'kPa',
|
| 373 |
+
'boltzmann', 'milli_mass_unit', 'planck_impedance', 'electric_constant',
|
| 374 |
+
'derived_dims', 'kg', 'coulomb', 'siemens', 'byte', 'magnetic_flux',
|
| 375 |
+
'atomic_mass_unit', 'm', 'kibibyte', 'kilogram', 'One', 'curie', 'u',
|
| 376 |
+
'time', 'pebibyte', 'velocity', 'ampere', 'katal',
|
| 377 |
+
]
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__init__.py
ADDED
|
File without changes
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (226 Bytes). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_dimensions.cpython-311.pyc
ADDED
|
Binary file (14.1 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_dimensionsystem.cpython-311.pyc
ADDED
|
Binary file (6.02 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_prefixes.cpython-311.pyc
ADDED
|
Binary file (5.32 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_quantities.cpython-311.pyc
ADDED
|
Binary file (38.8 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_unitsystem.cpython-311.pyc
ADDED
|
Binary file (6.96 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_util.cpython-311.pyc
ADDED
|
Binary file (20.1 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_dimensions.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.physics.units.systems.si import dimsys_SI
|
| 2 |
+
|
| 3 |
+
from sympy.core.numbers import pi
|
| 4 |
+
from sympy.core.singleton import S
|
| 5 |
+
from sympy.core.symbol import Symbol
|
| 6 |
+
from sympy.functions.elementary.complexes import Abs
|
| 7 |
+
from sympy.functions.elementary.exponential import log
|
| 8 |
+
from sympy.functions.elementary.miscellaneous import sqrt
|
| 9 |
+
from sympy.functions.elementary.trigonometric import (acos, atan2, cos)
|
| 10 |
+
from sympy.physics.units.dimensions import Dimension
|
| 11 |
+
from sympy.physics.units.definitions.dimension_definitions import (
|
| 12 |
+
length, time, mass, force, pressure, angle
|
| 13 |
+
)
|
| 14 |
+
from sympy.physics.units import foot
|
| 15 |
+
from sympy.testing.pytest import raises
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def test_Dimension_definition():
|
| 19 |
+
assert dimsys_SI.get_dimensional_dependencies(length) == {length: 1}
|
| 20 |
+
assert length.name == Symbol("length")
|
| 21 |
+
assert length.symbol == Symbol("L")
|
| 22 |
+
|
| 23 |
+
halflength = sqrt(length)
|
| 24 |
+
assert dimsys_SI.get_dimensional_dependencies(halflength) == {length: S.Half}
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def test_Dimension_error_definition():
|
| 28 |
+
# tuple with more or less than two entries
|
| 29 |
+
raises(TypeError, lambda: Dimension(("length", 1, 2)))
|
| 30 |
+
raises(TypeError, lambda: Dimension(["length"]))
|
| 31 |
+
|
| 32 |
+
# non-number power
|
| 33 |
+
raises(TypeError, lambda: Dimension({"length": "a"}))
|
| 34 |
+
|
| 35 |
+
# non-number with named argument
|
| 36 |
+
raises(TypeError, lambda: Dimension({"length": (1, 2)}))
|
| 37 |
+
|
| 38 |
+
# symbol should by Symbol or str
|
| 39 |
+
raises(AssertionError, lambda: Dimension("length", symbol=1))
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def test_str():
|
| 43 |
+
assert str(Dimension("length")) == "Dimension(length)"
|
| 44 |
+
assert str(Dimension("length", "L")) == "Dimension(length, L)"
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def test_Dimension_properties():
|
| 48 |
+
assert dimsys_SI.is_dimensionless(length) is False
|
| 49 |
+
assert dimsys_SI.is_dimensionless(length/length) is True
|
| 50 |
+
assert dimsys_SI.is_dimensionless(Dimension("undefined")) is False
|
| 51 |
+
|
| 52 |
+
assert length.has_integer_powers(dimsys_SI) is True
|
| 53 |
+
assert (length**(-1)).has_integer_powers(dimsys_SI) is True
|
| 54 |
+
assert (length**1.5).has_integer_powers(dimsys_SI) is False
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def test_Dimension_add_sub():
|
| 58 |
+
assert length + length == length
|
| 59 |
+
assert length - length == length
|
| 60 |
+
assert -length == length
|
| 61 |
+
|
| 62 |
+
raises(TypeError, lambda: length + foot)
|
| 63 |
+
raises(TypeError, lambda: foot + length)
|
| 64 |
+
raises(TypeError, lambda: length - foot)
|
| 65 |
+
raises(TypeError, lambda: foot - length)
|
| 66 |
+
|
| 67 |
+
# issue 14547 - only raise error for dimensional args; allow
|
| 68 |
+
# others to pass
|
| 69 |
+
x = Symbol('x')
|
| 70 |
+
e = length + x
|
| 71 |
+
assert e == x + length and e.is_Add and set(e.args) == {length, x}
|
| 72 |
+
e = length + 1
|
| 73 |
+
assert e == 1 + length == 1 - length and e.is_Add and set(e.args) == {length, 1}
|
| 74 |
+
|
| 75 |
+
assert dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + force) == \
|
| 76 |
+
{length: 1, mass: 1, time: -2}
|
| 77 |
+
assert dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + force -
|
| 78 |
+
pressure * length**2) == \
|
| 79 |
+
{length: 1, mass: 1, time: -2}
|
| 80 |
+
|
| 81 |
+
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + pressure))
|
| 82 |
+
|
| 83 |
+
def test_Dimension_mul_div_exp():
|
| 84 |
+
assert 2*length == length*2 == length/2 == length
|
| 85 |
+
assert 2/length == 1/length
|
| 86 |
+
x = Symbol('x')
|
| 87 |
+
m = x*length
|
| 88 |
+
assert m == length*x and m.is_Mul and set(m.args) == {x, length}
|
| 89 |
+
d = x/length
|
| 90 |
+
assert d == x*length**-1 and d.is_Mul and set(d.args) == {x, 1/length}
|
| 91 |
+
d = length/x
|
| 92 |
+
assert d == length*x**-1 and d.is_Mul and set(d.args) == {1/x, length}
|
| 93 |
+
|
| 94 |
+
velo = length / time
|
| 95 |
+
|
| 96 |
+
assert (length * length) == length ** 2
|
| 97 |
+
|
| 98 |
+
assert dimsys_SI.get_dimensional_dependencies(length * length) == {length: 2}
|
| 99 |
+
assert dimsys_SI.get_dimensional_dependencies(length ** 2) == {length: 2}
|
| 100 |
+
assert dimsys_SI.get_dimensional_dependencies(length * time) == {length: 1, time: 1}
|
| 101 |
+
assert dimsys_SI.get_dimensional_dependencies(velo) == {length: 1, time: -1}
|
| 102 |
+
assert dimsys_SI.get_dimensional_dependencies(velo ** 2) == {length: 2, time: -2}
|
| 103 |
+
|
| 104 |
+
assert dimsys_SI.get_dimensional_dependencies(length / length) == {}
|
| 105 |
+
assert dimsys_SI.get_dimensional_dependencies(velo / length * time) == {}
|
| 106 |
+
assert dimsys_SI.get_dimensional_dependencies(length ** -1) == {length: -1}
|
| 107 |
+
assert dimsys_SI.get_dimensional_dependencies(velo ** -1.5) == {length: -1.5, time: 1.5}
|
| 108 |
+
|
| 109 |
+
length_a = length**"a"
|
| 110 |
+
assert dimsys_SI.get_dimensional_dependencies(length_a) == {length: Symbol("a")}
|
| 111 |
+
|
| 112 |
+
assert dimsys_SI.get_dimensional_dependencies(length**pi) == {length: pi}
|
| 113 |
+
assert dimsys_SI.get_dimensional_dependencies(length**(length/length)) == {length: Dimension(1)}
|
| 114 |
+
|
| 115 |
+
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(length**length))
|
| 116 |
+
|
| 117 |
+
assert length != 1
|
| 118 |
+
assert length / length != 1
|
| 119 |
+
|
| 120 |
+
length_0 = length ** 0
|
| 121 |
+
assert dimsys_SI.get_dimensional_dependencies(length_0) == {}
|
| 122 |
+
|
| 123 |
+
# issue 18738
|
| 124 |
+
a = Symbol('a')
|
| 125 |
+
b = Symbol('b')
|
| 126 |
+
c = sqrt(a**2 + b**2)
|
| 127 |
+
c_dim = c.subs({a: length, b: length})
|
| 128 |
+
assert dimsys_SI.equivalent_dims(c_dim, length)
|
| 129 |
+
|
| 130 |
+
def test_Dimension_functions():
|
| 131 |
+
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(cos(length)))
|
| 132 |
+
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(acos(angle)))
|
| 133 |
+
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(atan2(length, time)))
|
| 134 |
+
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(log(length)))
|
| 135 |
+
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(log(100, length)))
|
| 136 |
+
raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(log(length, 10)))
|
| 137 |
+
|
| 138 |
+
assert dimsys_SI.get_dimensional_dependencies(pi) == {}
|
| 139 |
+
|
| 140 |
+
assert dimsys_SI.get_dimensional_dependencies(cos(1)) == {}
|
| 141 |
+
assert dimsys_SI.get_dimensional_dependencies(cos(angle)) == {}
|
| 142 |
+
|
| 143 |
+
assert dimsys_SI.get_dimensional_dependencies(atan2(length, length)) == {}
|
| 144 |
+
|
| 145 |
+
assert dimsys_SI.get_dimensional_dependencies(log(length / length, length / length)) == {}
|
| 146 |
+
|
| 147 |
+
assert dimsys_SI.get_dimensional_dependencies(Abs(length)) == {length: 1}
|
| 148 |
+
assert dimsys_SI.get_dimensional_dependencies(Abs(length / length)) == {}
|
| 149 |
+
|
| 150 |
+
assert dimsys_SI.get_dimensional_dependencies(sqrt(-1)) == {}
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_prefixes.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.mul import Mul
|
| 2 |
+
from sympy.core.numbers import Rational
|
| 3 |
+
from sympy.core.singleton import S
|
| 4 |
+
from sympy.core.symbol import (Symbol, symbols)
|
| 5 |
+
from sympy.physics.units import Quantity, length, meter, W
|
| 6 |
+
from sympy.physics.units.prefixes import PREFIXES, Prefix, prefix_unit, kilo, \
|
| 7 |
+
kibi
|
| 8 |
+
from sympy.physics.units.systems import SI
|
| 9 |
+
|
| 10 |
+
x = Symbol('x')
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def test_prefix_operations():
|
| 14 |
+
m = PREFIXES['m']
|
| 15 |
+
k = PREFIXES['k']
|
| 16 |
+
M = PREFIXES['M']
|
| 17 |
+
|
| 18 |
+
dodeca = Prefix('dodeca', 'dd', 1, base=12)
|
| 19 |
+
|
| 20 |
+
assert m * k is S.One
|
| 21 |
+
assert m * W == W / 1000
|
| 22 |
+
assert k * k == M
|
| 23 |
+
assert 1 / m == k
|
| 24 |
+
assert k / m == M
|
| 25 |
+
|
| 26 |
+
assert dodeca * dodeca == 144
|
| 27 |
+
assert 1 / dodeca == S.One / 12
|
| 28 |
+
assert k / dodeca == S(1000) / 12
|
| 29 |
+
assert dodeca / dodeca is S.One
|
| 30 |
+
|
| 31 |
+
m = Quantity("fake_meter")
|
| 32 |
+
SI.set_quantity_dimension(m, S.One)
|
| 33 |
+
SI.set_quantity_scale_factor(m, S.One)
|
| 34 |
+
|
| 35 |
+
assert dodeca * m == 12 * m
|
| 36 |
+
assert dodeca / m == 12 / m
|
| 37 |
+
|
| 38 |
+
expr1 = kilo * 3
|
| 39 |
+
assert isinstance(expr1, Mul)
|
| 40 |
+
assert expr1.args == (3, kilo)
|
| 41 |
+
|
| 42 |
+
expr2 = kilo * x
|
| 43 |
+
assert isinstance(expr2, Mul)
|
| 44 |
+
assert expr2.args == (x, kilo)
|
| 45 |
+
|
| 46 |
+
expr3 = kilo / 3
|
| 47 |
+
assert isinstance(expr3, Mul)
|
| 48 |
+
assert expr3.args == (Rational(1, 3), kilo)
|
| 49 |
+
assert expr3.args == (S.One/3, kilo)
|
| 50 |
+
|
| 51 |
+
expr4 = kilo / x
|
| 52 |
+
assert isinstance(expr4, Mul)
|
| 53 |
+
assert expr4.args == (1/x, kilo)
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
def test_prefix_unit():
|
| 57 |
+
m = Quantity("fake_meter", abbrev="m")
|
| 58 |
+
m.set_global_relative_scale_factor(1, meter)
|
| 59 |
+
|
| 60 |
+
pref = {"m": PREFIXES["m"], "c": PREFIXES["c"], "d": PREFIXES["d"]}
|
| 61 |
+
|
| 62 |
+
q1 = Quantity("millifake_meter", abbrev="mm")
|
| 63 |
+
q2 = Quantity("centifake_meter", abbrev="cm")
|
| 64 |
+
q3 = Quantity("decifake_meter", abbrev="dm")
|
| 65 |
+
|
| 66 |
+
SI.set_quantity_dimension(q1, length)
|
| 67 |
+
|
| 68 |
+
SI.set_quantity_scale_factor(q1, PREFIXES["m"])
|
| 69 |
+
SI.set_quantity_scale_factor(q1, PREFIXES["c"])
|
| 70 |
+
SI.set_quantity_scale_factor(q1, PREFIXES["d"])
|
| 71 |
+
|
| 72 |
+
res = [q1, q2, q3]
|
| 73 |
+
|
| 74 |
+
prefs = prefix_unit(m, pref)
|
| 75 |
+
assert set(prefs) == set(res)
|
| 76 |
+
assert {v.abbrev for v in prefs} == set(symbols("mm,cm,dm"))
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def test_bases():
|
| 80 |
+
assert kilo.base == 10
|
| 81 |
+
assert kibi.base == 2
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def test_repr():
|
| 85 |
+
assert eval(repr(kilo)) == kilo
|
| 86 |
+
assert eval(repr(kibi)) == kibi
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_unit_system_cgs_gauss.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.concrete.tests.test_sums_products import NS
|
| 2 |
+
|
| 3 |
+
from sympy.core.singleton import S
|
| 4 |
+
from sympy.functions.elementary.miscellaneous import sqrt
|
| 5 |
+
from sympy.physics.units import convert_to, coulomb_constant, elementary_charge, gravitational_constant, planck
|
| 6 |
+
from sympy.physics.units.definitions.unit_definitions import angstrom, statcoulomb, coulomb, second, gram, centimeter, erg, \
|
| 7 |
+
newton, joule, dyne, speed_of_light, meter, farad, henry, statvolt, volt, ohm
|
| 8 |
+
from sympy.physics.units.systems import SI
|
| 9 |
+
from sympy.physics.units.systems.cgs import cgs_gauss
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def test_conversion_to_from_si():
|
| 13 |
+
assert convert_to(statcoulomb, coulomb, cgs_gauss) == coulomb/2997924580
|
| 14 |
+
assert convert_to(coulomb, statcoulomb, cgs_gauss) == 2997924580*statcoulomb
|
| 15 |
+
assert convert_to(statcoulomb, sqrt(gram*centimeter**3)/second, cgs_gauss) == centimeter**(S(3)/2)*sqrt(gram)/second
|
| 16 |
+
assert convert_to(coulomb, sqrt(gram*centimeter**3)/second, cgs_gauss) == 2997924580*centimeter**(S(3)/2)*sqrt(gram)/second
|
| 17 |
+
|
| 18 |
+
# SI units have an additional base unit, no conversion in case of electromagnetism:
|
| 19 |
+
assert convert_to(coulomb, statcoulomb, SI) == coulomb
|
| 20 |
+
assert convert_to(statcoulomb, coulomb, SI) == statcoulomb
|
| 21 |
+
|
| 22 |
+
# SI without electromagnetism:
|
| 23 |
+
assert convert_to(erg, joule, SI) == joule/10**7
|
| 24 |
+
assert convert_to(erg, joule, cgs_gauss) == joule/10**7
|
| 25 |
+
assert convert_to(joule, erg, SI) == 10**7*erg
|
| 26 |
+
assert convert_to(joule, erg, cgs_gauss) == 10**7*erg
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
assert convert_to(dyne, newton, SI) == newton/10**5
|
| 30 |
+
assert convert_to(dyne, newton, cgs_gauss) == newton/10**5
|
| 31 |
+
assert convert_to(newton, dyne, SI) == 10**5*dyne
|
| 32 |
+
assert convert_to(newton, dyne, cgs_gauss) == 10**5*dyne
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def test_cgs_gauss_convert_constants():
|
| 36 |
+
|
| 37 |
+
assert convert_to(speed_of_light, centimeter/second, cgs_gauss) == 29979245800*centimeter/second
|
| 38 |
+
|
| 39 |
+
assert convert_to(coulomb_constant, 1, cgs_gauss) == 1
|
| 40 |
+
assert convert_to(coulomb_constant, newton*meter**2/coulomb**2, cgs_gauss) == 22468879468420441*meter**2*newton/(2500000*coulomb**2)
|
| 41 |
+
assert convert_to(coulomb_constant, newton*meter**2/coulomb**2, SI) == 22468879468420441*meter**2*newton/(2500000*coulomb**2)
|
| 42 |
+
assert convert_to(coulomb_constant, dyne*centimeter**2/statcoulomb**2, cgs_gauss) == centimeter**2*dyne/statcoulomb**2
|
| 43 |
+
assert convert_to(coulomb_constant, 1, SI) == coulomb_constant
|
| 44 |
+
assert NS(convert_to(coulomb_constant, newton*meter**2/coulomb**2, SI)) == '8987551787.36818*meter**2*newton/coulomb**2'
|
| 45 |
+
|
| 46 |
+
assert convert_to(elementary_charge, statcoulomb, cgs_gauss)
|
| 47 |
+
assert convert_to(angstrom, centimeter, cgs_gauss) == 1*centimeter/10**8
|
| 48 |
+
assert convert_to(gravitational_constant, dyne*centimeter**2/gram**2, cgs_gauss)
|
| 49 |
+
assert NS(convert_to(planck, erg*second, cgs_gauss)) == '6.62607015e-27*erg*second'
|
| 50 |
+
|
| 51 |
+
spc = 25000*second/(22468879468420441*centimeter)
|
| 52 |
+
assert convert_to(ohm, second/centimeter, cgs_gauss) == spc
|
| 53 |
+
assert convert_to(henry, second**2/centimeter, cgs_gauss) == spc*second
|
| 54 |
+
assert convert_to(volt, statvolt, cgs_gauss) == 10**6*statvolt/299792458
|
| 55 |
+
assert convert_to(farad, centimeter, cgs_gauss) == 299792458**2*centimeter/10**5
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_unitsystem.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.physics.units import DimensionSystem, joule, second, ampere
|
| 2 |
+
|
| 3 |
+
from sympy.core.numbers import Rational
|
| 4 |
+
from sympy.core.singleton import S
|
| 5 |
+
from sympy.physics.units.definitions import c, kg, m, s
|
| 6 |
+
from sympy.physics.units.definitions.dimension_definitions import length, time
|
| 7 |
+
from sympy.physics.units.quantities import Quantity
|
| 8 |
+
from sympy.physics.units.unitsystem import UnitSystem
|
| 9 |
+
from sympy.physics.units.util import convert_to
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def test_definition():
|
| 13 |
+
# want to test if the system can have several units of the same dimension
|
| 14 |
+
dm = Quantity("dm")
|
| 15 |
+
base = (m, s)
|
| 16 |
+
# base_dim = (m.dimension, s.dimension)
|
| 17 |
+
ms = UnitSystem(base, (c, dm), "MS", "MS system")
|
| 18 |
+
ms.set_quantity_dimension(dm, length)
|
| 19 |
+
ms.set_quantity_scale_factor(dm, Rational(1, 10))
|
| 20 |
+
|
| 21 |
+
assert set(ms._base_units) == set(base)
|
| 22 |
+
assert set(ms._units) == {m, s, c, dm}
|
| 23 |
+
# assert ms._units == DimensionSystem._sort_dims(base + (velocity,))
|
| 24 |
+
assert ms.name == "MS"
|
| 25 |
+
assert ms.descr == "MS system"
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def test_str_repr():
|
| 29 |
+
assert str(UnitSystem((m, s), name="MS")) == "MS"
|
| 30 |
+
assert str(UnitSystem((m, s))) == "UnitSystem((meter, second))"
|
| 31 |
+
|
| 32 |
+
assert repr(UnitSystem((m, s))) == "<UnitSystem: (%s, %s)>" % (m, s)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def test_convert_to():
|
| 36 |
+
A = Quantity("A")
|
| 37 |
+
A.set_global_relative_scale_factor(S.One, ampere)
|
| 38 |
+
|
| 39 |
+
Js = Quantity("Js")
|
| 40 |
+
Js.set_global_relative_scale_factor(S.One, joule*second)
|
| 41 |
+
|
| 42 |
+
mksa = UnitSystem((m, kg, s, A), (Js,))
|
| 43 |
+
assert convert_to(Js, mksa._base_units) == m**2*kg*s**-1/1000
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def test_extend():
|
| 47 |
+
ms = UnitSystem((m, s), (c,))
|
| 48 |
+
Js = Quantity("Js")
|
| 49 |
+
Js.set_global_relative_scale_factor(1, joule*second)
|
| 50 |
+
mks = ms.extend((kg,), (Js,))
|
| 51 |
+
|
| 52 |
+
res = UnitSystem((m, s, kg), (c, Js))
|
| 53 |
+
assert set(mks._base_units) == set(res._base_units)
|
| 54 |
+
assert set(mks._units) == set(res._units)
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def test_dim():
|
| 58 |
+
dimsys = UnitSystem((m, kg, s), (c,))
|
| 59 |
+
assert dimsys.dim == 3
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def test_is_consistent():
|
| 63 |
+
dimension_system = DimensionSystem([length, time])
|
| 64 |
+
us = UnitSystem([m, s], dimension_system=dimension_system)
|
| 65 |
+
assert us.is_consistent == True
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def test_get_units_non_prefixed():
|
| 69 |
+
from sympy.physics.units import volt, ohm
|
| 70 |
+
unit_system = UnitSystem.get_unit_system("SI")
|
| 71 |
+
units = unit_system.get_units_non_prefixed()
|
| 72 |
+
for prefix in ["giga", "tera", "peta", "exa", "zetta", "yotta", "kilo", "hecto", "deca", "deci", "centi", "milli", "micro", "nano", "pico", "femto", "atto", "zepto", "yocto"]:
|
| 73 |
+
for unit in units:
|
| 74 |
+
assert isinstance(unit, Quantity), f"{unit} must be a Quantity, not {type(unit)}"
|
| 75 |
+
assert not unit.is_prefixed, f"{unit} is marked as prefixed"
|
| 76 |
+
assert not unit.is_physical_constant, f"{unit} is marked as physics constant"
|
| 77 |
+
assert not unit.name.name.startswith(prefix), f"Unit {unit.name} has prefix {prefix}"
|
| 78 |
+
assert volt in units
|
| 79 |
+
assert ohm in units
|
| 80 |
+
|
| 81 |
+
def test_derived_units_must_exist_in_unit_system():
|
| 82 |
+
for unit_system in UnitSystem._unit_systems.values():
|
| 83 |
+
for preferred_unit in unit_system.derived_units.values():
|
| 84 |
+
units = preferred_unit.atoms(Quantity)
|
| 85 |
+
for unit in units:
|
| 86 |
+
assert unit in unit_system._units, f"Unit {unit} is not in unit system {unit_system}"
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_util.py
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.containers import Tuple
|
| 2 |
+
from sympy.core.numbers import pi
|
| 3 |
+
from sympy.core.power import Pow
|
| 4 |
+
from sympy.core.symbol import symbols
|
| 5 |
+
from sympy.core.sympify import sympify
|
| 6 |
+
from sympy.printing.str import sstr
|
| 7 |
+
from sympy.physics.units import (
|
| 8 |
+
G, centimeter, coulomb, day, degree, gram, hbar, hour, inch, joule, kelvin,
|
| 9 |
+
kilogram, kilometer, length, meter, mile, minute, newton, planck,
|
| 10 |
+
planck_length, planck_mass, planck_temperature, planck_time, radians,
|
| 11 |
+
second, speed_of_light, steradian, time, km)
|
| 12 |
+
from sympy.physics.units.util import convert_to, check_dimensions
|
| 13 |
+
from sympy.testing.pytest import raises
|
| 14 |
+
from sympy.functions.elementary.miscellaneous import sqrt
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def NS(e, n=15, **options):
|
| 18 |
+
return sstr(sympify(e).evalf(n, **options), full_prec=True)
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
L = length
|
| 22 |
+
T = time
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def test_dim_simplify_add():
|
| 26 |
+
# assert Add(L, L) == L
|
| 27 |
+
assert L + L == L
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def test_dim_simplify_mul():
|
| 31 |
+
# assert Mul(L, T) == L*T
|
| 32 |
+
assert L*T == L*T
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def test_dim_simplify_pow():
|
| 36 |
+
assert Pow(L, 2) == L**2
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def test_dim_simplify_rec():
|
| 40 |
+
# assert Mul(Add(L, L), T) == L*T
|
| 41 |
+
assert (L + L) * T == L*T
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
def test_convert_to_quantities():
|
| 45 |
+
assert convert_to(3, meter) == 3
|
| 46 |
+
|
| 47 |
+
assert convert_to(mile, kilometer) == 25146*kilometer/15625
|
| 48 |
+
assert convert_to(meter/second, speed_of_light) == speed_of_light/299792458
|
| 49 |
+
assert convert_to(299792458*meter/second, speed_of_light) == speed_of_light
|
| 50 |
+
assert convert_to(2*299792458*meter/second, speed_of_light) == 2*speed_of_light
|
| 51 |
+
assert convert_to(speed_of_light, meter/second) == 299792458*meter/second
|
| 52 |
+
assert convert_to(2*speed_of_light, meter/second) == 599584916*meter/second
|
| 53 |
+
assert convert_to(day, second) == 86400*second
|
| 54 |
+
assert convert_to(2*hour, minute) == 120*minute
|
| 55 |
+
assert convert_to(mile, meter) == 201168*meter/125
|
| 56 |
+
assert convert_to(mile/hour, kilometer/hour) == 25146*kilometer/(15625*hour)
|
| 57 |
+
assert convert_to(3*newton, meter/second) == 3*newton
|
| 58 |
+
assert convert_to(3*newton, kilogram*meter/second**2) == 3*meter*kilogram/second**2
|
| 59 |
+
assert convert_to(kilometer + mile, meter) == 326168*meter/125
|
| 60 |
+
assert convert_to(2*kilometer + 3*mile, meter) == 853504*meter/125
|
| 61 |
+
assert convert_to(inch**2, meter**2) == 16129*meter**2/25000000
|
| 62 |
+
assert convert_to(3*inch**2, meter) == 48387*meter**2/25000000
|
| 63 |
+
assert convert_to(2*kilometer/hour + 3*mile/hour, meter/second) == 53344*meter/(28125*second)
|
| 64 |
+
assert convert_to(2*kilometer/hour + 3*mile/hour, centimeter/second) == 213376*centimeter/(1125*second)
|
| 65 |
+
assert convert_to(kilometer * (mile + kilometer), meter) == 2609344 * meter ** 2
|
| 66 |
+
|
| 67 |
+
assert convert_to(steradian, coulomb) == steradian
|
| 68 |
+
assert convert_to(radians, degree) == 180*degree/pi
|
| 69 |
+
assert convert_to(radians, [meter, degree]) == 180*degree/pi
|
| 70 |
+
assert convert_to(pi*radians, degree) == 180*degree
|
| 71 |
+
assert convert_to(pi, degree) == 180*degree
|
| 72 |
+
|
| 73 |
+
# https://github.com/sympy/sympy/issues/26263
|
| 74 |
+
assert convert_to(sqrt(meter**2 + meter**2.0), meter) == sqrt(meter**2 + meter**2.0)
|
| 75 |
+
assert convert_to((meter**2 + meter**2.0)**2, meter) == (meter**2 + meter**2.0)**2
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def test_convert_to_tuples_of_quantities():
|
| 79 |
+
from sympy.core.symbol import symbols
|
| 80 |
+
|
| 81 |
+
alpha, beta = symbols('alpha beta')
|
| 82 |
+
|
| 83 |
+
assert convert_to(speed_of_light, [meter, second]) == 299792458 * meter / second
|
| 84 |
+
assert convert_to(speed_of_light, (meter, second)) == 299792458 * meter / second
|
| 85 |
+
assert convert_to(speed_of_light, Tuple(meter, second)) == 299792458 * meter / second
|
| 86 |
+
assert convert_to(joule, [meter, kilogram, second]) == kilogram*meter**2/second**2
|
| 87 |
+
assert convert_to(joule, [centimeter, gram, second]) == 10000000*centimeter**2*gram/second**2
|
| 88 |
+
assert convert_to(299792458*meter/second, [speed_of_light]) == speed_of_light
|
| 89 |
+
assert convert_to(speed_of_light / 2, [meter, second, kilogram]) == meter/second*299792458 / 2
|
| 90 |
+
# This doesn't make physically sense, but let's keep it as a conversion test:
|
| 91 |
+
assert convert_to(2 * speed_of_light, [meter, second, kilogram]) == 2 * 299792458 * meter / second
|
| 92 |
+
assert convert_to(G, [G, speed_of_light, planck]) == 1.0*G
|
| 93 |
+
|
| 94 |
+
assert NS(convert_to(meter, [G, speed_of_light, hbar]), n=7) == '6.187142e+34*gravitational_constant**0.5000000*hbar**0.5000000/speed_of_light**1.500000'
|
| 95 |
+
assert NS(convert_to(planck_mass, kilogram), n=7) == '2.176434e-8*kilogram'
|
| 96 |
+
assert NS(convert_to(planck_length, meter), n=7) == '1.616255e-35*meter'
|
| 97 |
+
assert NS(convert_to(planck_time, second), n=6) == '5.39125e-44*second'
|
| 98 |
+
assert NS(convert_to(planck_temperature, kelvin), n=7) == '1.416784e+32*kelvin'
|
| 99 |
+
assert NS(convert_to(convert_to(meter, [G, speed_of_light, planck]), meter), n=10) == '1.000000000*meter'
|
| 100 |
+
|
| 101 |
+
# similar to https://github.com/sympy/sympy/issues/26263
|
| 102 |
+
assert convert_to(sqrt(meter**2 + second**2.0), [meter, second]) == sqrt(meter**2 + second**2.0)
|
| 103 |
+
assert convert_to((meter**2 + second**2.0)**2, [meter, second]) == (meter**2 + second**2.0)**2
|
| 104 |
+
|
| 105 |
+
# similar to https://github.com/sympy/sympy/issues/21463
|
| 106 |
+
assert convert_to(1/(beta*meter + meter), 1/meter) == 1/(beta*meter + meter)
|
| 107 |
+
assert convert_to(1/(beta*meter + alpha*meter), 1/kilometer) == (1/(kilometer*beta/1000 + alpha*kilometer/1000))
|
| 108 |
+
|
| 109 |
+
def test_eval_simplify():
|
| 110 |
+
from sympy.physics.units import cm, mm, km, m, K, kilo
|
| 111 |
+
from sympy.core.symbol import symbols
|
| 112 |
+
|
| 113 |
+
x, y = symbols('x y')
|
| 114 |
+
|
| 115 |
+
assert (cm/mm).simplify() == 10
|
| 116 |
+
assert (km/m).simplify() == 1000
|
| 117 |
+
assert (km/cm).simplify() == 100000
|
| 118 |
+
assert (10*x*K*km**2/m/cm).simplify() == 1000000000*x*kelvin
|
| 119 |
+
assert (cm/km/m).simplify() == 1/(10000000*centimeter)
|
| 120 |
+
|
| 121 |
+
assert (3*kilo*meter).simplify() == 3000*meter
|
| 122 |
+
assert (4*kilo*meter/(2*kilometer)).simplify() == 2
|
| 123 |
+
assert (4*kilometer**2/(kilo*meter)**2).simplify() == 4
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
def test_quantity_simplify():
|
| 127 |
+
from sympy.physics.units.util import quantity_simplify
|
| 128 |
+
from sympy.physics.units import kilo, foot
|
| 129 |
+
from sympy.core.symbol import symbols
|
| 130 |
+
|
| 131 |
+
x, y = symbols('x y')
|
| 132 |
+
|
| 133 |
+
assert quantity_simplify(x*(8*kilo*newton*meter + y)) == x*(8000*meter*newton + y)
|
| 134 |
+
assert quantity_simplify(foot*inch*(foot + inch)) == foot**2*(foot + foot/12)/12
|
| 135 |
+
assert quantity_simplify(foot*inch*(foot*foot + inch*(foot + inch))) == foot**2*(foot**2 + foot/12*(foot + foot/12))/12
|
| 136 |
+
assert quantity_simplify(2**(foot/inch*kilo/1000)*inch) == 4096*foot/12
|
| 137 |
+
assert quantity_simplify(foot**2*inch + inch**2*foot) == 13*foot**3/144
|
| 138 |
+
|
| 139 |
+
def test_quantity_simplify_across_dimensions():
|
| 140 |
+
from sympy.physics.units.util import quantity_simplify
|
| 141 |
+
from sympy.physics.units import ampere, ohm, volt, joule, pascal, farad, second, watt, siemens, henry, tesla, weber, hour, newton
|
| 142 |
+
|
| 143 |
+
assert quantity_simplify(ampere*ohm, across_dimensions=True, unit_system="SI") == volt
|
| 144 |
+
assert quantity_simplify(6*ampere*ohm, across_dimensions=True, unit_system="SI") == 6*volt
|
| 145 |
+
assert quantity_simplify(volt/ampere, across_dimensions=True, unit_system="SI") == ohm
|
| 146 |
+
assert quantity_simplify(volt/ohm, across_dimensions=True, unit_system="SI") == ampere
|
| 147 |
+
assert quantity_simplify(joule/meter**3, across_dimensions=True, unit_system="SI") == pascal
|
| 148 |
+
assert quantity_simplify(farad*ohm, across_dimensions=True, unit_system="SI") == second
|
| 149 |
+
assert quantity_simplify(joule/second, across_dimensions=True, unit_system="SI") == watt
|
| 150 |
+
assert quantity_simplify(meter**3/second, across_dimensions=True, unit_system="SI") == meter**3/second
|
| 151 |
+
assert quantity_simplify(joule/second, across_dimensions=True, unit_system="SI") == watt
|
| 152 |
+
|
| 153 |
+
assert quantity_simplify(joule/coulomb, across_dimensions=True, unit_system="SI") == volt
|
| 154 |
+
assert quantity_simplify(volt/ampere, across_dimensions=True, unit_system="SI") == ohm
|
| 155 |
+
assert quantity_simplify(ampere/volt, across_dimensions=True, unit_system="SI") == siemens
|
| 156 |
+
assert quantity_simplify(coulomb/volt, across_dimensions=True, unit_system="SI") == farad
|
| 157 |
+
assert quantity_simplify(volt*second/ampere, across_dimensions=True, unit_system="SI") == henry
|
| 158 |
+
assert quantity_simplify(volt*second/meter**2, across_dimensions=True, unit_system="SI") == tesla
|
| 159 |
+
assert quantity_simplify(joule/ampere, across_dimensions=True, unit_system="SI") == weber
|
| 160 |
+
|
| 161 |
+
assert quantity_simplify(5*kilometer/hour, across_dimensions=True, unit_system="SI") == 25*meter/(18*second)
|
| 162 |
+
assert quantity_simplify(5*kilogram*meter/second**2, across_dimensions=True, unit_system="SI") == 5*newton
|
| 163 |
+
|
| 164 |
+
def test_check_dimensions():
|
| 165 |
+
x = symbols('x')
|
| 166 |
+
assert check_dimensions(inch + x) == inch + x
|
| 167 |
+
assert check_dimensions(length + x) == length + x
|
| 168 |
+
# after subs we get 2*length; check will clear the constant
|
| 169 |
+
assert check_dimensions((length + x).subs(x, length)) == length
|
| 170 |
+
assert check_dimensions(newton*meter + joule) == joule + meter*newton
|
| 171 |
+
raises(ValueError, lambda: check_dimensions(inch + 1))
|
| 172 |
+
raises(ValueError, lambda: check_dimensions(length + 1))
|
| 173 |
+
raises(ValueError, lambda: check_dimensions(length + time))
|
| 174 |
+
raises(ValueError, lambda: check_dimensions(meter + second))
|
| 175 |
+
raises(ValueError, lambda: check_dimensions(2 * meter + second))
|
| 176 |
+
raises(ValueError, lambda: check_dimensions(2 * meter + 3 * second))
|
| 177 |
+
raises(ValueError, lambda: check_dimensions(1 / second + 1 / meter))
|
| 178 |
+
raises(ValueError, lambda: check_dimensions(2 * meter*(mile + centimeter) + km))
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/unitsystem.py
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Unit system for physical quantities; include definition of constants.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from typing import Dict as tDict, Set as tSet
|
| 6 |
+
|
| 7 |
+
from sympy.core.add import Add
|
| 8 |
+
from sympy.core.function import (Derivative, Function)
|
| 9 |
+
from sympy.core.mul import Mul
|
| 10 |
+
from sympy.core.power import Pow
|
| 11 |
+
from sympy.core.singleton import S
|
| 12 |
+
from sympy.physics.units.dimensions import _QuantityMapper
|
| 13 |
+
from sympy.physics.units.quantities import Quantity
|
| 14 |
+
|
| 15 |
+
from .dimensions import Dimension
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class UnitSystem(_QuantityMapper):
|
| 19 |
+
"""
|
| 20 |
+
UnitSystem represents a coherent set of units.
|
| 21 |
+
|
| 22 |
+
A unit system is basically a dimension system with notions of scales. Many
|
| 23 |
+
of the methods are defined in the same way.
|
| 24 |
+
|
| 25 |
+
It is much better if all base units have a symbol.
|
| 26 |
+
"""
|
| 27 |
+
|
| 28 |
+
_unit_systems = {} # type: tDict[str, UnitSystem]
|
| 29 |
+
|
| 30 |
+
def __init__(self, base_units, units=(), name="", descr="", dimension_system=None, derived_units: tDict[Dimension, Quantity]={}):
|
| 31 |
+
|
| 32 |
+
UnitSystem._unit_systems[name] = self
|
| 33 |
+
|
| 34 |
+
self.name = name
|
| 35 |
+
self.descr = descr
|
| 36 |
+
|
| 37 |
+
self._base_units = base_units
|
| 38 |
+
self._dimension_system = dimension_system
|
| 39 |
+
self._units = tuple(set(base_units) | set(units))
|
| 40 |
+
self._base_units = tuple(base_units)
|
| 41 |
+
self._derived_units = derived_units
|
| 42 |
+
|
| 43 |
+
super().__init__()
|
| 44 |
+
|
| 45 |
+
def __str__(self):
|
| 46 |
+
"""
|
| 47 |
+
Return the name of the system.
|
| 48 |
+
|
| 49 |
+
If it does not exist, then it makes a list of symbols (or names) of
|
| 50 |
+
the base dimensions.
|
| 51 |
+
"""
|
| 52 |
+
|
| 53 |
+
if self.name != "":
|
| 54 |
+
return self.name
|
| 55 |
+
else:
|
| 56 |
+
return "UnitSystem((%s))" % ", ".join(
|
| 57 |
+
str(d) for d in self._base_units)
|
| 58 |
+
|
| 59 |
+
def __repr__(self):
|
| 60 |
+
return '<UnitSystem: %s>' % repr(self._base_units)
|
| 61 |
+
|
| 62 |
+
def extend(self, base, units=(), name="", description="", dimension_system=None, derived_units: tDict[Dimension, Quantity]={}):
|
| 63 |
+
"""Extend the current system into a new one.
|
| 64 |
+
|
| 65 |
+
Take the base and normal units of the current system to merge
|
| 66 |
+
them to the base and normal units given in argument.
|
| 67 |
+
If not provided, name and description are overridden by empty strings.
|
| 68 |
+
"""
|
| 69 |
+
|
| 70 |
+
base = self._base_units + tuple(base)
|
| 71 |
+
units = self._units + tuple(units)
|
| 72 |
+
|
| 73 |
+
return UnitSystem(base, units, name, description, dimension_system, {**self._derived_units, **derived_units})
|
| 74 |
+
|
| 75 |
+
def get_dimension_system(self):
|
| 76 |
+
return self._dimension_system
|
| 77 |
+
|
| 78 |
+
def get_quantity_dimension(self, unit):
|
| 79 |
+
qdm = self.get_dimension_system()._quantity_dimension_map
|
| 80 |
+
if unit in qdm:
|
| 81 |
+
return qdm[unit]
|
| 82 |
+
return super().get_quantity_dimension(unit)
|
| 83 |
+
|
| 84 |
+
def get_quantity_scale_factor(self, unit):
|
| 85 |
+
qsfm = self.get_dimension_system()._quantity_scale_factors
|
| 86 |
+
if unit in qsfm:
|
| 87 |
+
return qsfm[unit]
|
| 88 |
+
return super().get_quantity_scale_factor(unit)
|
| 89 |
+
|
| 90 |
+
@staticmethod
|
| 91 |
+
def get_unit_system(unit_system):
|
| 92 |
+
if isinstance(unit_system, UnitSystem):
|
| 93 |
+
return unit_system
|
| 94 |
+
|
| 95 |
+
if unit_system not in UnitSystem._unit_systems:
|
| 96 |
+
raise ValueError(
|
| 97 |
+
"Unit system is not supported. Currently"
|
| 98 |
+
"supported unit systems are {}".format(
|
| 99 |
+
", ".join(sorted(UnitSystem._unit_systems))
|
| 100 |
+
)
|
| 101 |
+
)
|
| 102 |
+
|
| 103 |
+
return UnitSystem._unit_systems[unit_system]
|
| 104 |
+
|
| 105 |
+
@staticmethod
|
| 106 |
+
def get_default_unit_system():
|
| 107 |
+
return UnitSystem._unit_systems["SI"]
|
| 108 |
+
|
| 109 |
+
@property
|
| 110 |
+
def dim(self):
|
| 111 |
+
"""
|
| 112 |
+
Give the dimension of the system.
|
| 113 |
+
|
| 114 |
+
That is return the number of units forming the basis.
|
| 115 |
+
"""
|
| 116 |
+
return len(self._base_units)
|
| 117 |
+
|
| 118 |
+
@property
|
| 119 |
+
def is_consistent(self):
|
| 120 |
+
"""
|
| 121 |
+
Check if the underlying dimension system is consistent.
|
| 122 |
+
"""
|
| 123 |
+
# test is performed in DimensionSystem
|
| 124 |
+
return self.get_dimension_system().is_consistent
|
| 125 |
+
|
| 126 |
+
@property
|
| 127 |
+
def derived_units(self) -> tDict[Dimension, Quantity]:
|
| 128 |
+
return self._derived_units
|
| 129 |
+
|
| 130 |
+
def get_dimensional_expr(self, expr):
|
| 131 |
+
from sympy.physics.units import Quantity
|
| 132 |
+
if isinstance(expr, Mul):
|
| 133 |
+
return Mul(*[self.get_dimensional_expr(i) for i in expr.args])
|
| 134 |
+
elif isinstance(expr, Pow):
|
| 135 |
+
return self.get_dimensional_expr(expr.base) ** expr.exp
|
| 136 |
+
elif isinstance(expr, Add):
|
| 137 |
+
return self.get_dimensional_expr(expr.args[0])
|
| 138 |
+
elif isinstance(expr, Derivative):
|
| 139 |
+
dim = self.get_dimensional_expr(expr.expr)
|
| 140 |
+
for independent, count in expr.variable_count:
|
| 141 |
+
dim /= self.get_dimensional_expr(independent)**count
|
| 142 |
+
return dim
|
| 143 |
+
elif isinstance(expr, Function):
|
| 144 |
+
args = [self.get_dimensional_expr(arg) for arg in expr.args]
|
| 145 |
+
if all(i == 1 for i in args):
|
| 146 |
+
return S.One
|
| 147 |
+
return expr.func(*args)
|
| 148 |
+
elif isinstance(expr, Quantity):
|
| 149 |
+
return self.get_quantity_dimension(expr).name
|
| 150 |
+
return S.One
|
| 151 |
+
|
| 152 |
+
def _collect_factor_and_dimension(self, expr):
|
| 153 |
+
"""
|
| 154 |
+
Return tuple with scale factor expression and dimension expression.
|
| 155 |
+
"""
|
| 156 |
+
from sympy.physics.units import Quantity
|
| 157 |
+
if isinstance(expr, Quantity):
|
| 158 |
+
return expr.scale_factor, expr.dimension
|
| 159 |
+
elif isinstance(expr, Mul):
|
| 160 |
+
factor = 1
|
| 161 |
+
dimension = Dimension(1)
|
| 162 |
+
for arg in expr.args:
|
| 163 |
+
arg_factor, arg_dim = self._collect_factor_and_dimension(arg)
|
| 164 |
+
factor *= arg_factor
|
| 165 |
+
dimension *= arg_dim
|
| 166 |
+
return factor, dimension
|
| 167 |
+
elif isinstance(expr, Pow):
|
| 168 |
+
factor, dim = self._collect_factor_and_dimension(expr.base)
|
| 169 |
+
exp_factor, exp_dim = self._collect_factor_and_dimension(expr.exp)
|
| 170 |
+
if self.get_dimension_system().is_dimensionless(exp_dim):
|
| 171 |
+
exp_dim = 1
|
| 172 |
+
return factor ** exp_factor, dim ** (exp_factor * exp_dim)
|
| 173 |
+
elif isinstance(expr, Add):
|
| 174 |
+
factor, dim = self._collect_factor_and_dimension(expr.args[0])
|
| 175 |
+
for addend in expr.args[1:]:
|
| 176 |
+
addend_factor, addend_dim = \
|
| 177 |
+
self._collect_factor_and_dimension(addend)
|
| 178 |
+
if not self.get_dimension_system().equivalent_dims(dim, addend_dim):
|
| 179 |
+
raise ValueError(
|
| 180 |
+
'Dimension of "{}" is {}, '
|
| 181 |
+
'but it should be {}'.format(
|
| 182 |
+
addend, addend_dim, dim))
|
| 183 |
+
factor += addend_factor
|
| 184 |
+
return factor, dim
|
| 185 |
+
elif isinstance(expr, Derivative):
|
| 186 |
+
factor, dim = self._collect_factor_and_dimension(expr.args[0])
|
| 187 |
+
for independent, count in expr.variable_count:
|
| 188 |
+
ifactor, idim = self._collect_factor_and_dimension(independent)
|
| 189 |
+
factor /= ifactor**count
|
| 190 |
+
dim /= idim**count
|
| 191 |
+
return factor, dim
|
| 192 |
+
elif isinstance(expr, Function):
|
| 193 |
+
fds = [self._collect_factor_and_dimension(arg) for arg in expr.args]
|
| 194 |
+
dims = [Dimension(1) if self.get_dimension_system().is_dimensionless(d[1]) else d[1] for d in fds]
|
| 195 |
+
return (expr.func(*(f[0] for f in fds)), *dims)
|
| 196 |
+
elif isinstance(expr, Dimension):
|
| 197 |
+
return S.One, expr
|
| 198 |
+
else:
|
| 199 |
+
return expr, Dimension(1)
|
| 200 |
+
|
| 201 |
+
def get_units_non_prefixed(self) -> tSet[Quantity]:
|
| 202 |
+
"""
|
| 203 |
+
Return the units of the system that do not have a prefix.
|
| 204 |
+
"""
|
| 205 |
+
return set(filter(lambda u: not u.is_prefixed and not u.is_physical_constant, self._units))
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/util.py
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Several methods to simplify expressions involving unit objects.
|
| 3 |
+
"""
|
| 4 |
+
from functools import reduce
|
| 5 |
+
from collections.abc import Iterable
|
| 6 |
+
from typing import Optional
|
| 7 |
+
|
| 8 |
+
from sympy import default_sort_key
|
| 9 |
+
from sympy.core.add import Add
|
| 10 |
+
from sympy.core.containers import Tuple
|
| 11 |
+
from sympy.core.mul import Mul
|
| 12 |
+
from sympy.core.power import Pow
|
| 13 |
+
from sympy.core.sorting import ordered
|
| 14 |
+
from sympy.core.sympify import sympify
|
| 15 |
+
from sympy.core.function import Function
|
| 16 |
+
from sympy.matrices.exceptions import NonInvertibleMatrixError
|
| 17 |
+
from sympy.physics.units.dimensions import Dimension, DimensionSystem
|
| 18 |
+
from sympy.physics.units.prefixes import Prefix
|
| 19 |
+
from sympy.physics.units.quantities import Quantity
|
| 20 |
+
from sympy.physics.units.unitsystem import UnitSystem
|
| 21 |
+
from sympy.utilities.iterables import sift
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def _get_conversion_matrix_for_expr(expr, target_units, unit_system):
|
| 25 |
+
from sympy.matrices.dense import Matrix
|
| 26 |
+
|
| 27 |
+
dimension_system = unit_system.get_dimension_system()
|
| 28 |
+
|
| 29 |
+
expr_dim = Dimension(unit_system.get_dimensional_expr(expr))
|
| 30 |
+
dim_dependencies = dimension_system.get_dimensional_dependencies(expr_dim, mark_dimensionless=True)
|
| 31 |
+
target_dims = [Dimension(unit_system.get_dimensional_expr(x)) for x in target_units]
|
| 32 |
+
canon_dim_units = [i for x in target_dims for i in dimension_system.get_dimensional_dependencies(x, mark_dimensionless=True)]
|
| 33 |
+
canon_expr_units = set(dim_dependencies)
|
| 34 |
+
|
| 35 |
+
if not canon_expr_units.issubset(set(canon_dim_units)):
|
| 36 |
+
return None
|
| 37 |
+
|
| 38 |
+
seen = set()
|
| 39 |
+
canon_dim_units = [i for i in canon_dim_units if not (i in seen or seen.add(i))]
|
| 40 |
+
|
| 41 |
+
camat = Matrix([[dimension_system.get_dimensional_dependencies(i, mark_dimensionless=True).get(j, 0) for i in target_dims] for j in canon_dim_units])
|
| 42 |
+
exprmat = Matrix([dim_dependencies.get(k, 0) for k in canon_dim_units])
|
| 43 |
+
|
| 44 |
+
try:
|
| 45 |
+
res_exponents = camat.solve(exprmat)
|
| 46 |
+
except NonInvertibleMatrixError:
|
| 47 |
+
return None
|
| 48 |
+
|
| 49 |
+
return res_exponents
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def convert_to(expr, target_units, unit_system="SI"):
|
| 53 |
+
"""
|
| 54 |
+
Convert ``expr`` to the same expression with all of its units and quantities
|
| 55 |
+
represented as factors of ``target_units``, whenever the dimension is compatible.
|
| 56 |
+
|
| 57 |
+
``target_units`` may be a single unit/quantity, or a collection of
|
| 58 |
+
units/quantities.
|
| 59 |
+
|
| 60 |
+
Examples
|
| 61 |
+
========
|
| 62 |
+
|
| 63 |
+
>>> from sympy.physics.units import speed_of_light, meter, gram, second, day
|
| 64 |
+
>>> from sympy.physics.units import mile, newton, kilogram, atomic_mass_constant
|
| 65 |
+
>>> from sympy.physics.units import kilometer, centimeter
|
| 66 |
+
>>> from sympy.physics.units import gravitational_constant, hbar
|
| 67 |
+
>>> from sympy.physics.units import convert_to
|
| 68 |
+
>>> convert_to(mile, kilometer)
|
| 69 |
+
25146*kilometer/15625
|
| 70 |
+
>>> convert_to(mile, kilometer).n()
|
| 71 |
+
1.609344*kilometer
|
| 72 |
+
>>> convert_to(speed_of_light, meter/second)
|
| 73 |
+
299792458*meter/second
|
| 74 |
+
>>> convert_to(day, second)
|
| 75 |
+
86400*second
|
| 76 |
+
>>> 3*newton
|
| 77 |
+
3*newton
|
| 78 |
+
>>> convert_to(3*newton, kilogram*meter/second**2)
|
| 79 |
+
3*kilogram*meter/second**2
|
| 80 |
+
>>> convert_to(atomic_mass_constant, gram)
|
| 81 |
+
1.660539060e-24*gram
|
| 82 |
+
|
| 83 |
+
Conversion to multiple units:
|
| 84 |
+
|
| 85 |
+
>>> convert_to(speed_of_light, [meter, second])
|
| 86 |
+
299792458*meter/second
|
| 87 |
+
>>> convert_to(3*newton, [centimeter, gram, second])
|
| 88 |
+
300000*centimeter*gram/second**2
|
| 89 |
+
|
| 90 |
+
Conversion to Planck units:
|
| 91 |
+
|
| 92 |
+
>>> convert_to(atomic_mass_constant, [gravitational_constant, speed_of_light, hbar]).n()
|
| 93 |
+
7.62963087839509e-20*hbar**0.5*speed_of_light**0.5/gravitational_constant**0.5
|
| 94 |
+
|
| 95 |
+
"""
|
| 96 |
+
from sympy.physics.units import UnitSystem
|
| 97 |
+
unit_system = UnitSystem.get_unit_system(unit_system)
|
| 98 |
+
|
| 99 |
+
if not isinstance(target_units, (Iterable, Tuple)):
|
| 100 |
+
target_units = [target_units]
|
| 101 |
+
|
| 102 |
+
def handle_Adds(expr):
|
| 103 |
+
return Add.fromiter(convert_to(i, target_units, unit_system)
|
| 104 |
+
for i in expr.args)
|
| 105 |
+
|
| 106 |
+
if isinstance(expr, Add):
|
| 107 |
+
return handle_Adds(expr)
|
| 108 |
+
elif isinstance(expr, Pow) and isinstance(expr.base, Add):
|
| 109 |
+
return handle_Adds(expr.base) ** expr.exp
|
| 110 |
+
|
| 111 |
+
expr = sympify(expr)
|
| 112 |
+
target_units = sympify(target_units)
|
| 113 |
+
|
| 114 |
+
if isinstance(expr, Function):
|
| 115 |
+
expr = expr.together()
|
| 116 |
+
|
| 117 |
+
if not isinstance(expr, Quantity) and expr.has(Quantity):
|
| 118 |
+
expr = expr.replace(lambda x: isinstance(x, Quantity),
|
| 119 |
+
lambda x: x.convert_to(target_units, unit_system))
|
| 120 |
+
|
| 121 |
+
def get_total_scale_factor(expr):
|
| 122 |
+
if isinstance(expr, Mul):
|
| 123 |
+
return reduce(lambda x, y: x * y,
|
| 124 |
+
[get_total_scale_factor(i) for i in expr.args])
|
| 125 |
+
elif isinstance(expr, Pow):
|
| 126 |
+
return get_total_scale_factor(expr.base) ** expr.exp
|
| 127 |
+
elif isinstance(expr, Quantity):
|
| 128 |
+
return unit_system.get_quantity_scale_factor(expr)
|
| 129 |
+
return expr
|
| 130 |
+
|
| 131 |
+
depmat = _get_conversion_matrix_for_expr(expr, target_units, unit_system)
|
| 132 |
+
if depmat is None:
|
| 133 |
+
return expr
|
| 134 |
+
|
| 135 |
+
expr_scale_factor = get_total_scale_factor(expr)
|
| 136 |
+
return expr_scale_factor * Mul.fromiter(
|
| 137 |
+
(1/get_total_scale_factor(u)*u)**p for u, p in
|
| 138 |
+
zip(target_units, depmat))
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
def quantity_simplify(expr, across_dimensions: bool=False, unit_system=None):
|
| 142 |
+
"""Return an equivalent expression in which prefixes are replaced
|
| 143 |
+
with numerical values and all units of a given dimension are the
|
| 144 |
+
unified in a canonical manner by default. `across_dimensions` allows
|
| 145 |
+
for units of different dimensions to be simplified together.
|
| 146 |
+
|
| 147 |
+
`unit_system` must be specified if `across_dimensions` is True.
|
| 148 |
+
|
| 149 |
+
Examples
|
| 150 |
+
========
|
| 151 |
+
|
| 152 |
+
>>> from sympy.physics.units.util import quantity_simplify
|
| 153 |
+
>>> from sympy.physics.units.prefixes import kilo
|
| 154 |
+
>>> from sympy.physics.units import foot, inch, joule, coulomb
|
| 155 |
+
>>> quantity_simplify(kilo*foot*inch)
|
| 156 |
+
250*foot**2/3
|
| 157 |
+
>>> quantity_simplify(foot - 6*inch)
|
| 158 |
+
foot/2
|
| 159 |
+
>>> quantity_simplify(5*joule/coulomb, across_dimensions=True, unit_system="SI")
|
| 160 |
+
5*volt
|
| 161 |
+
"""
|
| 162 |
+
|
| 163 |
+
if expr.is_Atom or not expr.has(Prefix, Quantity):
|
| 164 |
+
return expr
|
| 165 |
+
|
| 166 |
+
# replace all prefixes with numerical values
|
| 167 |
+
p = expr.atoms(Prefix)
|
| 168 |
+
expr = expr.xreplace({p: p.scale_factor for p in p})
|
| 169 |
+
|
| 170 |
+
# replace all quantities of given dimension with a canonical
|
| 171 |
+
# quantity, chosen from those in the expression
|
| 172 |
+
d = sift(expr.atoms(Quantity), lambda i: i.dimension)
|
| 173 |
+
for k in d:
|
| 174 |
+
if len(d[k]) == 1:
|
| 175 |
+
continue
|
| 176 |
+
v = list(ordered(d[k]))
|
| 177 |
+
ref = v[0]/v[0].scale_factor
|
| 178 |
+
expr = expr.xreplace({vi: ref*vi.scale_factor for vi in v[1:]})
|
| 179 |
+
|
| 180 |
+
if across_dimensions:
|
| 181 |
+
# combine quantities of different dimensions into a single
|
| 182 |
+
# quantity that is equivalent to the original expression
|
| 183 |
+
|
| 184 |
+
if unit_system is None:
|
| 185 |
+
raise ValueError("unit_system must be specified if across_dimensions is True")
|
| 186 |
+
|
| 187 |
+
unit_system = UnitSystem.get_unit_system(unit_system)
|
| 188 |
+
dimension_system: DimensionSystem = unit_system.get_dimension_system()
|
| 189 |
+
dim_expr = unit_system.get_dimensional_expr(expr)
|
| 190 |
+
dim_deps = dimension_system.get_dimensional_dependencies(dim_expr, mark_dimensionless=True)
|
| 191 |
+
|
| 192 |
+
target_dimension: Optional[Dimension] = None
|
| 193 |
+
for ds_dim, ds_dim_deps in dimension_system.dimensional_dependencies.items():
|
| 194 |
+
if ds_dim_deps == dim_deps:
|
| 195 |
+
target_dimension = ds_dim
|
| 196 |
+
break
|
| 197 |
+
|
| 198 |
+
if target_dimension is None:
|
| 199 |
+
# if we can't find a target dimension, we can't do anything. unsure how to handle this case.
|
| 200 |
+
return expr
|
| 201 |
+
|
| 202 |
+
target_unit = unit_system.derived_units.get(target_dimension)
|
| 203 |
+
if target_unit:
|
| 204 |
+
expr = convert_to(expr, target_unit, unit_system)
|
| 205 |
+
|
| 206 |
+
return expr
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
def check_dimensions(expr, unit_system="SI"):
|
| 210 |
+
"""Return expr if units in addends have the same
|
| 211 |
+
base dimensions, else raise a ValueError."""
|
| 212 |
+
# the case of adding a number to a dimensional quantity
|
| 213 |
+
# is ignored for the sake of SymPy core routines, so this
|
| 214 |
+
# function will raise an error now if such an addend is
|
| 215 |
+
# found.
|
| 216 |
+
# Also, when doing substitutions, multiplicative constants
|
| 217 |
+
# might be introduced, so remove those now
|
| 218 |
+
|
| 219 |
+
from sympy.physics.units import UnitSystem
|
| 220 |
+
unit_system = UnitSystem.get_unit_system(unit_system)
|
| 221 |
+
|
| 222 |
+
def addDict(dict1, dict2):
|
| 223 |
+
"""Merge dictionaries by adding values of common keys and
|
| 224 |
+
removing keys with value of 0."""
|
| 225 |
+
dict3 = {**dict1, **dict2}
|
| 226 |
+
for key, value in dict3.items():
|
| 227 |
+
if key in dict1 and key in dict2:
|
| 228 |
+
dict3[key] = value + dict1[key]
|
| 229 |
+
return {key:val for key, val in dict3.items() if val != 0}
|
| 230 |
+
|
| 231 |
+
adds = expr.atoms(Add)
|
| 232 |
+
DIM_OF = unit_system.get_dimension_system().get_dimensional_dependencies
|
| 233 |
+
for a in adds:
|
| 234 |
+
deset = set()
|
| 235 |
+
for ai in a.args:
|
| 236 |
+
if ai.is_number:
|
| 237 |
+
deset.add(())
|
| 238 |
+
continue
|
| 239 |
+
dims = []
|
| 240 |
+
skip = False
|
| 241 |
+
dimdict = {}
|
| 242 |
+
for i in Mul.make_args(ai):
|
| 243 |
+
if i.has(Quantity):
|
| 244 |
+
i = Dimension(unit_system.get_dimensional_expr(i))
|
| 245 |
+
if i.has(Dimension):
|
| 246 |
+
dimdict = addDict(dimdict, DIM_OF(i))
|
| 247 |
+
elif i.free_symbols:
|
| 248 |
+
skip = True
|
| 249 |
+
break
|
| 250 |
+
dims.extend(dimdict.items())
|
| 251 |
+
if not skip:
|
| 252 |
+
deset.add(tuple(sorted(dims, key=default_sort_key)))
|
| 253 |
+
if len(deset) > 1:
|
| 254 |
+
raise ValueError(
|
| 255 |
+
"addends have incompatible dimensions: {}".format(deset))
|
| 256 |
+
|
| 257 |
+
# clear multiplicative constants on Dimensions which may be
|
| 258 |
+
# left after substitution
|
| 259 |
+
reps = {}
|
| 260 |
+
for m in expr.atoms(Mul):
|
| 261 |
+
if any(isinstance(i, Dimension) for i in m.args):
|
| 262 |
+
reps[m] = m.func(*[
|
| 263 |
+
i for i in m.args if not i.is_number])
|
| 264 |
+
|
| 265 |
+
return expr.xreplace(reps)
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/vector/tests/__pycache__/test_functions.cpython-311.pyc
ADDED
|
Binary file (67.2 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/vector/tests/__pycache__/test_printing.cpython-311.pyc
ADDED
|
Binary file (19.1 kB). View file
|
|
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/vector/tests/test_vector.py
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from sympy.core.numbers import (Float, pi)
|
| 2 |
+
from sympy.core.symbol import symbols
|
| 3 |
+
from sympy.core.sorting import ordered
|
| 4 |
+
from sympy.functions.elementary.trigonometric import (cos, sin)
|
| 5 |
+
from sympy.matrices.immutable import ImmutableDenseMatrix as Matrix
|
| 6 |
+
from sympy.physics.vector import ReferenceFrame, Vector, dynamicsymbols, dot
|
| 7 |
+
from sympy.physics.vector.vector import VectorTypeError
|
| 8 |
+
from sympy.abc import x, y, z
|
| 9 |
+
from sympy.testing.pytest import raises
|
| 10 |
+
|
| 11 |
+
A = ReferenceFrame('A')
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def test_free_dynamicsymbols():
|
| 15 |
+
A, B, C, D = symbols('A, B, C, D', cls=ReferenceFrame)
|
| 16 |
+
a, b, c, d, e, f = dynamicsymbols('a, b, c, d, e, f')
|
| 17 |
+
B.orient_axis(A, a, A.x)
|
| 18 |
+
C.orient_axis(B, b, B.y)
|
| 19 |
+
D.orient_axis(C, c, C.x)
|
| 20 |
+
|
| 21 |
+
v = d*D.x + e*D.y + f*D.z
|
| 22 |
+
|
| 23 |
+
assert set(ordered(v.free_dynamicsymbols(A))) == {a, b, c, d, e, f}
|
| 24 |
+
assert set(ordered(v.free_dynamicsymbols(B))) == {b, c, d, e, f}
|
| 25 |
+
assert set(ordered(v.free_dynamicsymbols(C))) == {c, d, e, f}
|
| 26 |
+
assert set(ordered(v.free_dynamicsymbols(D))) == {d, e, f}
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def test_Vector():
|
| 30 |
+
assert A.x != A.y
|
| 31 |
+
assert A.y != A.z
|
| 32 |
+
assert A.z != A.x
|
| 33 |
+
|
| 34 |
+
assert A.x + 0 == A.x
|
| 35 |
+
|
| 36 |
+
v1 = x*A.x + y*A.y + z*A.z
|
| 37 |
+
v2 = x**2*A.x + y**2*A.y + z**2*A.z
|
| 38 |
+
v3 = v1 + v2
|
| 39 |
+
v4 = v1 - v2
|
| 40 |
+
|
| 41 |
+
assert isinstance(v1, Vector)
|
| 42 |
+
assert dot(v1, A.x) == x
|
| 43 |
+
assert dot(v1, A.y) == y
|
| 44 |
+
assert dot(v1, A.z) == z
|
| 45 |
+
|
| 46 |
+
assert isinstance(v2, Vector)
|
| 47 |
+
assert dot(v2, A.x) == x**2
|
| 48 |
+
assert dot(v2, A.y) == y**2
|
| 49 |
+
assert dot(v2, A.z) == z**2
|
| 50 |
+
|
| 51 |
+
assert isinstance(v3, Vector)
|
| 52 |
+
# We probably shouldn't be using simplify in dot...
|
| 53 |
+
assert dot(v3, A.x) == x**2 + x
|
| 54 |
+
assert dot(v3, A.y) == y**2 + y
|
| 55 |
+
assert dot(v3, A.z) == z**2 + z
|
| 56 |
+
|
| 57 |
+
assert isinstance(v4, Vector)
|
| 58 |
+
# We probably shouldn't be using simplify in dot...
|
| 59 |
+
assert dot(v4, A.x) == x - x**2
|
| 60 |
+
assert dot(v4, A.y) == y - y**2
|
| 61 |
+
assert dot(v4, A.z) == z - z**2
|
| 62 |
+
|
| 63 |
+
assert v1.to_matrix(A) == Matrix([[x], [y], [z]])
|
| 64 |
+
q = symbols('q')
|
| 65 |
+
B = A.orientnew('B', 'Axis', (q, A.x))
|
| 66 |
+
assert v1.to_matrix(B) == Matrix([[x],
|
| 67 |
+
[ y * cos(q) + z * sin(q)],
|
| 68 |
+
[-y * sin(q) + z * cos(q)]])
|
| 69 |
+
|
| 70 |
+
#Test the separate method
|
| 71 |
+
B = ReferenceFrame('B')
|
| 72 |
+
v5 = x*A.x + y*A.y + z*B.z
|
| 73 |
+
assert Vector(0).separate() == {}
|
| 74 |
+
assert v1.separate() == {A: v1}
|
| 75 |
+
assert v5.separate() == {A: x*A.x + y*A.y, B: z*B.z}
|
| 76 |
+
|
| 77 |
+
#Test the free_symbols property
|
| 78 |
+
v6 = x*A.x + y*A.y + z*A.z
|
| 79 |
+
assert v6.free_symbols(A) == {x,y,z}
|
| 80 |
+
|
| 81 |
+
raises(TypeError, lambda: v3.applyfunc(v1))
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def test_Vector_diffs():
|
| 85 |
+
q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4')
|
| 86 |
+
q1d, q2d, q3d, q4d = dynamicsymbols('q1 q2 q3 q4', 1)
|
| 87 |
+
q1dd, q2dd, q3dd, q4dd = dynamicsymbols('q1 q2 q3 q4', 2)
|
| 88 |
+
N = ReferenceFrame('N')
|
| 89 |
+
A = N.orientnew('A', 'Axis', [q3, N.z])
|
| 90 |
+
B = A.orientnew('B', 'Axis', [q2, A.x])
|
| 91 |
+
v1 = q2 * A.x + q3 * N.y
|
| 92 |
+
v2 = q3 * B.x + v1
|
| 93 |
+
v3 = v1.dt(B)
|
| 94 |
+
v4 = v2.dt(B)
|
| 95 |
+
v5 = q1*A.x + q2*A.y + q3*A.z
|
| 96 |
+
|
| 97 |
+
assert v1.dt(N) == q2d * A.x + q2 * q3d * A.y + q3d * N.y
|
| 98 |
+
assert v1.dt(A) == q2d * A.x + q3 * q3d * N.x + q3d * N.y
|
| 99 |
+
assert v1.dt(B) == (q2d * A.x + q3 * q3d * N.x + q3d *
|
| 100 |
+
N.y - q3 * cos(q3) * q2d * N.z)
|
| 101 |
+
assert v2.dt(N) == (q2d * A.x + (q2 + q3) * q3d * A.y + q3d * B.x + q3d *
|
| 102 |
+
N.y)
|
| 103 |
+
assert v2.dt(A) == q2d * A.x + q3d * B.x + q3 * q3d * N.x + q3d * N.y
|
| 104 |
+
assert v2.dt(B) == (q2d * A.x + q3d * B.x + q3 * q3d * N.x + q3d * N.y -
|
| 105 |
+
q3 * cos(q3) * q2d * N.z)
|
| 106 |
+
assert v3.dt(N) == (q2dd * A.x + q2d * q3d * A.y + (q3d**2 + q3 * q3dd) *
|
| 107 |
+
N.x + q3dd * N.y + (q3 * sin(q3) * q2d * q3d -
|
| 108 |
+
cos(q3) * q2d * q3d - q3 * cos(q3) * q2dd) * N.z)
|
| 109 |
+
assert v3.dt(A) == (q2dd * A.x + (2 * q3d**2 + q3 * q3dd) * N.x + (q3dd -
|
| 110 |
+
q3 * q3d**2) * N.y + (q3 * sin(q3) * q2d * q3d -
|
| 111 |
+
cos(q3) * q2d * q3d - q3 * cos(q3) * q2dd) * N.z)
|
| 112 |
+
assert (v3.dt(B) - (q2dd*A.x - q3*cos(q3)*q2d**2*A.y + (2*q3d**2 +
|
| 113 |
+
q3*q3dd)*N.x + (q3dd - q3*q3d**2)*N.y + (2*q3*sin(q3)*q2d*q3d -
|
| 114 |
+
2*cos(q3)*q2d*q3d - q3*cos(q3)*q2dd)*N.z)).express(B).simplify() == 0
|
| 115 |
+
assert v4.dt(N) == (q2dd * A.x + q3d * (q2d + q3d) * A.y + q3dd * B.x +
|
| 116 |
+
(q3d**2 + q3 * q3dd) * N.x + q3dd * N.y + (q3 *
|
| 117 |
+
sin(q3) * q2d * q3d - cos(q3) * q2d * q3d - q3 *
|
| 118 |
+
cos(q3) * q2dd) * N.z)
|
| 119 |
+
assert v4.dt(A) == (q2dd * A.x + q3dd * B.x + (2 * q3d**2 + q3 * q3dd) *
|
| 120 |
+
N.x + (q3dd - q3 * q3d**2) * N.y + (q3 * sin(q3) *
|
| 121 |
+
q2d * q3d - cos(q3) * q2d * q3d - q3 * cos(q3) *
|
| 122 |
+
q2dd) * N.z)
|
| 123 |
+
assert (v4.dt(B) - (q2dd*A.x - q3*cos(q3)*q2d**2*A.y + q3dd*B.x +
|
| 124 |
+
(2*q3d**2 + q3*q3dd)*N.x + (q3dd - q3*q3d**2)*N.y +
|
| 125 |
+
(2*q3*sin(q3)*q2d*q3d - 2*cos(q3)*q2d*q3d -
|
| 126 |
+
q3*cos(q3)*q2dd)*N.z)).express(B).simplify() == 0
|
| 127 |
+
assert v5.dt(B) == q1d*A.x + (q3*q2d + q2d)*A.y + (-q2*q2d + q3d)*A.z
|
| 128 |
+
assert v5.dt(A) == q1d*A.x + q2d*A.y + q3d*A.z
|
| 129 |
+
assert v5.dt(N) == (-q2*q3d + q1d)*A.x + (q1*q3d + q2d)*A.y + q3d*A.z
|
| 130 |
+
assert v3.diff(q1d, N) == 0
|
| 131 |
+
assert v3.diff(q2d, N) == A.x - q3 * cos(q3) * N.z
|
| 132 |
+
assert v3.diff(q3d, N) == q3 * N.x + N.y
|
| 133 |
+
assert v3.diff(q1d, A) == 0
|
| 134 |
+
assert v3.diff(q2d, A) == A.x - q3 * cos(q3) * N.z
|
| 135 |
+
assert v3.diff(q3d, A) == q3 * N.x + N.y
|
| 136 |
+
assert v3.diff(q1d, B) == 0
|
| 137 |
+
assert v3.diff(q2d, B) == A.x - q3 * cos(q3) * N.z
|
| 138 |
+
assert v3.diff(q3d, B) == q3 * N.x + N.y
|
| 139 |
+
assert v4.diff(q1d, N) == 0
|
| 140 |
+
assert v4.diff(q2d, N) == A.x - q3 * cos(q3) * N.z
|
| 141 |
+
assert v4.diff(q3d, N) == B.x + q3 * N.x + N.y
|
| 142 |
+
assert v4.diff(q1d, A) == 0
|
| 143 |
+
assert v4.diff(q2d, A) == A.x - q3 * cos(q3) * N.z
|
| 144 |
+
assert v4.diff(q3d, A) == B.x + q3 * N.x + N.y
|
| 145 |
+
assert v4.diff(q1d, B) == 0
|
| 146 |
+
assert v4.diff(q2d, B) == A.x - q3 * cos(q3) * N.z
|
| 147 |
+
assert v4.diff(q3d, B) == B.x + q3 * N.x + N.y
|
| 148 |
+
|
| 149 |
+
# diff() should only express vector components in the derivative frame if
|
| 150 |
+
# the orientation of the component's frame depends on the variable
|
| 151 |
+
v6 = q2**2*N.y + q2**2*A.y + q2**2*B.y
|
| 152 |
+
# already expressed in N
|
| 153 |
+
n_measy = 2*q2
|
| 154 |
+
# A_C_N does not depend on q2, so don't express in N
|
| 155 |
+
a_measy = 2*q2
|
| 156 |
+
# B_C_N depends on q2, so express in N
|
| 157 |
+
b_measx = (q2**2*B.y).dot(N.x).diff(q2)
|
| 158 |
+
b_measy = (q2**2*B.y).dot(N.y).diff(q2)
|
| 159 |
+
b_measz = (q2**2*B.y).dot(N.z).diff(q2)
|
| 160 |
+
n_comp, a_comp = v6.diff(q2, N).args
|
| 161 |
+
assert len(v6.diff(q2, N).args) == 2 # only N and A parts
|
| 162 |
+
assert n_comp[1] == N
|
| 163 |
+
assert a_comp[1] == A
|
| 164 |
+
assert n_comp[0] == Matrix([b_measx, b_measy + n_measy, b_measz])
|
| 165 |
+
assert a_comp[0] == Matrix([0, a_measy, 0])
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
def test_vector_var_in_dcm():
|
| 169 |
+
|
| 170 |
+
N = ReferenceFrame('N')
|
| 171 |
+
A = ReferenceFrame('A')
|
| 172 |
+
B = ReferenceFrame('B')
|
| 173 |
+
u1, u2, u3, u4 = dynamicsymbols('u1 u2 u3 u4')
|
| 174 |
+
|
| 175 |
+
v = u1 * u2 * A.x + u3 * N.y + u4**2 * N.z
|
| 176 |
+
|
| 177 |
+
assert v.diff(u1, N, var_in_dcm=False) == u2 * A.x
|
| 178 |
+
assert v.diff(u1, A, var_in_dcm=False) == u2 * A.x
|
| 179 |
+
assert v.diff(u3, N, var_in_dcm=False) == N.y
|
| 180 |
+
assert v.diff(u3, A, var_in_dcm=False) == N.y
|
| 181 |
+
assert v.diff(u3, B, var_in_dcm=False) == N.y
|
| 182 |
+
assert v.diff(u4, N, var_in_dcm=False) == 2 * u4 * N.z
|
| 183 |
+
|
| 184 |
+
raises(ValueError, lambda: v.diff(u1, N))
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
def test_vector_simplify():
|
| 188 |
+
x, y, z, k, n, m, w, f, s, A = symbols('x, y, z, k, n, m, w, f, s, A')
|
| 189 |
+
N = ReferenceFrame('N')
|
| 190 |
+
|
| 191 |
+
test1 = (1 / x + 1 / y) * N.x
|
| 192 |
+
assert (test1 & N.x) != (x + y) / (x * y)
|
| 193 |
+
test1 = test1.simplify()
|
| 194 |
+
assert (test1 & N.x) == (x + y) / (x * y)
|
| 195 |
+
|
| 196 |
+
test2 = (A**2 * s**4 / (4 * pi * k * m**3)) * N.x
|
| 197 |
+
test2 = test2.simplify()
|
| 198 |
+
assert (test2 & N.x) == (A**2 * s**4 / (4 * pi * k * m**3))
|
| 199 |
+
|
| 200 |
+
test3 = ((4 + 4 * x - 2 * (2 + 2 * x)) / (2 + 2 * x)) * N.x
|
| 201 |
+
test3 = test3.simplify()
|
| 202 |
+
assert (test3 & N.x) == 0
|
| 203 |
+
|
| 204 |
+
test4 = ((-4 * x * y**2 - 2 * y**3 - 2 * x**2 * y) / (x + y)**2) * N.x
|
| 205 |
+
test4 = test4.simplify()
|
| 206 |
+
assert (test4 & N.x) == -2 * y
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
def test_vector_evalf():
|
| 210 |
+
a, b = symbols('a b')
|
| 211 |
+
v = pi * A.x
|
| 212 |
+
assert v.evalf(2) == Float('3.1416', 2) * A.x
|
| 213 |
+
v = pi * A.x + 5 * a * A.y - b * A.z
|
| 214 |
+
assert v.evalf(3) == Float('3.1416', 3) * A.x + Float('5', 3) * a * A.y - b * A.z
|
| 215 |
+
assert v.evalf(5, subs={a: 1.234, b:5.8973}) == Float('3.1415926536', 5) * A.x + Float('6.17', 5) * A.y - Float('5.8973', 5) * A.z
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
def test_vector_angle():
|
| 219 |
+
A = ReferenceFrame('A')
|
| 220 |
+
v1 = A.x + A.y
|
| 221 |
+
v2 = A.z
|
| 222 |
+
assert v1.angle_between(v2) == pi/2
|
| 223 |
+
B = ReferenceFrame('B')
|
| 224 |
+
B.orient_axis(A, A.x, pi)
|
| 225 |
+
v3 = A.x
|
| 226 |
+
v4 = B.x
|
| 227 |
+
assert v3.angle_between(v4) == 0
|
| 228 |
+
|
| 229 |
+
|
| 230 |
+
def test_vector_xreplace():
|
| 231 |
+
x, y, z = symbols('x y z')
|
| 232 |
+
v = x**2 * A.x + x*y * A.y + x*y*z * A.z
|
| 233 |
+
assert v.xreplace({x : cos(x)}) == cos(x)**2 * A.x + y*cos(x) * A.y + y*z*cos(x) * A.z
|
| 234 |
+
assert v.xreplace({x*y : pi}) == x**2 * A.x + pi * A.y + x*y*z * A.z
|
| 235 |
+
assert v.xreplace({x*y*z : 1}) == x**2*A.x + x*y*A.y + A.z
|
| 236 |
+
assert v.xreplace({x:1, z:0}) == A.x + y * A.y
|
| 237 |
+
raises(TypeError, lambda: v.xreplace())
|
| 238 |
+
raises(TypeError, lambda: v.xreplace([x, y]))
|
| 239 |
+
|
| 240 |
+
def test_issue_23366():
|
| 241 |
+
u1 = dynamicsymbols('u1')
|
| 242 |
+
N = ReferenceFrame('N')
|
| 243 |
+
N_v_A = u1*N.x
|
| 244 |
+
raises(VectorTypeError, lambda: N_v_A.diff(N, u1))
|
| 245 |
+
|
| 246 |
+
|
| 247 |
+
def test_vector_outer():
|
| 248 |
+
a, b, c, d, e, f = symbols('a, b, c, d, e, f')
|
| 249 |
+
N = ReferenceFrame('N')
|
| 250 |
+
v1 = a*N.x + b*N.y + c*N.z
|
| 251 |
+
v2 = d*N.x + e*N.y + f*N.z
|
| 252 |
+
v1v2 = Matrix([[a*d, a*e, a*f],
|
| 253 |
+
[b*d, b*e, b*f],
|
| 254 |
+
[c*d, c*e, c*f]])
|
| 255 |
+
assert v1.outer(v2).to_matrix(N) == v1v2
|
| 256 |
+
assert (v1 | v2).to_matrix(N) == v1v2
|
| 257 |
+
v2v1 = Matrix([[d*a, d*b, d*c],
|
| 258 |
+
[e*a, e*b, e*c],
|
| 259 |
+
[f*a, f*b, f*c]])
|
| 260 |
+
assert v2.outer(v1).to_matrix(N) == v2v1
|
| 261 |
+
assert (v2 | v1).to_matrix(N) == v2v1
|
| 262 |
+
|
| 263 |
+
|
| 264 |
+
def test_overloaded_operators():
|
| 265 |
+
a, b, c, d, e, f = symbols('a, b, c, d, e, f')
|
| 266 |
+
N = ReferenceFrame('N')
|
| 267 |
+
v1 = a*N.x + b*N.y + c*N.z
|
| 268 |
+
v2 = d*N.x + e*N.y + f*N.z
|
| 269 |
+
|
| 270 |
+
assert v1 + v2 == v2 + v1
|
| 271 |
+
assert v1 - v2 == -v2 + v1
|
| 272 |
+
assert v1 & v2 == v2 & v1
|
| 273 |
+
assert v1 ^ v2 == v1.cross(v2)
|
| 274 |
+
assert v2 ^ v1 == v2.cross(v1)
|
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/polys/__pycache__/appellseqs.cpython-311.pyc
ADDED
|
Binary file (11 kB). View file
|
|
|