├── .gitignore ├── .nojekyll ├── CITATION.cff ├── LICENSE ├── README.md ├── dist ├── metrolopy-0.6.5-py3-none-any.whl └── metrolopy-0.6.5.tar.gz ├── docs ├── .nojekyll ├── Makefile ├── _build │ ├── doctrees │ │ ├── environment.pickle │ │ ├── hand_made_doc.doctree │ │ ├── index.doctree │ │ ├── metrolopy.doctree │ │ ├── metrolopy.tests.doctree │ │ ├── modules.doctree │ │ └── todo.doctree │ └── html │ │ ├── _downloads │ │ └── tutorial.ipynb │ │ ├── _sources │ │ ├── hand_made_doc.rst.txt │ │ ├── index.rst.txt │ │ ├── metrolopy.rst.txt │ │ ├── metrolopy.tests.rst.txt │ │ ├── modules.rst.txt │ │ └── todo.rst.txt │ │ ├── _static │ │ ├── ajax-loader.gif │ │ ├── basic.css │ │ ├── comment-bright.png │ │ ├── comment-close.png │ │ ├── comment.png │ │ ├── constants.html │ │ ├── doctools.js │ │ ├── down-pressed.png │ │ ├── down.png │ │ ├── file.png │ │ ├── jquery-3.1.0.js │ │ ├── jquery.js │ │ ├── minus.png │ │ ├── nature.css │ │ ├── plus.png │ │ ├── pygments.css │ │ ├── searchtools.js │ │ ├── tutorial.html │ │ ├── underscore-1.3.1.js │ │ ├── underscore.js │ │ ├── units.html │ │ ├── up-pressed.png │ │ ├── up.png │ │ └── websupport.js │ │ ├── genindex.html │ │ ├── hand_made_doc.html │ │ ├── index.html │ │ ├── metrolopy.html │ │ ├── metrolopy.tests.html │ │ ├── modules.html │ │ ├── objects.inv │ │ ├── py-modindex.html │ │ ├── search.html │ │ ├── searchindex.js │ │ └── todo.html ├── _static │ ├── .DS_Store │ ├── constants.html │ ├── tutorial.html │ └── units.html ├── conf.py ├── hand_made_doc.rst ├── index.html ├── index.rst ├── make.bat ├── metrolopy.rst ├── metrolopy.tests.rst ├── modules.rst ├── todo.rst └── tutorial.ipynb ├── metrolopy ├── __init__.py ├── budget.py ├── codata2018.py ├── constant.py ├── constcom.py ├── dfunc.py ├── distributions.py ├── exceptions.py ├── fit.py ├── functions.py ├── gummy.py ├── indexed.py ├── license.txt ├── logunit.py ├── mean.py ├── miscunits.py ├── nonlinearunit.py ├── nummy.py ├── offsetunit.py ├── pmethod.py ├── prefixedunit.py ├── printing.py ├── relunits.py ├── siunits.py ├── tests │ ├── __init__.py │ ├── common.py │ ├── test_complex.py │ ├── test_create.py │ ├── test_gummy.py │ ├── test_misc.py │ ├── test_operations.py │ └── test_ubreakdown.py ├── ummy.py ├── unit.py ├── unitparser.py ├── unitutils.py ├── usunits.py └── version.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | #dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | doctrees/ 107 | .buildinfo 108 | 109 | .DS_Store 110 | -------------------------------------------------------------------------------- /.nojekyll: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "If you use this software, please cite it as below." 3 | authors: 4 | - family-names: "Parks" 5 | given-names: "Harold V." 6 | title: "MetroloPy" 7 | version: 0.6.5 8 | doi: 10.5281/zenodo.15595291 9 | date-released: 2025-06-04 10 | url: "https://github.com/nrc-cnrc/MetroloPy" 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MetroloPy 2 | 3 | tools for dealing with physical quantities: uncertainty propagation and unit conversion 4 | 5 | --- 6 | 7 | MetroloPy is a pure python package and requires Python 3.5 or later and the SciPy stack (NumPy, SciPy and Pandas). It looks best in a Jupyter Notebook. 8 | 9 | Install MetroloPy with `pip install metrolopy` or 10 | `conda install -c conda-forge metrolopy`. 11 | 12 | Physical quantities can then be represented in Python as `gummy` objects with an uncertainty and (or) a unit: 13 | 14 |
>>> import metrolopy as uc
15 | >>> a = uc.gummy(1.2345,u=0.0234,unit='cm')
16 | >>> a
17 | 1.234(23) cm
18 | 
19 | >>> b = uc.gummy(3.034,u=0.174,unit='mm')
20 | >>> f = uc.gummy(uc.UniformDist(center=0.9345,half_width=0.096),unit='N')
21 | >>> p = f/(a*b)
22 | >>> p
23 | 2.50(21) N/cm2
24 | 
25 | >>> p.unit = 'kPa'
26 | >>> p.uunit = '%'
27 | >>> p
28 | 25.0 kPa ± 8.5%
29 | 
30 | 31 | MetroloPy can do much more including Monte-Carlo uncertainty propagation, generating uncertainty budget tables, and curve fitting. It can also handle expanded uncertainties, degrees of freedom, correlated quantities, and complex valued quantities. See: 32 | 33 | * [a tutorial](https://nrc-cnrc.github.io/MetroloPy/_build/html/_static/tutorial.html) (or download the tutorial as Jupyter notebook) 34 | * [the documentation](https://nrc-cnrc.github.io/MetroloPy/) 35 | * [the issues page on GitHub](https://github.com/nrc-cnrc/Metrolopy/issues) 36 | * [a list of the units built into MetroloPy](https://nrc-cnrc.github.io/MetroloPy/_static/units.html) 37 | * [a list of the physical constants built into MetroloPy](https://nrc-cnrc.github.io/MetroloPy/_static/constants.html) 38 | 39 | ## new in version 0.6.0 40 | 41 | * A constant library has been added with physical constants that can be accessed 42 | by name or alias with the `constant` function. The `search_constants` function 43 | with no argument gives a listing of all built-in constants. Each constant 44 | definition includes any correlations with other constants. 45 | 46 | * The `Quantity` class has been added to represent a general numerical value 47 | multiplied by a unit and the `unit` function has been added to retrieve 48 | `Unit` instances from the unit library by name or alias. `Unit` instances 49 | can now be multiplied and divided by other `Unit` instances to produce 50 | composite units, can be multiplied and divided by numbers to produce 51 | `Quantity` instances or multiply or divide `Quantity` instances. The 52 | `gummy` class is now a subclass of `Quantity` with a `nummy` value rather 53 | than a subclass of `nummy`. A `QuantityArray` class has been introduced 54 | to represent an array of values all with the same unit. Multiplying a `Unit` 55 | instance by a list, tuple, or numpy array produces a `QuantityArray` instance. 56 | 57 | * The `immy` class has been introduced as an `ummy` valued counterpart of the 58 | `jummy` class for representing complex values with uncertainties. `immy` 59 | and `jummy` values can now be displayed in a polar representation in addition 60 | to a cartesian representation. `immy` and `jummy` .r and .phi properties 61 | have been added to access the magnitude and argument of the values as a 62 | complement to the .real and .imag properties. 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /dist/metrolopy-0.6.5-py3-none-any.whl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/dist/metrolopy-0.6.5-py3-none-any.whl -------------------------------------------------------------------------------- /dist/metrolopy-0.6.5.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/dist/metrolopy-0.6.5.tar.gz -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = metrolopy 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/_build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/doctrees/environment.pickle -------------------------------------------------------------------------------- /docs/_build/doctrees/hand_made_doc.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/doctrees/hand_made_doc.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/doctrees/index.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/metrolopy.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/doctrees/metrolopy.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/metrolopy.tests.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/doctrees/metrolopy.tests.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/modules.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/doctrees/modules.doctree -------------------------------------------------------------------------------- /docs/_build/doctrees/todo.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/doctrees/todo.doctree -------------------------------------------------------------------------------- /docs/_build/html/_sources/index.rst.txt: -------------------------------------------------------------------------------- 1 | .. metrolopy documentation master file, created by 2 | sphinx-quickstart on Fri Feb 22 16:15:02 2019. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | :caption: Contents: 9 | 10 | =================== 11 | MetroloPy, the docs 12 | =================== 13 | 14 | tools for dealing with physical quantities: uncertainty propagation and unit 15 | conversion 16 | 17 | 18 | getting started 19 | =============== 20 | 21 | MetroloPy is a pure python package and requires Python 3 and the 22 | `SciPy `_ stack (NumPy, SciPy, Pandas, and IPython). 23 | It looks best in a `Jupyter notebook `_. 24 | 25 | Install MetroloPy with ``pip install metrolopy`` or 26 | ``conda install -c conda-forge metrolopy``. 27 | 28 | Physical quantities can then be represented in Python as `gummy`_ objects 29 | with an uncertainty and (or) a unit: 30 | 31 | .. _gummy: hand_made_doc.html#class-gummy 32 | 33 | .. raw:: html 34 | 35 |
>>> import metrolopy as uc
 36 |     >>> a = uc.gummy(1.2345,u=0.0234,unit='cm')
 37 |     >>> a
 38 |     1.234(23) cm
 39 |     
 40 |     >>> b = uc.gummy(3.034,u=0.174,unit='mm')
 41 |     >>> f = uc.gummy(uc.UniformDist(center=0.9345,half_width=0.096),unit='N')
 42 |     >>> p = f/(a*b)
 43 |     >>> p
 44 |     2.50(21) N/cm2
 45 |     
 46 |     >>> p.unit = 'kPa'
 47 |     >>> p.uunit = '%'
 48 |     >>> p
 49 |     25.0 kPa ± 8.5%
 50 |     
51 |
52 | 53 | MetroloPy can do much more including `Monte-Carlo uncertainty propagation`_, 54 | generating `uncertainty budget tables`_, and `curve fitting`_. It can also handle 55 | `expanded uncertainties`_, `degrees of freedom`_, `correlated quantities`_, and 56 | `complex valued quantities`_. 57 | 58 | .. _Monte-Carlo uncertainty propagation: _static/tutorial.html#Monte-Carlo-uncertainty-propagation 59 | 60 | .. _uncertainty budget tables: _static/tutorial.html#an-uncertainty-budget 61 | 62 | .. _curve fitting: _static/tutorial.html#curve-fitting 63 | 64 | .. _expanded uncertainties: _static/tutorial.html#expanded-uncertainty 65 | 66 | .. _degrees of freedom: _static/tutorial.html#degrees-of-freedom-and-uncertainty-types 67 | 68 | .. _correlated quantities: _static/tutorial.html#creating-correlated-gummys 69 | 70 | .. _complex valued quantities: hand_made_doc.html#jummy 71 | 72 | further reading 73 | =============== 74 | 75 | * `a tutorial <_static/tutorial.html>`_ (or :download:`download the tutorial as a Jupyter notebook `) 76 | * :ref:`the API documentation ` (see the auto-generated docs below for an alternative set of documentation) 77 | * `a list of the measurement units built into MetroloPy <_static/units.html>`_ 78 | * `a list of the physical constants built into MetroloPy `_ 79 | * :ref:`package development and to do ` 80 | * `the issues page on GitHub `_ 81 | * `the source code on GitHub `_ 82 | 83 | 84 | the auto-generated docs (indices and tables) 85 | ============================================ 86 | 87 | These pages were automatically generated from the doc strings in the source 88 | code. They are slightly more comprehensive but perhaps slightly more confusing 89 | than the handmade API docs referenced in the further reading section above. 90 | 91 | * :ref:`genindex` 92 | * :ref:`modindex` 93 | * :ref:`search` 94 | 95 | 96 | Where did the name for the gummy class come from? 97 | ================================================= 98 | 99 | The name comes from the 100 | `JGCM/ISO Guide to the Expression of Uncertainty in Measurement `_ 101 | which is also known as the GUM. The GUM is the international standard used by 102 | metrology institutes and calibration labs for expressing and propagating 103 | measurement uncertainty. The gummy object implements many of the 104 | recommendations outlined in the GUM. 105 | 106 | Other references of note are the 107 | `draft 9th edition of the SI Brochure `_ 108 | which contains the definitions of the SI units, and 109 | `NIST Special Publication 1038 `_ 110 | where many of the US customary units are defined. Some physical constants 111 | used for unit definitions are from the 112 | `2014 CODATA recommended values `_ 113 | and the 114 | `IAU 2009 system of astronomical constants `_. 115 | 116 | 117 | version history 118 | =============== 119 | 120 | * Version 0.5.0, built 26 March 2019, is the first public release. 121 | * Version 0.5.1, built 2 April 2019, fixed a major bug that generated negative 122 | uncertainties in some cases and fixed some other minor bugs. Improved support 123 | for fraction.Fraction and mpmath.mpf values. 124 | * Version 0.5.2, built 5 April 2019, fixed a major bug that propagated 125 | uncertainty incorrectly if a gummy was created with an uncertainty set with 126 | an integer data type. Fixed several other minor bugs. 127 | * Version 0.5.3, built 10 April 2019, minor bug fixes. 128 | * Version 0.5.4, built 15 April 2019, minor bug fixes. 129 | * Version 0.5.5, built 7 May 2020, minor bug fixes. 130 | * Version 0.5.6, built 24 September 2020, minor bug fixes. 131 | * Version 0.5.7, built 26 September 2020, minor change to setup.py. 132 | * Verison 0.6.0, built 19 October 2020, added the `Quantity` and `immy` classes 133 | as well as a library of physical constants. 134 | * Version 0.6.1 built 19 October 2020, bug fixes 135 | * Version 0.6.2 built 10 July 2021, bug fixes 136 | * Version 0.6.3 built 13 May 2022, bug fixes 137 | * Version 0.6.4 built 28 May 2025, bug fixes 138 | * Version 0.6.5 built 04 June 2025, bug fixe 139 | 140 | 141 | author 142 | ====== 143 | 144 | Harold Parks, parksh@nrc.ca, National Research Council Canada 145 | 146 | 147 | license 148 | ======= 149 | 150 | MetroloPy is distributed as free software under the terms of the 151 | `GNU General Public License version 3 `_. 152 | In practice, this license imposes 153 | no restriction on using MetroloPy. However, if you want to further convey 154 | verbatim or modified versions of the code you must do so under the same license 155 | terms. Please contact NRC if you wish to license MetroloPy under different 156 | terms. 157 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/metrolopy.rst.txt: -------------------------------------------------------------------------------- 1 | metrolopy package 2 | ================= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | 9 | metrolopy.tests 10 | 11 | Submodules 12 | ---------- 13 | 14 | metrolopy.budget module 15 | ----------------------- 16 | 17 | .. automodule:: metrolopy.budget 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | 22 | metrolopy.dfunc module 23 | ---------------------- 24 | 25 | .. automodule:: metrolopy.dfunc 26 | :members: 27 | :undoc-members: 28 | :show-inheritance: 29 | 30 | metrolopy.distributions module 31 | ------------------------------ 32 | 33 | .. automodule:: metrolopy.distributions 34 | :members: 35 | :undoc-members: 36 | :show-inheritance: 37 | 38 | metrolopy.exceptions module 39 | --------------------------- 40 | 41 | .. automodule:: metrolopy.exceptions 42 | :members: 43 | :undoc-members: 44 | :show-inheritance: 45 | 46 | metrolopy.fit module 47 | -------------------- 48 | 49 | .. automodule:: metrolopy.fit 50 | :members: 51 | :undoc-members: 52 | :show-inheritance: 53 | 54 | metrolopy.functions module 55 | -------------------------- 56 | 57 | .. automodule:: metrolopy.functions 58 | :members: 59 | :undoc-members: 60 | :show-inheritance: 61 | 62 | metrolopy.gummy module 63 | ---------------------- 64 | 65 | .. automodule:: metrolopy.gummy 66 | :members: 67 | :undoc-members: 68 | :show-inheritance: 69 | 70 | metrolopy.logunit module 71 | ------------------------ 72 | 73 | .. automodule:: metrolopy.logunit 74 | :members: 75 | :undoc-members: 76 | :show-inheritance: 77 | 78 | metrolopy.mean module 79 | --------------------- 80 | 81 | .. automodule:: metrolopy.mean 82 | :members: 83 | :undoc-members: 84 | :show-inheritance: 85 | 86 | metrolopy.nonlinearunit module 87 | ------------------------------ 88 | 89 | .. automodule:: metrolopy.nonlinearunit 90 | :members: 91 | :undoc-members: 92 | :show-inheritance: 93 | 94 | metrolopy.nummy module 95 | ---------------------- 96 | 97 | .. automodule:: metrolopy.nummy 98 | :members: 99 | :undoc-members: 100 | :show-inheritance: 101 | 102 | metrolopy.offsetunit module 103 | --------------------------- 104 | 105 | .. automodule:: metrolopy.offsetunit 106 | :members: 107 | :undoc-members: 108 | :show-inheritance: 109 | 110 | metrolopy.pmethod module 111 | ------------------------ 112 | 113 | .. automodule:: metrolopy.pmethod 114 | :members: 115 | :undoc-members: 116 | :show-inheritance: 117 | 118 | metrolopy.prefixedunit module 119 | ----------------------------- 120 | 121 | .. automodule:: metrolopy.prefixedunit 122 | :members: 123 | :undoc-members: 124 | :show-inheritance: 125 | 126 | metrolopy.printing module 127 | ------------------------- 128 | 129 | .. automodule:: metrolopy.printing 130 | :members: 131 | :undoc-members: 132 | :show-inheritance: 133 | 134 | metrolopy.relunits module 135 | ------------------------- 136 | 137 | .. automodule:: metrolopy.relunits 138 | :members: 139 | :undoc-members: 140 | :show-inheritance: 141 | 142 | metrolopy.siunits module 143 | ------------------------ 144 | 145 | .. automodule:: metrolopy.siunits 146 | :members: 147 | :undoc-members: 148 | :show-inheritance: 149 | 150 | metrolopy.ummy module 151 | --------------------- 152 | 153 | .. automodule:: metrolopy.ummy 154 | :members: 155 | :undoc-members: 156 | :show-inheritance: 157 | 158 | metrolopy.unit module 159 | --------------------- 160 | 161 | .. automodule:: metrolopy.unit 162 | :members: 163 | :undoc-members: 164 | :show-inheritance: 165 | 166 | metrolopy.unitutils module 167 | -------------------------- 168 | 169 | .. automodule:: metrolopy.unitutils 170 | :members: 171 | :undoc-members: 172 | :show-inheritance: 173 | 174 | metrolopy.usunits module 175 | ------------------------ 176 | 177 | .. automodule:: metrolopy.usunits 178 | :members: 179 | :undoc-members: 180 | :show-inheritance: 181 | 182 | metrolopy.version module 183 | ------------------------ 184 | 185 | .. automodule:: metrolopy.version 186 | :members: 187 | :undoc-members: 188 | :show-inheritance: 189 | 190 | 191 | Module contents 192 | --------------- 193 | 194 | .. automodule:: metrolopy 195 | :members: 196 | :undoc-members: 197 | :show-inheritance: 198 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/metrolopy.tests.rst.txt: -------------------------------------------------------------------------------- 1 | metrolopy.tests package 2 | ======================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | metrolopy.tests.test_create module 8 | ---------------------------------- 9 | 10 | .. automodule:: metrolopy.tests.test_create 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | 16 | Module contents 17 | --------------- 18 | 19 | .. automodule:: metrolopy.tests 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/modules.rst.txt: -------------------------------------------------------------------------------- 1 | metrolopy 2 | ========= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | metrolopy 8 | -------------------------------------------------------------------------------- /docs/_build/html/_sources/todo.rst.txt: -------------------------------------------------------------------------------- 1 | .. toctree:: 2 | :maxdepth: 2 3 | :caption: Contents: 4 | 5 | .. _todo: 6 | 7 | Lots of help is needed to find bugs. 8 | 9 | to do 10 | ===== 11 | 12 | start by putting something here 13 | -------------------------------------------------------------------------------- /docs/_build/html/_static/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/html/_static/ajax-loader.gif -------------------------------------------------------------------------------- /docs/_build/html/_static/comment-bright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/html/_static/comment-bright.png -------------------------------------------------------------------------------- /docs/_build/html/_static/comment-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/html/_static/comment-close.png -------------------------------------------------------------------------------- /docs/_build/html/_static/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/html/_static/comment.png -------------------------------------------------------------------------------- /docs/_build/html/_static/doctools.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Base JavaScript utilities for all Sphinx HTML documentation. 3 | */ 4 | "use strict"; 5 | 6 | const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ 7 | "TEXTAREA", 8 | "INPUT", 9 | "SELECT", 10 | "BUTTON", 11 | ]); 12 | 13 | const _ready = (callback) => { 14 | if (document.readyState !== "loading") { 15 | callback(); 16 | } else { 17 | document.addEventListener("DOMContentLoaded", callback); 18 | } 19 | }; 20 | 21 | /** 22 | * Small JavaScript module for the documentation. 23 | */ 24 | const Documentation = { 25 | init: () => { 26 | Documentation.initDomainIndexTable(); 27 | Documentation.initOnKeyListeners(); 28 | }, 29 | 30 | /** 31 | * i18n support 32 | */ 33 | TRANSLATIONS: {}, 34 | PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), 35 | LOCALE: "unknown", 36 | 37 | // gettext and ngettext don't access this so that the functions 38 | // can safely bound to a different name (_ = Documentation.gettext) 39 | gettext: (string) => { 40 | const translated = Documentation.TRANSLATIONS[string]; 41 | switch (typeof translated) { 42 | case "undefined": 43 | return string; // no translation 44 | case "string": 45 | return translated; // translation exists 46 | default: 47 | return translated[0]; // (singular, plural) translation tuple exists 48 | } 49 | }, 50 | 51 | ngettext: (singular, plural, n) => { 52 | const translated = Documentation.TRANSLATIONS[singular]; 53 | if (typeof translated !== "undefined") 54 | return translated[Documentation.PLURAL_EXPR(n)]; 55 | return n === 1 ? singular : plural; 56 | }, 57 | 58 | addTranslations: (catalog) => { 59 | Object.assign(Documentation.TRANSLATIONS, catalog.messages); 60 | Documentation.PLURAL_EXPR = new Function( 61 | "n", 62 | `return (${catalog.plural_expr})` 63 | ); 64 | Documentation.LOCALE = catalog.locale; 65 | }, 66 | 67 | /** 68 | * helper function to focus on search bar 69 | */ 70 | focusSearchBar: () => { 71 | document.querySelectorAll("input[name=q]")[0]?.focus(); 72 | }, 73 | 74 | /** 75 | * Initialise the domain index toggle buttons 76 | */ 77 | initDomainIndexTable: () => { 78 | const toggler = (el) => { 79 | const idNumber = el.id.substr(7); 80 | const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); 81 | if (el.src.substr(-9) === "minus.png") { 82 | el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; 83 | toggledRows.forEach((el) => (el.style.display = "none")); 84 | } else { 85 | el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; 86 | toggledRows.forEach((el) => (el.style.display = "")); 87 | } 88 | }; 89 | 90 | const togglerElements = document.querySelectorAll("img.toggler"); 91 | togglerElements.forEach((el) => 92 | el.addEventListener("click", (event) => toggler(event.currentTarget)) 93 | ); 94 | togglerElements.forEach((el) => (el.style.display = "")); 95 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); 96 | }, 97 | 98 | initOnKeyListeners: () => { 99 | // only install a listener if it is really needed 100 | if ( 101 | !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && 102 | !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS 103 | ) 104 | return; 105 | 106 | document.addEventListener("keydown", (event) => { 107 | // bail for input elements 108 | if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; 109 | // bail with special keys 110 | if (event.altKey || event.ctrlKey || event.metaKey) return; 111 | 112 | if (!event.shiftKey) { 113 | switch (event.key) { 114 | case "ArrowLeft": 115 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; 116 | 117 | const prevLink = document.querySelector('link[rel="prev"]'); 118 | if (prevLink && prevLink.href) { 119 | window.location.href = prevLink.href; 120 | event.preventDefault(); 121 | } 122 | break; 123 | case "ArrowRight": 124 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; 125 | 126 | const nextLink = document.querySelector('link[rel="next"]'); 127 | if (nextLink && nextLink.href) { 128 | window.location.href = nextLink.href; 129 | event.preventDefault(); 130 | } 131 | break; 132 | } 133 | } 134 | 135 | // some keyboard layouts may need Shift to get / 136 | switch (event.key) { 137 | case "/": 138 | if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; 139 | Documentation.focusSearchBar(); 140 | event.preventDefault(); 141 | } 142 | }); 143 | }, 144 | }; 145 | 146 | // quick alias for translations 147 | const _ = Documentation.gettext; 148 | 149 | _ready(Documentation.init); 150 | -------------------------------------------------------------------------------- /docs/_build/html/_static/down-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/html/_static/down-pressed.png -------------------------------------------------------------------------------- /docs/_build/html/_static/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/html/_static/down.png -------------------------------------------------------------------------------- /docs/_build/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/html/_static/file.png -------------------------------------------------------------------------------- /docs/_build/html/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/html/_static/minus.png -------------------------------------------------------------------------------- /docs/_build/html/_static/nature.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Sphinx stylesheet -- nature theme. 3 | */ 4 | 5 | @import url("basic.css"); 6 | 7 | /* -- page layout ----------------------------------------------------------- */ 8 | 9 | body { 10 | font-family: Arial, sans-serif; 11 | font-size: 100%; 12 | background-color: #fff; 13 | color: #555; 14 | margin: 0; 15 | padding: 0; 16 | } 17 | 18 | div.documentwrapper { 19 | float: left; 20 | width: 100%; 21 | } 22 | 23 | div.bodywrapper { 24 | margin: 0 0 0 230px; 25 | } 26 | 27 | hr { 28 | border: 1px solid #B1B4B6; 29 | } 30 | 31 | div.document { 32 | background-color: #eee; 33 | } 34 | 35 | div.body { 36 | background-color: #ffffff; 37 | color: #3E4349; 38 | padding: 0 30px 30px 30px; 39 | font-size: 0.9em; 40 | } 41 | 42 | div.footer { 43 | color: #555; 44 | width: 100%; 45 | padding: 13px 0; 46 | text-align: center; 47 | font-size: 75%; 48 | } 49 | 50 | div.footer a { 51 | color: #444; 52 | text-decoration: underline; 53 | } 54 | 55 | div.related { 56 | background-color: #6BA81E; 57 | line-height: 32px; 58 | color: #fff; 59 | text-shadow: 0px 1px 0 #444; 60 | font-size: 0.9em; 61 | } 62 | 63 | div.related a { 64 | color: #E2F3CC; 65 | } 66 | 67 | div.sphinxsidebar { 68 | font-size: 0.75em; 69 | line-height: 1.5em; 70 | } 71 | 72 | div.sphinxsidebarwrapper{ 73 | padding: 20px 0; 74 | } 75 | 76 | div.sphinxsidebar h3, 77 | div.sphinxsidebar h4 { 78 | font-family: Arial, sans-serif; 79 | color: #222; 80 | font-size: 1.2em; 81 | font-weight: normal; 82 | margin: 0; 83 | padding: 5px 10px; 84 | background-color: #ddd; 85 | text-shadow: 1px 1px 0 white 86 | } 87 | 88 | div.sphinxsidebar h4{ 89 | font-size: 1.1em; 90 | } 91 | 92 | div.sphinxsidebar h3 a { 93 | color: #444; 94 | } 95 | 96 | 97 | div.sphinxsidebar p { 98 | color: #888; 99 | padding: 5px 20px; 100 | } 101 | 102 | div.sphinxsidebar p.topless { 103 | } 104 | 105 | div.sphinxsidebar ul { 106 | margin: 10px 20px; 107 | padding: 0; 108 | color: #000; 109 | } 110 | 111 | div.sphinxsidebar a { 112 | color: #444; 113 | } 114 | 115 | div.sphinxsidebar input { 116 | border: 1px solid #ccc; 117 | font-family: sans-serif; 118 | font-size: 1em; 119 | } 120 | 121 | div.sphinxsidebar .searchformwrapper { 122 | margin-left: 20px; 123 | margin-right: 20px; 124 | } 125 | 126 | /* -- body styles ----------------------------------------------------------- */ 127 | 128 | a { 129 | color: #005B81; 130 | text-decoration: none; 131 | } 132 | 133 | a:hover { 134 | color: #E32E00; 135 | text-decoration: underline; 136 | } 137 | 138 | a:visited { 139 | color: #551A8B; 140 | } 141 | 142 | div.body h1, 143 | div.body h2, 144 | div.body h3, 145 | div.body h4, 146 | div.body h5, 147 | div.body h6 { 148 | font-family: Arial, sans-serif; 149 | background-color: #BED4EB; 150 | font-weight: normal; 151 | color: #212224; 152 | margin: 30px 0px 10px 0px; 153 | padding: 5px 0 5px 10px; 154 | text-shadow: 0px 1px 0 white 155 | } 156 | 157 | div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; } 158 | div.body h2 { font-size: 150%; background-color: #C8D5E3; } 159 | div.body h3 { font-size: 120%; background-color: #D8DEE3; } 160 | div.body h4 { font-size: 110%; background-color: #D8DEE3; } 161 | div.body h5 { font-size: 100%; background-color: #D8DEE3; } 162 | div.body h6 { font-size: 100%; background-color: #D8DEE3; } 163 | 164 | a.headerlink { 165 | color: #c60f0f; 166 | font-size: 0.8em; 167 | padding: 0 4px 0 4px; 168 | text-decoration: none; 169 | } 170 | 171 | a.headerlink:hover { 172 | background-color: #c60f0f; 173 | color: white; 174 | } 175 | 176 | div.body p, div.body dd, div.body li { 177 | line-height: 1.5em; 178 | } 179 | 180 | div.admonition p.admonition-title + p { 181 | display: inline; 182 | } 183 | 184 | div.note { 185 | background-color: #eee; 186 | border: 1px solid #ccc; 187 | } 188 | 189 | div.seealso { 190 | background-color: #ffc; 191 | border: 1px solid #ff6; 192 | } 193 | 194 | nav.contents, 195 | aside.topic, 196 | div.topic { 197 | background-color: #eee; 198 | } 199 | 200 | div.warning { 201 | background-color: #ffe4e4; 202 | border: 1px solid #f66; 203 | } 204 | 205 | p.admonition-title { 206 | display: inline; 207 | } 208 | 209 | p.admonition-title:after { 210 | content: ":"; 211 | } 212 | 213 | pre { 214 | padding: 10px; 215 | line-height: 1.2em; 216 | border: 1px solid #C6C9CB; 217 | font-size: 1.1em; 218 | margin: 1.5em 0 1.5em 0; 219 | -webkit-box-shadow: 1px 1px 1px #d8d8d8; 220 | -moz-box-shadow: 1px 1px 1px #d8d8d8; 221 | } 222 | 223 | code { 224 | background-color: #ecf0f3; 225 | color: #222; 226 | /* padding: 1px 2px; */ 227 | font-size: 1.1em; 228 | font-family: monospace; 229 | } 230 | 231 | .viewcode-back { 232 | font-family: Arial, sans-serif; 233 | } 234 | 235 | div.viewcode-block:target { 236 | background-color: #f4debf; 237 | border-top: 1px solid #ac9; 238 | border-bottom: 1px solid #ac9; 239 | } 240 | 241 | div.code-block-caption { 242 | background-color: #ddd; 243 | color: #222; 244 | border: 1px solid #C6C9CB; 245 | } -------------------------------------------------------------------------------- /docs/_build/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/html/_static/plus.png -------------------------------------------------------------------------------- /docs/_build/html/_static/pygments.css: -------------------------------------------------------------------------------- 1 | pre { line-height: 125%; } 2 | td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } 3 | span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } 4 | td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } 5 | span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } 6 | .highlight .hll { background-color: #ffffcc } 7 | .highlight { background: #eeffcc; } 8 | .highlight .c { color: #408090; font-style: italic } /* Comment */ 9 | .highlight .err { border: 1px solid #F00 } /* Error */ 10 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */ 11 | .highlight .o { color: #666 } /* Operator */ 12 | .highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ 13 | .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ 14 | .highlight .cp { color: #007020 } /* Comment.Preproc */ 15 | .highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ 16 | .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ 17 | .highlight .cs { color: #408090; background-color: #FFF0F0 } /* Comment.Special */ 18 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 19 | .highlight .ge { font-style: italic } /* Generic.Emph */ 20 | .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ 21 | .highlight .gr { color: #F00 } /* Generic.Error */ 22 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 23 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 24 | .highlight .go { color: #333 } /* Generic.Output */ 25 | .highlight .gp { color: #C65D09; font-weight: bold } /* Generic.Prompt */ 26 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 27 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 28 | .highlight .gt { color: #04D } /* Generic.Traceback */ 29 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 30 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 31 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 32 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */ 33 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 34 | .highlight .kt { color: #902000 } /* Keyword.Type */ 35 | .highlight .m { color: #208050 } /* Literal.Number */ 36 | .highlight .s { color: #4070A0 } /* Literal.String */ 37 | .highlight .na { color: #4070A0 } /* Name.Attribute */ 38 | .highlight .nb { color: #007020 } /* Name.Builtin */ 39 | .highlight .nc { color: #0E84B5; font-weight: bold } /* Name.Class */ 40 | .highlight .no { color: #60ADD5 } /* Name.Constant */ 41 | .highlight .nd { color: #555; font-weight: bold } /* Name.Decorator */ 42 | .highlight .ni { color: #D55537; font-weight: bold } /* Name.Entity */ 43 | .highlight .ne { color: #007020 } /* Name.Exception */ 44 | .highlight .nf { color: #06287E } /* Name.Function */ 45 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ 46 | .highlight .nn { color: #0E84B5; font-weight: bold } /* Name.Namespace */ 47 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ 48 | .highlight .nv { color: #BB60D5 } /* Name.Variable */ 49 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ 50 | .highlight .w { color: #BBB } /* Text.Whitespace */ 51 | .highlight .mb { color: #208050 } /* Literal.Number.Bin */ 52 | .highlight .mf { color: #208050 } /* Literal.Number.Float */ 53 | .highlight .mh { color: #208050 } /* Literal.Number.Hex */ 54 | .highlight .mi { color: #208050 } /* Literal.Number.Integer */ 55 | .highlight .mo { color: #208050 } /* Literal.Number.Oct */ 56 | .highlight .sa { color: #4070A0 } /* Literal.String.Affix */ 57 | .highlight .sb { color: #4070A0 } /* Literal.String.Backtick */ 58 | .highlight .sc { color: #4070A0 } /* Literal.String.Char */ 59 | .highlight .dl { color: #4070A0 } /* Literal.String.Delimiter */ 60 | .highlight .sd { color: #4070A0; font-style: italic } /* Literal.String.Doc */ 61 | .highlight .s2 { color: #4070A0 } /* Literal.String.Double */ 62 | .highlight .se { color: #4070A0; font-weight: bold } /* Literal.String.Escape */ 63 | .highlight .sh { color: #4070A0 } /* Literal.String.Heredoc */ 64 | .highlight .si { color: #70A0D0; font-style: italic } /* Literal.String.Interpol */ 65 | .highlight .sx { color: #C65D09 } /* Literal.String.Other */ 66 | .highlight .sr { color: #235388 } /* Literal.String.Regex */ 67 | .highlight .s1 { color: #4070A0 } /* Literal.String.Single */ 68 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */ 69 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ 70 | .highlight .fm { color: #06287E } /* Name.Function.Magic */ 71 | .highlight .vc { color: #BB60D5 } /* Name.Variable.Class */ 72 | .highlight .vg { color: #BB60D5 } /* Name.Variable.Global */ 73 | .highlight .vi { color: #BB60D5 } /* Name.Variable.Instance */ 74 | .highlight .vm { color: #BB60D5 } /* Name.Variable.Magic */ 75 | .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /docs/_build/html/_static/up-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/html/_static/up-pressed.png -------------------------------------------------------------------------------- /docs/_build/html/_static/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/html/_static/up.png -------------------------------------------------------------------------------- /docs/_build/html/metrolopy.tests.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | metrolopy.tests package — metrolopy 0.6.5 documentation 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 30 | 31 |
32 |
33 |
34 |
35 | 36 |
37 |

metrolopy.tests package

38 |
39 |

Submodules

40 |
41 |
42 |

metrolopy.tests.test_create module

43 |
44 |
45 | class metrolopy.tests.test_create.TestCreate(methodName='runTest')
46 |

Bases: TestCase

47 |
48 |
49 | test_gummy_init(n=None, exception_on_warning=True, prnt=False, plot=False)
50 |
51 | 52 |
53 | 54 |
55 |
56 |

Module contents

57 |
58 |
59 | 60 | 61 |
62 |
63 |
64 |
65 | 104 |
105 |
106 | 119 | 123 | 124 | -------------------------------------------------------------------------------- /docs/_build/html/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_build/html/objects.inv -------------------------------------------------------------------------------- /docs/_build/html/py-modindex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Python Module Index — metrolopy 0.6.5 documentation 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 32 | 33 |
34 |
35 |
36 |
37 | 38 | 39 |

Python Module Index

40 | 41 |
42 | m 43 |
44 | 45 | 46 | 47 | 49 | 50 | 52 | 55 | 56 | 57 | 60 | 61 | 62 | 65 | 66 | 67 | 70 | 71 | 72 | 75 | 76 | 77 | 80 | 81 | 82 | 85 | 86 | 87 | 90 | 91 | 92 | 95 | 96 | 97 | 100 | 101 | 102 | 105 | 106 | 107 | 110 | 111 | 112 | 115 | 116 | 117 | 120 | 121 | 122 | 125 | 126 | 127 | 130 | 131 | 132 | 135 | 136 | 137 | 140 | 141 | 142 | 145 | 146 | 147 | 150 | 151 | 152 | 155 | 156 | 157 | 160 | 161 | 162 | 165 | 166 | 167 | 170 | 171 | 172 | 175 |
 
48 | m
53 | metrolopy 54 |
    58 | metrolopy.budget 59 |
    63 | metrolopy.dfunc 64 |
    68 | metrolopy.distributions 69 |
    73 | metrolopy.exceptions 74 |
    78 | metrolopy.fit 79 |
    83 | metrolopy.functions 84 |
    88 | metrolopy.gummy 89 |
    93 | metrolopy.logunit 94 |
    98 | metrolopy.mean 99 |
    103 | metrolopy.nonlinearunit 104 |
    108 | metrolopy.nummy 109 |
    113 | metrolopy.offsetunit 114 |
    118 | metrolopy.pmethod 119 |
    123 | metrolopy.prefixedunit 124 |
    128 | metrolopy.printing 129 |
    133 | metrolopy.relunits 134 |
    138 | metrolopy.siunits 139 |
    143 | metrolopy.tests 144 |
    148 | metrolopy.tests.test_create 149 |
    153 | metrolopy.ummy 154 |
    158 | metrolopy.unit 159 |
    163 | metrolopy.unitutils 164 |
    168 | metrolopy.usunits 169 |
    173 | metrolopy.version 174 |
176 | 177 | 178 |
179 |
180 |
181 |
182 | 196 |
197 |
198 | 211 | 215 | 216 | -------------------------------------------------------------------------------- /docs/_build/html/search.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Search — metrolopy 0.6.5 documentation 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 36 | 37 |
38 |
39 |
40 |
41 | 42 |

Search

43 | 44 | 52 | 53 | 54 |

55 | Searching for multiple words only shows matches that contain 56 | all words. 57 |

58 | 59 | 60 |
61 | 62 | 63 | 64 |
65 | 66 | 67 |
68 | 69 | 70 |
71 |
72 |
73 |
74 | 78 |
79 |
80 | 93 | 97 | 98 | -------------------------------------------------------------------------------- /docs/_build/html/todo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | to do — metrolopy 0.6.5 documentation 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 30 | 31 |
32 |
33 |
34 |
35 | 36 |
37 |
38 |

Lots of help is needed to find bugs.

39 |
40 |

to do

41 |

start by putting something here

42 |
43 | 44 | 45 |
46 |
47 |
48 |
49 | 70 |
71 |
72 | 85 | 89 | 90 | -------------------------------------------------------------------------------- /docs/_static/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrc-cnrc/MetroloPy/333f9a9fb8c81696a92adafbf3ed831bf18b3d17/docs/_static/.DS_Store -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # gummy documentation build configuration file, created by 5 | # sphinx-quickstart on Fri Feb 22 16:15:02 2019. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | # 20 | # import os 21 | # import sys 22 | # sys.path.insert(0, os.path.abspath('.')) 23 | 24 | 25 | # -- General configuration ------------------------------------------------ 26 | 27 | # If your documentation needs a minimal Sphinx version, state it here. 28 | # 29 | # needs_sphinx = '1.0' 30 | 31 | # Add any Sphinx extension module names here, as strings. They can be 32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 33 | # ones. 34 | 35 | extensions = [ 36 | 'sphinx.ext.autodoc', 37 | 'sphinx.ext.mathjax', 38 | 'sphinx.ext.githubpages', 39 | 'sphinx.ext.napoleon'] 40 | 41 | napoleon_use_param = False 42 | 43 | # Add any paths that contain templates here, relative to this directory. 44 | templates_path = ['_templates'] 45 | 46 | # The suffix(es) of source filenames. 47 | # You can specify multiple suffix as a list of string: 48 | # 49 | # source_suffix = ['.rst', '.md'] 50 | source_suffix = '.rst' 51 | 52 | # The master toctree document. 53 | master_doc = 'index' 54 | 55 | # General information about the project. 56 | project = 'metrolopy' 57 | copyright = '2020, National Research Council Canada' 58 | author = 'Harold Parks' 59 | 60 | __version__ = None 61 | with open('../metrolopy/version.py') as f: 62 | exec(f.read()) 63 | # The version info for the project you're documenting, acts as replacement for 64 | # |version| and |release|, also used in various other places throughout the 65 | # built documents. 66 | # 67 | # The short X.Y version. 68 | version = __version__ 69 | # The full version, including alpha/beta/rc tags. 70 | release = __version__ 71 | 72 | # The language for content autogenerated by Sphinx. Refer to documentation 73 | # for a list of supported languages. 74 | # 75 | # This is also used if you do content translation via gettext catalogs. 76 | # Usually you set "language" from the command line for these cases. 77 | language = None 78 | 79 | # List of patterns, relative to source directory, that match files and 80 | # directories to ignore when looking for source files. 81 | # This patterns also effect to html_static_path and html_extra_path 82 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 83 | 84 | # The name of the Pygments (syntax highlighting) style to use. 85 | pygments_style = 'sphinx' 86 | 87 | # If true, `todo` and `todoList` produce output, else they produce nothing. 88 | todo_include_todos = False 89 | 90 | 91 | # -- Options for HTML output ---------------------------------------------- 92 | 93 | # The theme to use for HTML and HTML Help pages. See the documentation for 94 | # a list of builtin themes. 95 | # 96 | html_theme = 'nature' 97 | 98 | # Theme options are theme-specific and customize the look and feel of a theme 99 | # further. For a list of options available for each theme, see the 100 | # documentation. 101 | # 102 | # html_theme_options = {} 103 | 104 | # Add any paths that contain custom static files (such as style sheets) here, 105 | # relative to this directory. They are copied after the builtin static files, 106 | # so a file named "default.css" will overwrite the builtin "default.css". 107 | html_static_path = ['_static'] 108 | 109 | 110 | # -- Options for HTMLHelp output ------------------------------------------ 111 | 112 | # Output file base name for HTML help builder. 113 | htmlhelp_basename = 'metrolopydoc' 114 | 115 | 116 | # -- Options for LaTeX output --------------------------------------------- 117 | 118 | latex_elements = { 119 | # The paper size ('letterpaper' or 'a4paper'). 120 | # 121 | # 'papersize': 'letterpaper', 122 | 123 | # The font size ('10pt', '11pt' or '12pt'). 124 | # 125 | # 'pointsize': '10pt', 126 | 127 | # Additional stuff for the LaTeX preamble. 128 | # 129 | # 'preamble': '', 130 | 131 | # Latex figure (float) alignment 132 | # 133 | # 'figure_align': 'htbp', 134 | } 135 | 136 | # Grouping the document tree into LaTeX files. List of tuples 137 | # (source start file, target name, title, 138 | # author, documentclass [howto, manual, or own class]). 139 | latex_documents = [ 140 | (master_doc, 'metrolopy.tex', 'MetroloPy Documentation', 141 | 'Harold Parks', 'manual'), 142 | ] 143 | 144 | 145 | # -- Options for manual page output --------------------------------------- 146 | 147 | # One entry per manual page. List of tuples 148 | # (source start file, name, description, authors, manual section). 149 | man_pages = [ 150 | (master_doc, 'metrolopy', 'MetroloPy Documentation', 151 | [author], 1) 152 | ] 153 | 154 | 155 | # -- Options for Texinfo output ------------------------------------------- 156 | 157 | # Grouping the document tree into Texinfo files. List of tuples 158 | # (source start file, target name, title, author, 159 | # dir menu entry, description, category) 160 | texinfo_documents = [ 161 | (master_doc, 'metrolopy', 'MetroloPy Documentation', 162 | author, 'metrolopy', 'One line description of project.', 163 | 'Miscellaneous'), 164 | ] 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. metrolopy documentation master file, created by 2 | sphinx-quickstart on Fri Feb 22 16:15:02 2019. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | :caption: Contents: 9 | 10 | =================== 11 | MetroloPy, the docs 12 | =================== 13 | 14 | tools for dealing with physical quantities: uncertainty propagation and unit 15 | conversion 16 | 17 | 18 | getting started 19 | =============== 20 | 21 | MetroloPy is a pure python package and requires Python 3 and the 22 | `SciPy `_ stack (NumPy, SciPy, Pandas, and IPython). 23 | It looks best in a `Jupyter notebook `_. 24 | 25 | Install MetroloPy with ``pip install metrolopy`` or 26 | ``conda install -c conda-forge metrolopy``. 27 | 28 | Physical quantities can then be represented in Python as `gummy`_ objects 29 | with an uncertainty and (or) a unit: 30 | 31 | .. _gummy: hand_made_doc.html#class-gummy 32 | 33 | .. raw:: html 34 | 35 |
>>> import metrolopy as uc
 36 |     >>> a = uc.gummy(1.2345,u=0.0234,unit='cm')
 37 |     >>> a
 38 |     1.234(23) cm
 39 |     
 40 |     >>> b = uc.gummy(3.034,u=0.174,unit='mm')
 41 |     >>> f = uc.gummy(uc.UniformDist(center=0.9345,half_width=0.096),unit='N')
 42 |     >>> p = f/(a*b)
 43 |     >>> p
 44 |     2.50(21) N/cm2
 45 |     
 46 |     >>> p.unit = 'kPa'
 47 |     >>> p.uunit = '%'
 48 |     >>> p
 49 |     25.0 kPa ± 8.5%
 50 |     
51 |
52 | 53 | MetroloPy can do much more including `Monte-Carlo uncertainty propagation`_, 54 | generating `uncertainty budget tables`_, and `curve fitting`_. It can also handle 55 | `expanded uncertainties`_, `degrees of freedom`_, `correlated quantities`_, and 56 | `complex valued quantities`_. 57 | 58 | .. _Monte-Carlo uncertainty propagation: _static/tutorial.html#Monte-Carlo-uncertainty-propagation 59 | 60 | .. _uncertainty budget tables: _static/tutorial.html#an-uncertainty-budget 61 | 62 | .. _curve fitting: _static/tutorial.html#curve-fitting 63 | 64 | .. _expanded uncertainties: _static/tutorial.html#expanded-uncertainty 65 | 66 | .. _degrees of freedom: _static/tutorial.html#degrees-of-freedom-and-uncertainty-types 67 | 68 | .. _correlated quantities: _static/tutorial.html#creating-correlated-gummys 69 | 70 | .. _complex valued quantities: hand_made_doc.html#jummy 71 | 72 | further reading 73 | =============== 74 | 75 | * `a tutorial <_static/tutorial.html>`_ (or :download:`download the tutorial as a Jupyter notebook `) 76 | * :ref:`the API documentation ` (see the auto-generated docs below for an alternative set of documentation) 77 | * `a list of the measurement units built into MetroloPy <_static/units.html>`_ 78 | * `a list of the physical constants built into MetroloPy `_ 79 | * :ref:`package development and to do ` 80 | * `the issues page on GitHub `_ 81 | * `the source code on GitHub `_ 82 | 83 | 84 | the auto-generated docs (indices and tables) 85 | ============================================ 86 | 87 | These pages were automatically generated from the doc strings in the source 88 | code. They are slightly more comprehensive but perhaps slightly more confusing 89 | than the handmade API docs referenced in the further reading section above. 90 | 91 | * :ref:`genindex` 92 | * :ref:`modindex` 93 | * :ref:`search` 94 | 95 | 96 | Where did the name for the gummy class come from? 97 | ================================================= 98 | 99 | The name comes from the 100 | `JGCM/ISO Guide to the Expression of Uncertainty in Measurement `_ 101 | which is also known as the GUM. The GUM is the international standard used by 102 | metrology institutes and calibration labs for expressing and propagating 103 | measurement uncertainty. The gummy object implements many of the 104 | recommendations outlined in the GUM. 105 | 106 | Other references of note are the 107 | `draft 9th edition of the SI Brochure `_ 108 | which contains the definitions of the SI units, and 109 | `NIST Special Publication 1038 `_ 110 | where many of the US customary units are defined. Some physical constants 111 | used for unit definitions are from the 112 | `2014 CODATA recommended values `_ 113 | and the 114 | `IAU 2009 system of astronomical constants `_. 115 | 116 | 117 | version history 118 | =============== 119 | 120 | * Version 0.5.0, built 26 March 2019, is the first public release. 121 | * Version 0.5.1, built 2 April 2019, fixed a major bug that generated negative 122 | uncertainties in some cases and fixed some other minor bugs. Improved support 123 | for fraction.Fraction and mpmath.mpf values. 124 | * Version 0.5.2, built 5 April 2019, fixed a major bug that propagated 125 | uncertainty incorrectly if a gummy was created with an uncertainty set with 126 | an integer data type. Fixed several other minor bugs. 127 | * Version 0.5.3, built 10 April 2019, minor bug fixes. 128 | * Version 0.5.4, built 15 April 2019, minor bug fixes. 129 | * Version 0.5.5, built 7 May 2020, minor bug fixes. 130 | * Version 0.5.6, built 24 September 2020, minor bug fixes. 131 | * Version 0.5.7, built 26 September 2020, minor change to setup.py. 132 | * Verison 0.6.0, built 19 October 2020, added the `Quantity` and `immy` classes 133 | as well as a library of physical constants. 134 | * Version 0.6.1 built 19 October 2020, bug fixes 135 | * Version 0.6.2 built 10 July 2021, bug fixes 136 | * Version 0.6.3 built 13 May 2022, bug fixes 137 | * Version 0.6.4 built 28 May 2025, bug fixes 138 | * Version 0.6.5 built 04 June 2025, bug fixe 139 | 140 | 141 | author 142 | ====== 143 | 144 | Harold Parks, parksh@nrc.ca, National Research Council Canada 145 | 146 | 147 | license 148 | ======= 149 | 150 | MetroloPy is distributed as free software under the terms of the 151 | `GNU General Public License version 3 `_. 152 | In practice, this license imposes 153 | no restriction on using MetroloPy. However, if you want to further convey 154 | verbatim or modified versions of the code you must do so under the same license 155 | terms. Please contact NRC if you wish to license MetroloPy under different 156 | terms. 157 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=metrolopy 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/metrolopy.rst: -------------------------------------------------------------------------------- 1 | metrolopy package 2 | ================= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | 9 | metrolopy.tests 10 | 11 | Submodules 12 | ---------- 13 | 14 | metrolopy.budget module 15 | ----------------------- 16 | 17 | .. automodule:: metrolopy.budget 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | 22 | metrolopy.dfunc module 23 | ---------------------- 24 | 25 | .. automodule:: metrolopy.dfunc 26 | :members: 27 | :undoc-members: 28 | :show-inheritance: 29 | 30 | metrolopy.distributions module 31 | ------------------------------ 32 | 33 | .. automodule:: metrolopy.distributions 34 | :members: 35 | :undoc-members: 36 | :show-inheritance: 37 | 38 | metrolopy.exceptions module 39 | --------------------------- 40 | 41 | .. automodule:: metrolopy.exceptions 42 | :members: 43 | :undoc-members: 44 | :show-inheritance: 45 | 46 | metrolopy.fit module 47 | -------------------- 48 | 49 | .. automodule:: metrolopy.fit 50 | :members: 51 | :undoc-members: 52 | :show-inheritance: 53 | 54 | metrolopy.functions module 55 | -------------------------- 56 | 57 | .. automodule:: metrolopy.functions 58 | :members: 59 | :undoc-members: 60 | :show-inheritance: 61 | 62 | metrolopy.gummy module 63 | ---------------------- 64 | 65 | .. automodule:: metrolopy.gummy 66 | :members: 67 | :undoc-members: 68 | :show-inheritance: 69 | 70 | metrolopy.logunit module 71 | ------------------------ 72 | 73 | .. automodule:: metrolopy.logunit 74 | :members: 75 | :undoc-members: 76 | :show-inheritance: 77 | 78 | metrolopy.mean module 79 | --------------------- 80 | 81 | .. automodule:: metrolopy.mean 82 | :members: 83 | :undoc-members: 84 | :show-inheritance: 85 | 86 | metrolopy.nonlinearunit module 87 | ------------------------------ 88 | 89 | .. automodule:: metrolopy.nonlinearunit 90 | :members: 91 | :undoc-members: 92 | :show-inheritance: 93 | 94 | metrolopy.nummy module 95 | ---------------------- 96 | 97 | .. automodule:: metrolopy.nummy 98 | :members: 99 | :undoc-members: 100 | :show-inheritance: 101 | 102 | metrolopy.offsetunit module 103 | --------------------------- 104 | 105 | .. automodule:: metrolopy.offsetunit 106 | :members: 107 | :undoc-members: 108 | :show-inheritance: 109 | 110 | metrolopy.pmethod module 111 | ------------------------ 112 | 113 | .. automodule:: metrolopy.pmethod 114 | :members: 115 | :undoc-members: 116 | :show-inheritance: 117 | 118 | metrolopy.prefixedunit module 119 | ----------------------------- 120 | 121 | .. automodule:: metrolopy.prefixedunit 122 | :members: 123 | :undoc-members: 124 | :show-inheritance: 125 | 126 | metrolopy.printing module 127 | ------------------------- 128 | 129 | .. automodule:: metrolopy.printing 130 | :members: 131 | :undoc-members: 132 | :show-inheritance: 133 | 134 | metrolopy.relunits module 135 | ------------------------- 136 | 137 | .. automodule:: metrolopy.relunits 138 | :members: 139 | :undoc-members: 140 | :show-inheritance: 141 | 142 | metrolopy.siunits module 143 | ------------------------ 144 | 145 | .. automodule:: metrolopy.siunits 146 | :members: 147 | :undoc-members: 148 | :show-inheritance: 149 | 150 | metrolopy.ummy module 151 | --------------------- 152 | 153 | .. automodule:: metrolopy.ummy 154 | :members: 155 | :undoc-members: 156 | :show-inheritance: 157 | 158 | metrolopy.unit module 159 | --------------------- 160 | 161 | .. automodule:: metrolopy.unit 162 | :members: 163 | :undoc-members: 164 | :show-inheritance: 165 | 166 | metrolopy.unitutils module 167 | -------------------------- 168 | 169 | .. automodule:: metrolopy.unitutils 170 | :members: 171 | :undoc-members: 172 | :show-inheritance: 173 | 174 | metrolopy.usunits module 175 | ------------------------ 176 | 177 | .. automodule:: metrolopy.usunits 178 | :members: 179 | :undoc-members: 180 | :show-inheritance: 181 | 182 | metrolopy.version module 183 | ------------------------ 184 | 185 | .. automodule:: metrolopy.version 186 | :members: 187 | :undoc-members: 188 | :show-inheritance: 189 | 190 | 191 | Module contents 192 | --------------- 193 | 194 | .. automodule:: metrolopy 195 | :members: 196 | :undoc-members: 197 | :show-inheritance: 198 | -------------------------------------------------------------------------------- /docs/metrolopy.tests.rst: -------------------------------------------------------------------------------- 1 | metrolopy.tests package 2 | ======================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | metrolopy.tests.test_create module 8 | ---------------------------------- 9 | 10 | .. automodule:: metrolopy.tests.test_create 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | 16 | Module contents 17 | --------------- 18 | 19 | .. automodule:: metrolopy.tests 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/modules.rst: -------------------------------------------------------------------------------- 1 | metrolopy 2 | ========= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | metrolopy 8 | -------------------------------------------------------------------------------- /docs/todo.rst: -------------------------------------------------------------------------------- 1 | .. toctree:: 2 | :maxdepth: 2 3 | :caption: Contents: 4 | 5 | .. _todo: 6 | 7 | Lots of help is needed to find bugs. 8 | 9 | to do 10 | ===== 11 | 12 | start by putting something here 13 | -------------------------------------------------------------------------------- /metrolopy/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module __init__ 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | from .version import __version__ 24 | 25 | from .gummy import gummy,jummy 26 | from .unit import Unit,Conversion,one,Quantity,QuantityArray,unit 27 | from .ummy import ummy,immy,MFraction 28 | from .budget import Budget 29 | from .prefixedunit import PrefixedUnit,BinaryPrefixedUnit 30 | from .nonlinearunit import NonlinearUnit,NonlinearConversion 31 | from .offsetunit import OffsetUnit,OffsetConversion 32 | from .logunit import LogUnit,LogConversion 33 | from .functions import * 34 | from .mean import * 35 | from .fit import * 36 | from .distributions import * 37 | from .exceptions import * 38 | from .printing import set_printer 39 | from .unitutils import search_units,shadowed_units,convert 40 | from .constant import (GummyConstant,JummyConstant,constant,search_constants, 41 | shadowed_constants) -------------------------------------------------------------------------------- /metrolopy/constcom.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module constant 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | """ 24 | Constants used by both the siunits and the codata2018 modules. Most constants 25 | are from CODATA 2018 26 | """ 27 | 28 | import numpy as np 29 | from warnings import warn 30 | from .gummy import gummy 31 | from .ummy import ummy,MFraction,_getfinfo,_iinfo 32 | 33 | 34 | def _rounding_u(x): 35 | if not ummy.rounding_u: 36 | try: 37 | fi,_ = _getfinfo(x) 38 | if fi is _iinfo: 39 | raise ValueError() 40 | return ummy(x,x*fi.rel_u) 41 | except: 42 | warn('numpy.finfo cannot get the floating point accuracy for float64 math constants') 43 | return ummy(x) 44 | else: 45 | return ummy(x) 46 | 47 | pi = _rounding_u(np.pi) 48 | euler = _rounding_u(np.e) 49 | sqrt2 = _rounding_u(np.sqrt(2)) 50 | 51 | 52 | # constants from CODATA 2018: 53 | 54 | ( 55 | alph, 56 | aral, 57 | ryd, 58 | are, 59 | mpsme, 60 | ae, 61 | rd, 62 | ghn, 63 | arh, 64 | sigmah, 65 | mmu, 66 | amu, 67 | arn, 68 | gnn, 69 | ard, 70 | gdn, 71 | gp, 72 | sigmapp, 73 | mtu, 74 | gtn 75 | ) = gummy.create([0.0072973525693, 76 | 4.001506179127, 77 | 10973731.56816, 78 | 0.000548579909065, 79 | 1836.15267343, 80 | 0.00115965218128, 81 | 2.12799e-15, 82 | -4.255250615, 83 | 3.014932247175, 84 | 5.996743000000001e-05, 85 | 1.8835316269999999e-28, 86 | 0.00116592089, 87 | 1.00866491595, 88 | -3.82608545, 89 | 2.013553212745, 90 | 0.8574382338, 91 | 5.5856946893, 92 | 2.5689000000000004e-05, 93 | 3.01550071621, 94 | 5.957924931], 95 | u=[1.1e-12, 96 | 6.3e-11, 97 | 2.1e-05, 98 | 1.6e-14, 99 | 1.1e-07, 100 | 1.8e-13, 101 | 7.4e-19, 102 | 5e-08, 103 | 9.7e-11, 104 | 1.0e-10, 105 | 4.2e-36, 106 | 6.3e-10, 107 | 4.9e-10, 108 | 9e-07, 109 | 4e-11, 110 | 2.2e-09, 111 | 1.6e-09, 112 | 1.1e-08, 113 | 1.2e-10, 114 | 1.2e-08], 115 | correlation_matrix=[[ 1, 0.00003, 0.00207,-0.05927, 0.03103, 0.99492, 0.00320,-0.00017, 0.00147, 0.00000,-0.00013, 0.00055, 0.00003,-0.00001, 0.00002, 0.00005, 0.00001,-0.00019, 0.00117, 0.00000], 116 | [ 0.00003, 1,-0.00000,-0.00050, 0.00024, 0.00003,-0.00000,-0.00000, 0.00000, 0.00000, 0.00000,-0.00000, 0.00000,-0.00000, 0.00000, 0.00000, 0.00000,-0.00000, 0.00000, 0.00000], 117 | [ 0.00207,-0.00000, 1, 0.00704,-0.01206, 0.00206, 0.90366, 0.00006,-0.00578, 0.00000, 0.00017, 0.00001, 0.00044, 0.00000,-0.00093,-0.00002,-0.00000, 0.00007,-0.00463,-0.00000], 118 | [-0.05927,-0.00050, 0.00704, 1,-0.48443,-0.05896, 0.00317, 0.00249,-0.00044, 0.00000,-0.00001, 0.00002,-0.00003, 0.00012,-0.00040,-0.00067,-0.00016, 0.00267,-0.00022,-0.00002], 119 | [ 0.03103, 0.00024,-0.01206,-0.48443, 1, 0.03087,-0.01113,-0.00513, 0.47743, 0.00000, 0.00003,-0.00009,-0.03920,-0.00026, 0.00020, 0.00137, 0.00032,-0.00551, 0.38235, 0.00005], 120 | [ 0.99492, 0.00003, 0.00206,-0.05896, 0.03087, 1, 0.00319,-0.00017, 0.00146, 0.00000,-0.00013, 0.00055, 0.00003,-0.00001, 0.00002, 0.00005, 0.00001,-0.00019, 0.00116, 0.00000], 121 | [ 0.00320,-0.00000, 0.90366, 0.00317,-0.01113, 0.00319, 1, 0.00006,-0.00511, 0.00000, 0.00016, 0.00001, 0.00049, 0.00000, 0.00209,-0.00002,-0.00000, 0.00006,-0.00410,-0.00000], 122 | [-0.00017,-0.00000, 0.00006, 0.00249,-0.00513,-0.00017, 0.00006, 1,-0.00245,-0.00854,-0.00000, 0.00000, 0.00020, 0.04291,-0.00000,-0.00001,-0.00000, 0.92869,-0.00196,-0.00000], 123 | [ 0.00147, 0.00000,-0.00578,-0.00044, 0.47743, 0.00146,-0.00511,-0.00245, 1, 0.00000, 0.00001,-0.00005,-0.02445,-0.00012, 0.41560, 0.00066, 0.00015,-0.00263, 0.80098, 0.00002], 124 | [ 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,-0.00854, 0.00000, 1, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000], 125 | [-0.00013, 0.00000, 0.00017,-0.00001, 0.00003,-0.00013, 0.00016,-0.00000, 0.00001, 0.00000, 1, 0.06971,-0.00000,-0.00000,-0.00000,-0.00002,-0.00016,-0.00000, 0.00001,-0.00002], 126 | [ 0.00055,-0.00000, 0.00001, 0.00002,-0.00009, 0.00055, 0.00001, 0.00000,-0.00005, 0.00000, 0.06971, 1, 0.00000, 0.00000,-0.00000, 0.00006, 0.00054, 0.00002,-0.00004, 0.00008], 127 | [ 0.00003, 0.00000, 0.00044,-0.00003,-0.03920, 0.00003, 0.00049, 0.00020,-0.02445, 0.00000,-0.00000, 0.00000, 1, 0.00001,-0.00000,-0.00005,-0.00001, 0.00022,-0.01959,-0.00000], 128 | [-0.00001,-0.00000, 0.00000, 0.00012,-0.00026,-0.00001, 0.00000, 0.04291,-0.00012, 0.00000,-0.00000, 0.00000, 0.00001, 1,-0.00000,-0.00000,-0.00000, 0.04618,-0.00010,-0.00000], 129 | [ 0.00002, 0.00000,-0.00093,-0.00040, 0.00020, 0.00002, 0.00209,-0.00000, 0.41560, 0.00000,-0.00000,-0.00000,-0.00000,-0.00000, 1, 0.00000, 0.00000,-0.00000, 0.33288, 0.00000], 130 | [ 0.00005, 0.00000,-0.00002,-0.00067, 0.00137, 0.00005,-0.00002,-0.00001, 0.00066, 0.00000,-0.00002, 0.00006,-0.00005,-0.00000, 0.00000, 1, 0.10706, 0.00289, 0.00053, 0.01581], 131 | [ 0.00001, 0.00000,-0.00000,-0.00016, 0.00032, 0.00001,-0.00000,-0.00000, 0.00015, 0.00000,-0.00016, 0.00054,-0.00001,-0.00000, 0.00000, 0.10706, 1, 0.02707, 0.00012, 0.14766], 132 | [-0.00019,-0.00000, 0.00007, 0.00267,-0.00551,-0.00019, 0.00006, 0.92869,-0.00263, 0.00000,-0.00000, 0.00002, 0.00022, 0.04618,-0.00000, 0.00289, 0.02707, 1,-0.00211, 0.00400], 133 | [ 0.00117, 0.00000,-0.00463,-0.00022, 0.38235, 0.00116,-0.00410,-0.00196, 0.80098, 0.00000, 0.00001,-0.00004,-0.01959,-0.00010, 0.33288, 0.00053, 0.00012,-0.00211, 1, 0.00002], 134 | [ 0.00000, 0.00000,-0.00000,-0.00002, 0.00005, 0.00000,-0.00000,-0.00000, 0.00002, 0.00000,-0.00002, 0.00008,-0.00000,-0.00000, 0.00000, 0.01581, 0.14766, 0.00400, 0.00002, 1]] 135 | ) 136 | 137 | 138 | c = 299792458 # speed of light in m/s 139 | h = MFraction('6.62607015e-34') # planck constant in J s 140 | 141 | 142 | e = MFraction('1.602176634e-19') # electron charge in C 143 | k = MFraction('1.380649e-23') # Boltzmann constant in J/K 144 | 145 | KJ = 2*e/h 146 | RK = h/e**2 147 | 148 | KJ90 = MFraction('483597.9e9') # Josephson constant Hz/V, 1990 conventional value 149 | RK90 = MFraction('25812.807') # Von Klitzing constant in ohm, 1990 conventional value 150 | 151 | G = ummy(6.67430e-11,0.00015e-11) # gravitational constant in m**3/kg s**2 152 | 153 | dalton = 2*ryd*h/(are*c*alph**2) 154 | me = 2*ryd*h/(c*alph**2) #electron mass in kg 155 | 156 | a0 = alph/(4*pi*ryd) # bohr radius in m 157 | 158 | mp = mpsme*me # in kg 159 | 160 | 161 | # constants from IAU 2009: 162 | earth_mass = ummy(3.986004418e14,8e5)/G # in kg 163 | solar_mass = ummy(1.32712442099e20,1e10)/G # in kg 164 | jupiter_mass = solar_mass/ummy(1.047348644e3,1.7e-5) # in kg 165 | 166 | hbar = h/(2*pi) -------------------------------------------------------------------------------- /metrolopy/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module exceptions 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | class IncompatibleUnitsError(ValueError): 24 | """ 25 | This exception is raised when an operation is attempted with gummys that 26 | have units that are incompatible for that operation. 27 | """ 28 | pass 29 | 30 | class UnitError(Exception): 31 | """ 32 | Base class for Unit exceptions. 33 | """ 34 | pass 35 | 36 | class UnitLibError(UnitError): 37 | """ 38 | This exception is raised when the UnitLibrary cannot parse a unit string. 39 | """ 40 | pass 41 | 42 | class UnitNotFoundError(UnitLibError): 43 | pass 44 | 45 | class CircularUnitConversionError(UnitError): 46 | pass 47 | 48 | class NoUnitConversionFoundError(UnitError): 49 | pass 50 | 51 | class UnitLibNotFoundError(UnitLibError): 52 | pass 53 | 54 | class ConstantNotFoundError(ValueError): 55 | pass 56 | 57 | class NoSimulatedDataError(Exception): 58 | pass 59 | 60 | class UnitWarning(Warning): 61 | pass 62 | 63 | class GummyWarning(Warning): 64 | pass 65 | 66 | class FitWarning(Warning): 67 | pass 68 | 69 | class BudgetWarning(Warning): 70 | pass 71 | 72 | class UncertiantyPrecisionWarning(Warning): 73 | pass -------------------------------------------------------------------------------- /metrolopy/functions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module functions 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | """ 24 | A number of mathematical functions are defined here that can be used with 25 | gummys. 26 | """ 27 | 28 | import numpy as np 29 | from .gummy import gummy,jummy 30 | from .ummy import ummy 31 | from numbers import Complex 32 | from .dfunc import _call 33 | 34 | def _callg(f,*args): 35 | # decide whether to call jummy.apply, gummy.apply or ummy.apply 36 | g = None 37 | u = None 38 | c = False 39 | for a in args: 40 | if isinstance(a,jummy): 41 | return a.__array_ufunc__(f,'__call__',*args) 42 | if isinstance(a,gummy): 43 | g = a 44 | if isinstance(a,ummy): 45 | u = a 46 | if isinstance(a,Complex): 47 | c = True 48 | if g is not None: 49 | if c: 50 | return jummy(g).__array_ufunc__(f,'__call__',*args) 51 | return g.__array_ufunc__(f,'__call__',*args) 52 | if u is not None: 53 | return u.__array_ufunc__(f,'__call__',*args) 54 | return _call(f,*args) 55 | 56 | def _bcallg(f,*args): 57 | # broadcast f across any arrays in args. 58 | bargs = np.broadcast(*args) 59 | if bargs.shape == (): 60 | return _callg(f,*args) 61 | ret = np.array([_callg(f,*a) for a in bargs]) 62 | ret = ret.reshape(bargs.shape) 63 | return ret 64 | 65 | 66 | def sin(x): 67 | """ 68 | Returns the sine of x where x can be float, complex, gummy or jummy. 69 | """ 70 | return _bcallg(np.sin,x) 71 | 72 | def cos(x): 73 | """ 74 | Returns the cosine of x where x can be float, complex, gummy or jummy. 75 | """ 76 | return _bcallg(np.cos,x) 77 | 78 | def tan(x): 79 | """ 80 | Returns the tangent of x where x can be float, complex, gummy or jummy. 81 | """ 82 | return _bcallg(np.tan,x) 83 | 84 | def arcsin(x): 85 | """ 86 | Returns the inverse sine of x where x can be float, complex, gummy or jummy. 87 | """ 88 | return _bcallg(np.arcsin,x) 89 | 90 | def arccos(x): 91 | """ 92 | Returns the inverse cosine of x where x can be float, complex, gummy or jummy. 93 | """ 94 | return _bcallg(np.arccos,x) 95 | 96 | def arctan(x): 97 | """ 98 | Returns the inverse tangent of x where x can be float, complex, gummy or jummy. 99 | """ 100 | return _bcallg(np.arctan,x) 101 | 102 | def arctan2(x1,x2): 103 | """ 104 | Returns the inverse tangent of x1/x2 choosing the quadrant correctly where 105 | x1 and x2 can be float, complex, gummy or jummy. 106 | """ 107 | return _bcallg(np.arctan2,x1,x2) 108 | 109 | def sinh(x): 110 | """ 111 | Returns the hyperbolic sine of x where x can be float, complex, gummy or jummy. 112 | """ 113 | return _bcallg(np.sinh,x) 114 | 115 | def cosh(x): 116 | """ 117 | Returns the hyperbolic cosine of x where x can be float, complex, gummy or jummy. 118 | """ 119 | return _bcallg(np.cosh,x) 120 | 121 | def tanh(x): 122 | """ 123 | Returns the hyperbolic tangent of x where x can be float, complex, gummy or jummy. 124 | """ 125 | return _bcallg(np.tanh,x) 126 | 127 | def arcsinh(x): 128 | """ 129 | Returns the inverse hyperbolic sine of x where x can be float, complex, gummy 130 | or jummy. 131 | """ 132 | return _bcallg(np.arcsinh,x) 133 | 134 | def arccosh(x): 135 | """ 136 | Returns the inverse hyperbolic cosine of x where x can be float, complex, gummy 137 | or jummy. 138 | """ 139 | return _bcallg(np.arccosh,x) 140 | 141 | def arctanh(x): 142 | """ 143 | Returns the inverse hyperbolic tangent of x where x can be float, complex, 144 | gummy or jummy. 145 | """ 146 | return _bcallg(np.arctanh,x) 147 | 148 | def exp(x): 149 | """ 150 | Returns e to the power of x where x can be float, complex, gummy or jummy. 151 | """ 152 | return _bcallg(np.exp,x) 153 | 154 | def exp2(x): 155 | """ 156 | Returns 2 to the power of x where x can be float, complex, gummy or jummy. 157 | """ 158 | return _bcallg(np.exp2,x) 159 | 160 | def expm1(x): 161 | """ 162 | Returns exp(x) - 1 where x can be float, complex, gummy or jummy. 163 | """ 164 | return _bcallg(np.expm1,x) 165 | 166 | def log(x): 167 | """ 168 | Returns the natural logrithm of x where x can be float, complex, gummy or jummy. 169 | """ 170 | return _bcallg(np.log,x) 171 | 172 | def log2(x): 173 | """ 174 | Returns the log base 2 of x where x can be float, complex, gummy or jummy. 175 | """ 176 | return _bcallg(np.log2,x) 177 | 178 | def log10(x): 179 | """ 180 | Returns the log base 10 of x where x can be float, complex, gummy or jummy. 181 | """ 182 | return _bcallg(np.log10,x) 183 | 184 | def log1p(x): 185 | """ 186 | Returns the natural logrithm of x plus 1 where x can be float, complex, gummy 187 | or jummy. 188 | """ 189 | return _bcallg(np.log1p,x) 190 | 191 | def logaddexp(x1,x2): 192 | """ 193 | Returns the log(exp(x1) + exp(x2)) where x1 and x2 can be float, complex, gummy 194 | or jummy and log is the natural logrithm. 195 | """ 196 | return _bcallg(np.logaddexp,x1,x2) 197 | 198 | def logaddexp2(x1,x2): 199 | """ 200 | Returns the log2(2**x1 + 2**x2) where x1 and x2 can be float, complex, gummy 201 | or jummy and log2 is the logrithm to base 2. 202 | """ 203 | return _bcallg(np.logaddexp2,x1,x2) 204 | 205 | def sqrt(x): 206 | """ 207 | Returns the square root of x where x can be float, complex, gummy or jummy. 208 | """ 209 | return _bcallg(np.sqrt,x) 210 | 211 | def cbrt(x): 212 | """ 213 | Returns the cube root of x where x can be float, complex, gummy or jummy. 214 | """ 215 | return _bcallg(np.cbrt,x) 216 | 217 | def square(x): 218 | """ 219 | Returns the square of x where x can be float, complex, gummy or jummy. 220 | """ 221 | return _bcallg(np.square,x) 222 | 223 | def add(x1,x2): 224 | """ 225 | returns x1 + x2 226 | """ 227 | return _bcallg(np.add,x1,x2) 228 | 229 | def subtract(x1,x2): 230 | """ 231 | returns x1 - x2 232 | """ 233 | return _bcallg(np.subtract,x1,x2) 234 | 235 | def negative(x): 236 | """ 237 | returns -x 238 | """ 239 | return _bcallg(np.negative,x) 240 | 241 | def multiply(x1,x2): 242 | """ 243 | returns x1 * x2 244 | """ 245 | return _bcallg(np.multiply,x1,x2) 246 | 247 | def divide(x1,x2): 248 | """ 249 | returns x1 / x2 250 | """ 251 | return _bcallg(np.divide,x1,x2) 252 | 253 | def true_divide(x1,x2): 254 | """returns x1 / x2 255 | """ 256 | return _bcallg(np.true_divide,x1,x2) 257 | 258 | def floor_divide(x1,x2): 259 | """ 260 | returns x1 // x2 261 | """ 262 | return _bcallg(np.floor_divide,x1,x2) 263 | 264 | def reciprocal(x): 265 | """ 266 | returns 1/x 267 | """ 268 | return _bcallg(np.reciprocal,x) 269 | 270 | def power(x1,x2): 271 | """ 272 | returns x1**x2 273 | """ 274 | return _bcallg(np.power,x1,x2) 275 | 276 | def absolute(x): 277 | """ 278 | Returns the absoulte value of x where x can be float, complex, gummy or jummy. 279 | This is equivalent to abs(x). 280 | """ 281 | return _bcallg(np.absolute,x) 282 | 283 | def mod(x1,x2): 284 | """ 285 | returns x1 % x2 286 | """ 287 | return _bcallg(np.mod,x1,x2) 288 | 289 | def remainder(x1,x2): 290 | """ 291 | returns x1 % x2 292 | """ 293 | return _bcallg(np.remainder,x1,x2) 294 | 295 | def divmod(x1,x2): 296 | """ 297 | returns (x1 // x2, x1 % x2) 298 | """ 299 | return _bcallg(np.divmod,x1,x2) 300 | 301 | def modf(x1,x2): 302 | """ 303 | returns (x1 % 1, x1 // 1), a tuple of integer and fractional parts 304 | """ 305 | return _bcallg(np.modf,x1,x2) 306 | 307 | def angle(x): 308 | """ 309 | Returns the complex argument of x, where x can be float, complex, gummy or 310 | jummy and the return value is a float if x is float or complex and gummy 311 | if x is gummy or jummy. 312 | """ 313 | return _bcallg(np.angle,x) 314 | 315 | def real(x): 316 | """ 317 | returns x.real 318 | """ 319 | return _bcallg(np.real,x) 320 | 321 | def imag(x): 322 | """ 323 | returns x.imag 324 | """ 325 | return _bcallg(np.imag,x) 326 | 327 | def conj(x): 328 | """ 329 | returns x.conjugate(), the complex conjugate of x 330 | """ 331 | return _bcallg(np.conj,x) 332 | 333 | def around(x,n=0): 334 | """ 335 | Returns x rounded to n digits where x can be float, complex, gummy or jummy 336 | but n must be int. 337 | """ 338 | return _bcallg(np.around,x,n) 339 | 340 | def rint(x): 341 | """ 342 | Returns x rounded to the nearest integer value where x can be float, complex, 343 | gummy or jummy. 344 | """ 345 | return _bcallg(np.rint,x) 346 | 347 | def fix(x): 348 | """ 349 | Returns x rounded towards zero where x can be float, complex, gummy or jummy. 350 | """ 351 | return _bcallg(np.fix,x) 352 | 353 | def floor(x): 354 | """ 355 | Returns the floor of x where x can be float, complex, gummy or jummy. 356 | """ 357 | return _bcallg(np.floor,x) 358 | 359 | def ceil(x): 360 | """ 361 | Returns the ceiling of x where x can be float, complex, gummy or jummy. 362 | """ 363 | return _bcallg(np.ceil,x) 364 | 365 | def trunc(x): 366 | """ 367 | Returns x rounded towards zero where x can be float, complex, gummy or jummy. 368 | """ 369 | return _bcallg(np.trunc,x) 370 | 371 | def heaviside(x,h0): 372 | """ 373 | Heavyside function of x, h0 is the value at x = 0 374 | """ 375 | return _bcallg(np.heavyside,x,h0) 376 | 377 | def sign(x): 378 | """ 379 | sign of x 380 | """ 381 | return _bcallg(np.sign,x) 382 | 383 | def sum(*args,**kwds): 384 | """ 385 | Alias for numpy.sum 386 | """ 387 | return np.sum(*args,**kwds) 388 | 389 | def prod(*args,**kwds): 390 | """ 391 | Alias for numpy.prod 392 | """ 393 | return np.prod(*args,**kwds) 394 | 395 | def cumsum(*args,**kwds): 396 | """ 397 | Alias for numpy.cumsum 398 | """ 399 | return np.cumsum(*args,**kwds) 400 | 401 | def cumprod(*args,**kwds): 402 | """ 403 | Alias for numpy.cumprod 404 | """ 405 | return np.cumprod(*args,**kwds) 406 | 407 | def diff(*args,**kwds): 408 | """ 409 | Alias for numpy.diff 410 | """ 411 | return np.diff(*args,**kwds) 412 | 413 | def ediff1d(*args,**kwds): 414 | """ 415 | Alias for numpy.ediff1d 416 | """ 417 | return np.ediff1d(*args,**kwds) 418 | 419 | def gradient(*args,**kwds): 420 | """ 421 | Alias for numpy.gradient 422 | """ 423 | return np.gradient(*args,**kwds) 424 | 425 | def cross(*args,**kwds): 426 | """ 427 | Alias for numpy.cross 428 | """ 429 | return np.cross(*args,**kwds) 430 | 431 | 432 | -------------------------------------------------------------------------------- /metrolopy/indexed.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module indexed 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | """ 24 | indexed 25 | """ 26 | 27 | from importlib import import_module 28 | 29 | 30 | class _Builtin: 31 | """ 32 | See the Indexed._builtin() class methos for the use of this class 33 | """ 34 | def __init__(self,_cls): 35 | self._cls = _cls 36 | 37 | def __enter__(self): 38 | self._cls._open_lib = self._cls._builtin_lib 39 | def __exit__(self,type, value, traceback): 40 | self._cls._open_lib = self._cls._lib 41 | 42 | class Indexed: 43 | 44 | # to speed loading of the module, only wait to create instances until they 45 | # are needed. If a instance cannot be found the modules below are loaded in 46 | # reverse order. 47 | #_builtins_to_import = [] 48 | 49 | # define these in a subclass at the class level: 50 | # _builtin_lib = {} 51 | # _lib = {} 52 | # _open_lib = _builtin_lib 53 | 54 | @classmethod 55 | def alias(cls,alias,inst): 56 | """ 57 | Creates an alias that can be used to reference an instance. 58 | 59 | Parameters 60 | ---------- 61 | alias: `str` 62 | a string containing the new alias 63 | 64 | inst: `str` or `Indexed` instance 65 | A string referencing the `Indexed` instance that will be assigned 66 | the alias or the `Indexed` instance its self. 67 | """ 68 | inst = cls.get(inst) 69 | cls._open_lib[alias] = inst 70 | inst._add_alias(alias) 71 | 72 | @staticmethod 73 | def load(library_name): 74 | import_module(library_name) 75 | 76 | @classmethod 77 | def get(cls,name,exception=True): 78 | if isinstance(name,cls): 79 | return name 80 | c = cls._lib.get(name) 81 | if c is None: 82 | c = cls._builtin_lib.get(name) 83 | if c is None: 84 | while len(cls._builtins_to_import) > 0: 85 | import_module(cls._builtins_to_import.pop(),cls.__module__) 86 | c = cls._builtin_lib.get(name) 87 | if c is not None: 88 | break 89 | 90 | if c is None and exception: 91 | cls._raise_not_found(name) 92 | return c 93 | 94 | @classmethod 95 | def _raise_not_found(cls,name): 96 | raise ValueError(cls.object_name + ' "' + str(name) + '" was not found') 97 | 98 | @classmethod 99 | def _builtin(cls): 100 | """ 101 | Allows Indexed instances to be added to Indexed._builtin_lib rather 102 | than Indexed._lib using a "with" statement. 103 | 104 | Example 105 | ------- 106 | 107 | >>> with Unit._builtin(): 108 | ... one = Unit('1','',add_symbol=False) 109 | 110 | """ 111 | return _Builtin(cls) 112 | 113 | @staticmethod 114 | def format_latex(text): 115 | return text 116 | 117 | def __init__(self,name,symbol=None,short_name=None,add_symbol=False, 118 | html_symbol=None,latex_symbol=None,ascii_symbol=None, 119 | description=None): 120 | self.name = name 121 | self.description=description 122 | 123 | if symbol is None: 124 | self.symbol = name 125 | else: 126 | self.symbol = symbol 127 | 128 | if html_symbol is None: 129 | self.html_symbol = symbol 130 | else: 131 | self.html_symbol=html_symbol 132 | if latex_symbol is None: 133 | self.latex_symbol = self.format_latex(symbol) 134 | else: 135 | self.latex_symbol = self.format_latex(latex_symbol) 136 | if ascii_symbol is None: 137 | self.ascii_symbol=symbol 138 | else: 139 | self.ascii_symbol=ascii_symbol 140 | 141 | self._aliases = set() 142 | 143 | self._open_lib[name] = self 144 | if add_symbol: 145 | if symbol.strip() != name: 146 | self._open_lib[symbol.strip()] = self 147 | self._aliases.add(symbol.strip()) 148 | if (ascii_symbol is not None and ascii_symbol.strip() != name and 149 | ascii_symbol.strip() != symbol.strip()): 150 | self._open_lib[ascii_symbol.strip()] = self 151 | self._aliases.add(ascii_symbol.strip()) 152 | if short_name is not None: 153 | self._open_lib[short_name] = self 154 | self.short_name = short_name 155 | self._aliases.add(short_name) 156 | else: 157 | if add_symbol: 158 | if ascii_symbol is not None: 159 | self.short_name = ascii_symbol 160 | else: 161 | self.short_name = symbol 162 | else: 163 | self.short_name = name 164 | 165 | @property 166 | def aliases(self): 167 | """read-only 168 | 169 | Returns a set of the unshadowed aliases of the instannce. To add aliases 170 | to the unit use the `Indexed.alias` static method. 171 | """ 172 | return {a for a in self._aliases if (self.get(a,exception=False) is self and a != self.name)} 173 | 174 | @property 175 | def shadowed_aliases(self): 176 | """read-only 177 | 178 | Returns a set of the shadowed aliases of the instance. 179 | """ 180 | sha = {a for a in self._aliases if self.get(a,exception=False) is not self} 181 | if self.get(self.name) is not self: 182 | sha.add(self.name) 183 | return sha 184 | 185 | def _add_alias(self,alias): 186 | self._aliases.add(alias) 187 | 188 | def tostring(self,fmt=None,**kwds): 189 | """ 190 | Returns a string containing the symbol for the instance in the format 191 | given by the keyword `fmt` which may be set to a string the values 192 | 'html', 'latex', 'ascii' or 'unicode'. 193 | """ 194 | if fmt is None or fmt == 'unicode': 195 | return self.symbol 196 | if fmt is None: 197 | return self.symbol 198 | if fmt == 'html': 199 | return self.html_symbol 200 | if fmt == 'latex': 201 | return self.latex_symbol 202 | if fmt == 'ascii': 203 | return self.ascii_symbol 204 | raise ValueError('format ' + str(fmt) + ' is not recognized') 205 | 206 | -------------------------------------------------------------------------------- /metrolopy/logunit.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module logunit 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | """ 24 | Unit and Conversion sub-classes are defined here to implement logarithmic 25 | units. 26 | """ 27 | 28 | import numpy as np 29 | from .unit import one,_CompositeUnit,Quantity 30 | from .ummy import ummy 31 | from .nonlinearunit import NonlinearConversion,NonlinearUnit 32 | from .exceptions import IncompatibleUnitsError 33 | 34 | class LogConversion(NonlinearConversion): 35 | def __init__(self,reference,multiplier,log_base,log_func,offset=0): 36 | if isinstance(reference,Quantity): 37 | self._unit = reference.unit 38 | self._rf = reference.value 39 | if self._unit.is_dimensionless: 40 | self._dim = False 41 | else: 42 | self._dim = True 43 | else: 44 | self._unit = one 45 | self._rf = reference 46 | self._dim = False 47 | 48 | self.reference = reference 49 | 50 | self.multiplier = multiplier 51 | self.log_base = log_base 52 | self._log_func = log_func 53 | self._lnbase = np.log(log_base) 54 | self.offset = offset 55 | 56 | def log_func(self,x): 57 | if isinstance(x,Quantity): 58 | x = x.value 59 | if isinstance(x,ummy): 60 | x = x.x 61 | if x <= 0: 62 | return type(x)(-float('inf')) 63 | 64 | return self._log_func(x) 65 | 66 | def to(self,g): 67 | g = (g - self.offset)/self.multiplier 68 | def f(x): 69 | if x == -float('inf'): 70 | return 0.0 71 | try: 72 | return self.log_base**x 73 | except OverflowError: 74 | return float('inf') 75 | return self._rf*f(g) 76 | 77 | def frm(self,g): 78 | return self.multiplier*self.log_func(g/self._rf) + self.offset 79 | 80 | def copy(self): 81 | r = LogConversion(self.reference,self.multiplier,self.log_base,self.log_func) 82 | r.parent = self.parent 83 | return r 84 | 85 | 86 | class LogUnit(NonlinearUnit): 87 | 88 | _ufunc_dict = {} 89 | 90 | def __init__(self,*p,**kwds): 91 | super().__init__(*p,**kwds) 92 | self.reference = self.conversion.reference 93 | self.multiplier = self.conversion.multiplier 94 | self.log_base = self.conversion.log_base 95 | 96 | def get_composite(self,ul): 97 | n = 0 98 | for u,e in ul: 99 | if not u.linear: 100 | n += 1 101 | if n > 1: 102 | raise IncompatibleUnitsError('unit ' + self.tostring() + ' may not be combined with other nonlinear units') 103 | 104 | return _LogCompositeUnit 105 | 106 | def zero(self): 107 | return -float('inf') 108 | 109 | def _add(self,a,bunit,b,aconv): 110 | if self.conversion._dim: 111 | raise IncompatibleUnitsError('operation not allowed with unit ' + self.tostring()) 112 | if bunit is not self: 113 | raise IncompatibleUnitsError('a quantity with unit ' + self.tostring() + ' may not be added to a quantity with unit ' + bunit.tostring() + '; automatic conversion is disabled with LogUnit instances') 114 | return (a + b,self) 115 | 116 | def _radd(self,a,bunit,b,aconv): 117 | if self.conversion._dim: 118 | raise IncompatibleUnitsError('operation not allowed with unit ' + self.tostring()) 119 | 120 | if bunit is not self: 121 | raise IncompatibleUnitsError('a quantity with unit ' + self.tostring() + ' may not be added to a quantity with unit ' + bunit.tostring() + '; automatic conversion is disabled with LogUnit instances') 122 | return (b + a,self) 123 | 124 | def _sub(self,a,bunit,b,aconv): 125 | if self.conversion._dim: 126 | raise IncompatibleUnitsError('operation not allowed with unit ' + self.tostring()) 127 | 128 | if bunit is not self: 129 | raise IncompatibleUnitsError('a quantity with unit ' + bunit.tostring() + ' may not be subtracted from a quantity with unit ' + self.tostring() + '; automatic conversion is disabled with LogUnit instances') 130 | return (a - b,self) 131 | 132 | def _rsub(self,a,bunit,b,aconv): 133 | if self.conversion._dim: 134 | raise IncompatibleUnitsError('operation not allowed with unit ' + self.tostring()) 135 | 136 | if bunit is not self: 137 | raise IncompatibleUnitsError('a quantity with unit ' + self.tostring() + ' may not be subtracted from a quantity with unit ' + bunit.tostring() + '; automatic conversion is disabled with LogUnit instances') 138 | return (a + b,self) 139 | 140 | def _mul(self,a,bunit,b,aconv): 141 | if self.conversion._dim: 142 | raise IncompatibleUnitsError('operation not allowed with unit ' + self.tostring()) 143 | 144 | if not bunit.linear: 145 | raise IncompatibleUnitsError('only quantities with linear units may multiply or divide a quanity with unit ' + self.tostring()) 146 | 147 | if aconv: 148 | un,c = self._mul_cancel(bunit) 149 | else: 150 | un,c = bunit._mul_cancel(self) 151 | 152 | return ((a*b)*c,un) 153 | 154 | def _rmul(self,a,bunit,b,aconv): 155 | if self.conversion._dim: 156 | raise IncompatibleUnitsError('operation not allowed with unit ' + self.tostring()) 157 | 158 | if not bunit.linear: 159 | raise IncompatibleUnitsError('only quantities with linear units may multiply or divide a quanity with unit ' + self.tostring()) 160 | 161 | if aconv: 162 | un,c = self._mul_cancel(bunit) 163 | else: 164 | un,c = bunit._mul_cancel(self) 165 | 166 | return ((b*a)*c,un) 167 | 168 | def _truediv(self,a,bunit,b,aconv): 169 | if self.conversion._dim: 170 | raise IncompatibleUnitsError('operation not allowed with unit ' + self.tostring()) 171 | 172 | if not bunit.linear: 173 | raise IncompatibleUnitsError('only quantities with linear units may multiply or divide a quanity with unit ' + self.tostring()) 174 | 175 | if aconv: 176 | un,c = self._div_cancel(bunit) 177 | else: 178 | un,c = bunit._rdiv_cancel(self) 179 | 180 | return ((a/b)*c,un) 181 | 182 | def _neg(self,a): 183 | return (-a,self) 184 | 185 | def _pos(self,a): 186 | return (+a,self) 187 | 188 | def _abs(self,a): 189 | return (abs(a),self) 190 | 191 | def __mul__(self,a): 192 | if not a.linear: 193 | raise IncompatibleUnitsError('only linear units may multiply or divide unit ' + self.tostring()) 194 | return _CompositeUnit(self.units + a.units) 195 | 196 | def __truediv__(self,a): 197 | if not a.linear: 198 | raise IncompatibleUnitsError('only linear units may multiply or divide unit ' + self.tostring()) 199 | vi = [(e[0],-e[1]) for e in a.units] 200 | return _CompositeUnit(self.units + vi) 201 | 202 | 203 | class _LogCompositeUnit(LogUnit,_CompositeUnit): 204 | pass -------------------------------------------------------------------------------- /metrolopy/nonlinearunit.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module nonlinearunit 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # Copyright (C) 2019 National Research Council Canada 9 | # Author: Harold Parks 10 | 11 | # This file is part of MetroloPy. 12 | 13 | # MetroloPy is free software: you can redistribute it and/or modify it under 14 | # the terms of the GNU General Public License as published by the Free Software 15 | # Foundation, either version 3 of the License, or (at your option) any later 16 | # version. 17 | 18 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 19 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 20 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 21 | # details. 22 | 23 | # You should have received a copy of the GNU General Public License along with 24 | # MetroloPy. If not, see . 25 | 26 | """ 27 | This module defines the Nonlinear Unit and Nonlinear Conversion abstract 28 | classes that are the base class for the LogUnit and OffsetUnit classes. 29 | """ 30 | 31 | from .unit import Unit, Conversion 32 | from .exceptions import IncompatibleUnitsError 33 | 34 | class NonlinearConversion(Conversion): 35 | """ 36 | Base class for non-linear conversions. 37 | """ 38 | # self._unit must be set in __init__ and must be linear 39 | 40 | # self._parent is the owning unit and must be set in the owning unit's __init__ 41 | 42 | linear = False 43 | 44 | def chain(self,c): 45 | return _ChainedConversion(self,c) 46 | 47 | def rchain(self,c): 48 | return _ChainedConversion(c,self) 49 | 50 | def copy(self): 51 | raise NotImplementedError('this is an "abstract" method and must be overriden in a subclass') 52 | 53 | def pow(self,e): 54 | if e != 1: 55 | raise ValueError() 56 | return self 57 | 58 | 59 | class _ChainedConversion(NonlinearConversion): 60 | linear = False 61 | 62 | def __init__(self,c1,c2): 63 | self.parent = c1.parent 64 | self._unit = c2.unit 65 | 66 | if isinstance(c1,_ChainedConversion): 67 | frmlst = c1._frmlst 68 | tolst = c1._tolst 69 | elif not c1.linear: 70 | frmlst = [c1.frm] 71 | tolst = [c1.to] 72 | else: 73 | frmlst = [] 74 | tolst = [] 75 | 76 | if isinstance(c2,_ChainedConversion): 77 | frmlst = c2._frmlst + frmlst 78 | tolst += c2._tolst 79 | elif not c2.linear: 80 | frmlst = [c1.frm] + frmlst 81 | tolst += [c1.to] 82 | 83 | self._frmlst = frmlst 84 | self._tolst = tolst 85 | 86 | factor = 1 87 | if c1.linear or isinstance(c1,_ChainedConversion): 88 | factor *= c1.factor 89 | if c2.linear or isinstance(c2,_ChainedConversion): 90 | factor *= c2.factor 91 | self.factor = factor 92 | 93 | self._c1 = c1 94 | self._c2 = c2 95 | 96 | def to(self,g): 97 | g = self._to(g) 98 | return g*self.factor 99 | 100 | def frm(self,g): 101 | g = g/self.factor 102 | return self._frm(g) 103 | 104 | def _to(self,g): 105 | for f in self._tolst: 106 | g = f(g) 107 | return g 108 | 109 | def _frm(self,g): 110 | for f in self._frmlst: 111 | g = f(g) 112 | return g 113 | 114 | def chain(self,c): 115 | return _ChainedConversion(self,c) 116 | 117 | def copy(self): 118 | return _ChainedConversion(self._c1,self._c2) 119 | 120 | 121 | class NonlinearUnit(Unit): 122 | """Base class of non-linear units. 123 | """ 124 | _linear = False 125 | 126 | #def _getme(self,unit_list,power): 127 | # add this method to return a different instance depending on whether 128 | # the unit is in a composite unit or not. e.g. an OffsetUnit where 129 | # 'degC/m' actually means 'degC-i/m'. 130 | # This us called only from Unit.unit when returning a composite unit 131 | # from a parsed string. unit_list is the raw unit list returned from 132 | # the parser an power is the exponent for this unit. 133 | 134 | #def _format_xu(g,fmt,style,norm,nsig,solidus=solidus,mulsep=mulsep): 135 | # add this method to override the gummy display formatting 136 | # g is a gummy and fmt is a gummy format 137 | # return a tuple: ('override','put the string to be displayed here') 138 | 139 | def zero(self): 140 | raise NotImplementedError('this is an "abstract" method and must be overriden in a subclass') 141 | 142 | def get_composite(self,ul): 143 | # If this method raises a NotImplementedError then the unit cannot be 144 | # combined with other units. Override this method to return a subclass 145 | # of _CompositeUnit to allow combinations. 146 | raise NotImplementedError() 147 | 148 | def from_uunit(self,u,unit): 149 | raise IncompatibleUnitsError('uunit may not be used with unit ' + self.tostring()) 150 | 151 | def to_uunit(self,u,unit): 152 | raise IncompatibleUnitsError('uunit may not be used with unit ' + self.tostring()) 153 | 154 | # override any of the methods below to allow the operations 155 | def _add(self,a,bunit,b,aconv): 156 | raise IncompatibleUnitsError('the + operation is not defined with unit ' + self.tostring()) 157 | 158 | def _radd(self,a,bunit,b,aconv): 159 | raise IncompatibleUnitsError('the + operation is not defined with unit ' + self.tostring()) 160 | 161 | def _sub(self,a,bunit,b,aconv): 162 | raise IncompatibleUnitsError('the - operation is not defined with unit ' + self.tostring()) 163 | 164 | def _rsub(self,a,bunit,b,aconv): 165 | raise IncompatibleUnitsError('the - operation is not defined with unit ' + self.tostring()) 166 | 167 | def _mul(self,a,bunit,b,aconv): 168 | raise IncompatibleUnitsError('the * operation is not defined with unit ' + self.tostring()) 169 | 170 | def _rmul(self,a,bunit,b,aconv): 171 | raise IncompatibleUnitsError('the * operation is not defined with unit ' + self.tostring()) 172 | 173 | def _truediv(self,a,bunit,b,aconv): 174 | raise IncompatibleUnitsError('the / operation is not defined with unit ' + self.tostring()) 175 | 176 | def _rtruediv(self,a,bunit,b,aconv): 177 | raise IncompatibleUnitsError('the / operation is not defined with unit ' + self.tostring()) 178 | 179 | def _pow(self,a,bunit,b,aconv): 180 | raise IncompatibleUnitsError('the ** operation is not defined with unit ' + self.tostring()) 181 | 182 | def _rpow(self,a,bunit,b,aconv): 183 | raise IncompatibleUnitsError('the ** operation is not defined with unit ' + self.tostring()) 184 | 185 | def _mod(self,a,bunit,b,aconv): 186 | raise IncompatibleUnitsError('the mod operation is not defined with unit ' + self.tostring()) 187 | 188 | def _rmod(self,a,bunit,b,aconv): 189 | raise IncompatibleUnitsError('the mod operation is not defined with unit ' + self.tostring()) 190 | 191 | def _neg(self,a): 192 | raise IncompatibleUnitsError('the - operation is not defined with unit ' + self.tostring()) 193 | 194 | def _pos(self,a): 195 | raise IncompatibleUnitsError('the + operation is not defined with unit ' + self.tostring()) 196 | 197 | def _abs(self,a): 198 | raise IncompatibleUnitsError('the abs operation is not defined with unit ' + self.tostring()) 199 | 200 | def __pow__(self,a): 201 | raise IncompatibleUnitsError('the pow operation is not defined with unit ' + self.tostring()) 202 | 203 | def __mul__(self,a): 204 | raise IncompatibleUnitsError('the * operation is not defined with unit ' + self.tostring()) 205 | 206 | def __truediv__(self,a): 207 | raise IncompatibleUnitsError('the / operation is not defined with unit ' + self.tostring()) 208 | 209 | def __rtruediv__(self,a): 210 | raise IncompatibleUnitsError('the reciprocal of unit ' + self.tostring() + ' is not allowed') 211 | 212 | class ReciprocalConversion(NonlinearConversion): 213 | def __init__(self,conversion): 214 | self._conversion = conversion 215 | if hasattr(conversion,'factor'): 216 | self.factor = 1/conversion.factor 217 | self._unit = conversion._unit**-1 218 | self.parent = conversion.parent**-1 219 | 220 | def to(self,g): 221 | return self._conversion.frm(g) 222 | 223 | def frm(self,g): 224 | return self._conversion.to(g) 225 | 226 | def chain(self,c): 227 | return _ChainedConversion(self,c) 228 | 229 | def copy(self): 230 | return ReciprocalConversion(self._conversion) -------------------------------------------------------------------------------- /metrolopy/offsetunit.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module offsetunit 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | """ 24 | The OffsetUnit class was created to handle Celsius and Fahrenheit units. 25 | """ 26 | 27 | from .unit import Unit,Conversion 28 | from .nonlinearunit import NonlinearUnit,NonlinearConversion 29 | from .exceptions import IncompatibleUnitsError 30 | 31 | class OffsetConversion(NonlinearConversion): 32 | """ 33 | Represents a conversion of the form x -> x + offset. 34 | """ 35 | def __init__(self,unit,offset): 36 | self._unit = unit 37 | self.offset = offset 38 | 39 | def to(self,g): 40 | return g + self.offset 41 | 42 | def frm(self,g): 43 | return g - self.offset 44 | 45 | def copy(self): 46 | r = OffsetConversion(self._unit,self.offset) 47 | r.parent = self.parent 48 | return r 49 | 50 | 51 | class _IntervalUnit(Unit): 52 | 53 | def __init__(self,parent,*params,**kwds): 54 | conv = Conversion(parent.conversion.unit,1) 55 | if 'short_name' in kwds: 56 | kwds['short_name'] += '-i' 57 | elif kwds.get('add_symbol'): 58 | if 'ascii_symbol' in kwds: 59 | kwds['short_name'] = kwds['ascii_symbol'] + '-i' 60 | else: 61 | kwds['short_name'] = params[1] + '-i' 62 | kwds['add_symbol'] = False 63 | 64 | kwds['parent'] = parent 65 | Unit.__init__(self,params[0] + ' interval',params[1],conversion=conv,**kwds) 66 | 67 | def _getme(self,ul,e): 68 | return self.parent 69 | 70 | class OffsetUnit(NonlinearUnit): 71 | """ 72 | This class was created to handle units such as the degree Celsius and the 73 | degree Fahrenheit. This class takes the same parameters as the Unit class, 74 | but actually creates two unit instances... 75 | """ 76 | def __init__(self,*params,**kwds): 77 | Unit.__init__(self,*params,**kwds) 78 | 79 | self.interval_unit = _IntervalUnit(self,*params,**kwds) 80 | 81 | def zero(self): 82 | return -self.conversion.offset 83 | 84 | def _add_alias(self,alias): 85 | self._aliases.add(alias) 86 | Unit.alias(alias + '-i',self.interval_unit) 87 | 88 | def _add(self,a,bunit,b,aconv): 89 | if bunit is not self.interval_unit: 90 | raise IncompatibleUnitsError('a quantity with unit ' + self.tostring() + ' may only be added to its interval unit counterpart') 91 | return (a + b,self) 92 | 93 | def _radd(self,a,bunit,b,aconv): 94 | if bunit is not self.interval_unit: 95 | raise IncompatibleUnitsError('a quantity with unit ' + self.tostring() + ' may only be added to its interval unit counterpart') 96 | return (b + a,self) 97 | 98 | def _sub(self,a,bunit,b,aconv): 99 | if bunit is self: 100 | return (a - b,self.interval_unit) 101 | if bunit is self.interval_unit: 102 | return (a - b,self) 103 | raise IncompatibleUnitsError('a quantity with unit ' + bunit.tostring() + ' may not be subtracted from a quantity with unit ' + self.tostring() + '; automatic conversion is disabled with offset unit instances') 104 | 105 | def _rsub(self,a,bunit,b,aconv): 106 | if bunit is self: 107 | return (b - a,self.interval_unit) 108 | raise IncompatibleUnitsError('a quantity with unit ' + self.tostring() + ' may not be subtracted from a quantity with unit ' + bunit.tostring() + '; automatic conversion is disabled with offset unit instances') 109 | 110 | -------------------------------------------------------------------------------- /metrolopy/pmethod.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module pmethod 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | """ 24 | Functions and classes for converting between coverage factor k and level of 25 | confidence p. 26 | """ 27 | 28 | import numpy as np 29 | 30 | def coverage_factor(p,dof=float('inf'),bayesian=False): 31 | """Returns the k factor for a given level of confidence and degrees of freedom 32 | calculated from a normal or Student's t distribution 33 | 34 | Parameters: 35 | 36 | p: `float` 37 | The level of confidence (as a fraction of 1). 38 | 39 | dof: `float` or `int`, 40 | optional (default is float('inf')), the degrees of freedom. 41 | 42 | Returns 43 | ------- 44 | `float` 45 | """ 46 | from scipy.stats import t as students_t 47 | from scipy.stats import norm 48 | 49 | if np.isinf(dof): 50 | ret = norm.ppf(0.5 + p/2) 51 | else: 52 | ret = students_t.ppf(0.5 + p/2, dof) 53 | if bayesian: 54 | ret *= np.sqrt((dof-2)/dof) 55 | 56 | return float(ret) 57 | 58 | def loc_from_k(k,dof=float('inf'),bayesian=False): 59 | """Returns the level of confidence given a coverage factor k and degrees of 60 | freedom for a Student's t distribution. 61 | 62 | Parameters: 63 | k: `float` 64 | coverage factor. 65 | dof: `float` or `int`, optional 66 | (default is float('inf')), the degrees of freedom. 67 | 68 | Returns: float 69 | """ 70 | from scipy.stats import t as students_t 71 | from scipy.stats import norm 72 | 73 | if np.isinf(dof): 74 | return float(1-2*(1-norm.cdf(k))) 75 | 76 | if bayesian: 77 | if dof <= 2: 78 | return 1 79 | k *= np.sqrt(dof/(dof-2)) 80 | return float(1-2*(1-students_t.cdf(k,dof))) 81 | 82 | def coverage_probability(p,dof=float('inf'),bayesian=False): 83 | k = 2/(3*(np.sqrt(1 - p))) 84 | if not bayesian and np.isfinite(dof): 85 | k *= np.sqrt(dof/(dof-2)) 86 | return float(k) 87 | 88 | def cp_from_k(k,dof=float('inf'),bayesian=False): 89 | if not bayesian and np.isfinite(dof): 90 | k *= np.sqrt((dof-2)/dof) 91 | cp = 1 - 4/(9*k**2) 92 | return float(cp) 93 | 94 | def conservative_coverage_probability(p,dof=float('inf'),bayesian=False): 95 | k = 1/np.sqrt(1 - p) 96 | if not bayesian and np.isfinite(dof): 97 | k *= np.sqrt(dof/(dof-2)) 98 | return float(k) 99 | 100 | def ccp_from_k(k,dof=float('inf'),bayesian=False): 101 | if not bayesian and np.isfinite(dof): 102 | k *= np.sqrt((dof-2)/dof) 103 | ccp = 1 - 1/k**2 104 | return float(ccp) 105 | 106 | class _Pmthd: 107 | def __init__(self,text): 108 | text = text.lower().strip() 109 | 110 | if text in {'loc','level of confidence'}: 111 | self.method = 'loc' 112 | self.fptok = coverage_factor 113 | self.fktop = loc_from_k 114 | self.text = 'level of confidence' 115 | return 116 | 117 | if text in {'cp','coverage probability','gauss'}: 118 | self.method = 'cp' 119 | self.fptok = coverage_probability 120 | self.fktop = cp_from_k 121 | self.text = 'coverage probability' 122 | return 123 | 124 | if text in {'ccp','conservative coverage probability','chebyshev'}: 125 | self.method = 'ccp' 126 | self.fptok = conservative_coverage_probability 127 | self.fktop = ccp_from_k 128 | self.text = 'conservative coverage probability' 129 | return -------------------------------------------------------------------------------- /metrolopy/prefixedunit.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module prefixedunit 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | """ 24 | Classes to automatically generate prefixed units from a base unit. 25 | """ 26 | 27 | from .unit import Unit,Conversion 28 | 29 | class PrefixedUnit(Unit): 30 | """PrefixedUnit(name,symbol,conversion=None,short_name=None, 31 | additional_names=None,additional_short_names=None, 32 | add_symbol=False,html_symbol=None,latex_symbol=None, 33 | ascii_symbol=None,description=None,order=-1,prefixes=None, 34 | base_prefix=None,base_description=None) 35 | 36 | Creating an instance of this class not only creates the base unit but also 37 | adds units with with a set of prefixes to the unit library. 38 | 39 | If the `prefixes` keyword is `None` then units with the standard SI prefixes 40 | will be generated. 41 | """ 42 | prefix_definitions = { 43 | 'yocto':[1e-24,'y',None,None,None], 44 | 'zepto':[1e-21,'z',None,None,None], 45 | 'atto':[1e-18,'a',None,None,None], 46 | 'femto':[1e-15,'f',None,None,None], 47 | 'pico':[1e-12,'p',None,None,None], 48 | 'nano':[1e-9,'n',None,None,None], 49 | 'micro':[1e-6,'\u03BC','μ',None,'u'], 50 | 'milli':[0.001,'m',None,None,None], 51 | 'centi':[0.01,'c',None,None,None], 52 | 'deci':[0.1,'d',None,None,None], 53 | 'deca':[10,'da',None,None,None], 54 | 'hecto':[100,'h',None,None,None], 55 | 'kilo':[1000,'k',None,None,None], 56 | 'mega':[1000000,'M',None,None,None], 57 | 'giga':[1e9,'G',None,None,None], 58 | 'tera':[1e12,'T',None,None,None], 59 | 'peta':[1e15,'P',None,None,None], 60 | 'exa':[1e18,'E',None,None,None], 61 | 'zetta':[1e21,'Z',None,None,None], 62 | 'yotta':[1e24,'Y',None,None,None], 63 | } 64 | 65 | @staticmethod 66 | def _add_prefix(pdef,symbol,index): 67 | if pdef is None: 68 | return symbol 69 | 70 | pfx = pdef[index] 71 | if pfx is None: 72 | pfx = pdef[1] 73 | 74 | if symbol.startswith('\t\t'): 75 | return '\t\t' + pfx + symbol[2:] 76 | if symbol.startswith('\t'): 77 | return '\t' + pfx + symbol[2:] 78 | 79 | return pfx + symbol 80 | 81 | def __init__(self,name,symbol,conversion=None,short_name=None, 82 | additional_names=None,additional_short_names=None, 83 | add_symbol=False,html_symbol=None,latex_symbol=None, 84 | ascii_symbol=None,linear=True,description=None,order=-1, 85 | prefixes=None,base_prefix=None,base_description=None,**kwds): 86 | self._linear=linear 87 | if base_description is not None: 88 | self.description=base_description 89 | else: 90 | self.description=description 91 | 92 | if symbol.startswith('\t\t'): 93 | raise ValueError('the symbol may not start with more than one tab character') 94 | if html_symbol is None: 95 | html_symbol = symbol 96 | if latex_symbol is None: 97 | latex_symbol = symbol 98 | if ascii_symbol is None: 99 | ascii_symbol = symbol 100 | 101 | #reset _used_units incase we are shadowing any unit definitions 102 | Unit._used_units = {} 103 | 104 | self._aliases = set() 105 | 106 | if short_name is None: 107 | if add_symbol: 108 | if ascii_symbol is not None: 109 | short_name = ascii_symbol 110 | else: 111 | short_name = symbol 112 | else: 113 | short_name = name 114 | 115 | self.parent = kwds.get('parent') 116 | 117 | if self.parent is None: 118 | if prefixes is None: 119 | self.prefixes = list(type(self).prefix_definitions.keys()) 120 | else: 121 | self.prefixes = list(prefixes) 122 | pfx = base_prefix 123 | if pfx is not None: 124 | pdef = type(self).prefix_definitions[pfx] 125 | self.conversion = conversion 126 | self.order = order 127 | 128 | pfxs = list(self.prefixes) 129 | if base_prefix is not None: 130 | pfxs.append(None) 131 | for p in pfxs: 132 | type(self)(name,symbol, 133 | conversion=conversion, 134 | short_name=short_name, 135 | additional_names=additional_names, 136 | additional_short_names=additional_short_names, 137 | add_symbol=add_symbol, 138 | html_symbol=html_symbol, 139 | latex_symbol=latex_symbol, 140 | ascii_symbol=ascii_symbol, 141 | linear=linear, 142 | description=description, 143 | base_prefix=base_prefix, 144 | order=order, 145 | parent=self, 146 | pfx=p, 147 | **kwds) 148 | else: 149 | pfx = kwds['pfx'] 150 | if pfx is None: 151 | factor = 1/type(self).prefix_definitions[base_prefix][0] 152 | else: 153 | pdef = type(self).prefix_definitions[pfx] 154 | if base_prefix is None: 155 | factor = pdef[0] 156 | else: 157 | factor = pdef[0]/type(self).prefix_definitions[base_prefix][0] 158 | self.conversion = Conversion(self.parent,factor) 159 | self.order = order - 0.01 160 | self.prefixes = self.parent.prefixes 161 | 162 | if pfx is None: 163 | self.name = name 164 | self.short_name = short_name 165 | self.symbol = symbol 166 | pdef = None 167 | else: 168 | self.name = pfx + name 169 | if pdef[4] is None: 170 | self.short_name = pdef[1] + short_name 171 | else: 172 | self.short_name = pdef[4] + short_name 173 | self.symbol = pdef[1] + symbol 174 | 175 | self.html_symbol = PrefixedUnit._add_prefix(pdef,html_symbol,2) 176 | self.latex_symbol = Unit.format_latex(PrefixedUnit._add_prefix(pdef,latex_symbol,3)) 177 | self.ascii_symbol = PrefixedUnit._add_prefix(pdef,ascii_symbol,4) 178 | 179 | Unit._open_lib[self.name] = self 180 | Unit._open_lib[self.short_name] = self 181 | if self.short_name != self.name: 182 | self._aliases.add(self.short_name) 183 | 184 | if add_symbol: 185 | if self.symbol.strip() != self.name: 186 | Unit._open_lib[self.symbol.strip()] = self 187 | self._aliases.add(self.symbol.strip()) 188 | if (self.ascii_symbol is not None and 189 | self.ascii_symbol.strip() != self.name and 190 | self.ascii_symbol != self.symbol): 191 | Unit._open_lib[self.ascii_symbol.strip()] = self 192 | self._aliases.add(self.ascii_symbol.strip()) 193 | if additional_names is not None: 194 | for n in additional_names: 195 | if pfx is None: 196 | nm = n 197 | else: 198 | nm = pfx + n 199 | Unit._open_lib[nm]= self 200 | self._aliases.add(nm) 201 | if additional_short_names is not None: 202 | for n in additional_short_names: 203 | if pfx is None: 204 | nm = n 205 | else: 206 | nm = pdef[1] + n 207 | Unit._open_lib[nm]= self 208 | self._aliases.add(nm) 209 | 210 | class BinaryPrefixedUnit(PrefixedUnit): 211 | """PrefixedUnit(name,symbol,conversion=None,short_name=None, 212 | additional_names=None,additional_short_names=None, 213 | add_symbol=False,html_symbol=None,latex_symbol=None, 214 | ascii_symbol=None,description=None,order=-1,prefixes=None, 215 | base_prefix=None,base_description=None) 216 | 217 | Creating an instance of this class not only creates the base unit but also 218 | adds units with with a set of prefixes to the unit library. 219 | 220 | If the `prefixes` keyword is `None` then units with the following prefixes will 221 | be generated: kibi, mebi, gibi, tebi, pebi, exbi, zibi, yobi, kilo, mega, 222 | giga, tera, peta, exa, zetta and yotta. 223 | """ 224 | prefix_definitions = { 225 | 'kilo':[1000,'k',None,None,None], 226 | 'mega':[1e6,'M',None,None,None], 227 | 'giga':[1e9,'G',None,None,None], 228 | 'tera':[1e12,'T',None,None,None], 229 | 'peta':[1e15,'P',None,None,None], 230 | 'exa':[1e18,'E',None,None,None], 231 | 'zetta':[1e21,'Z',None,None,None], 232 | 'yotta':[1e24,'Y',None,None,None], 233 | 'kibi':[1024,'Ki',None,None,None], 234 | 'mebi':[1024**2,'Mi',None,None,None], 235 | 'gibi':[1024**3,'Gi',None,None,None], 236 | 'tebi':[1024**4,'Ti',None,None,None], 237 | 'pebi':[1024**5,'Pi',None,None,None], 238 | 'exbi':[1024**6,'Ei',None,None,None], 239 | 'zibi':[1024**7,'Zi',None,None,None], 240 | 'yobi':[1024**8,'Yi',None,None,None] 241 | } 242 | -------------------------------------------------------------------------------- /metrolopy/printing.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module printing 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | """ 24 | This module contains code to support pretty printing of gummys using LaTex and 25 | HTML. 26 | """ 27 | 28 | try: 29 | from IPython.display import display,Math,HTML,Markdown 30 | ipython_installed = True 31 | except ImportError: 32 | ipython_installed = False 33 | 34 | 35 | def print_html(text): 36 | if ipython_installed: 37 | display(HTML(text)) 38 | else: 39 | raise NotImplementedError('ipython must be installed to print in HTML format') 40 | 41 | def print_latex(text): 42 | if ipython_installed: 43 | display(Math(text)) 44 | else: 45 | raise NotImplementedError('ipython must be installed to print in HTML format') 46 | 47 | def print_markdown(text): 48 | if ipython_installed: 49 | display(Markdown(text)) 50 | else: 51 | raise NotImplementedError('ipython must be installed to print in Markdown format') 52 | 53 | 54 | 55 | 56 | # Called from _repr_latex_ or Ipyhton.display.Math and gummy.latex_math 57 | # Not sure if this is necessary; may depend on the version of Ipython. 58 | def _latex_math(text): 59 | return '$ ' + text + ' $' 60 | 61 | def _latex_norm(text): 62 | return '\\text{' + text + '}' 63 | 64 | # Same as above for text used in plot titles and labels 65 | def _latex_norm_plot(txt): 66 | txt = txt.replace(' ',' \\ ') 67 | return '\\mathrm{' + txt + '}' 68 | 69 | 70 | def _find_printer(value): 71 | if value is None: 72 | return 'any_but_latex' 73 | value = value.lower().strip() 74 | if value not in ['latex','html','ascii','unicode','any','any_but_latex']: 75 | raise ValueError('printer ' + str(value) + ' is not recognized') 76 | return value 77 | 78 | class MetaPrettyPrinter(type): 79 | @property 80 | def printer(self): 81 | """ 82 | Get or set the prefered display printer. This is a string with one of 83 | the following values: 84 | 85 | "any", "latex", "html", "unicode", "ascii", or "any_but_latex" 86 | 87 | "any" will usually pick html or latex output when running in an IPython 88 | console or Jupyter notebook and unicode otherwise. 89 | 90 | "any_but_latex" will usually pick html when running in an IPython 91 | console or Jupyter notebook and unicode otherwise. 92 | 93 | "latex" and "html" are only available when running under IPython. If 94 | these printers are not available the display will default to "unicode". 95 | """ 96 | return PrettyPrinter._printer 97 | @printer.setter 98 | def printer(self,value): 99 | PrettyPrinter._printer = _find_printer(value) 100 | 101 | class PrettyPrinter(metaclass=MetaPrettyPrinter): 102 | # Base class that can be inherited to provide HTML and LaTeX ouput to an 103 | # ipython console or Jupyter notebook. 104 | 105 | # The inheriting class must define a tostring(self,fmt='unicode',**kwds) 106 | # method that accepts fmt values in ['html',latex','unicode','ascii']. 107 | 108 | break_on_printing_error = False 109 | 110 | # Set latex_math to None in the inherited class if the output of the latex 111 | # and _repr_latex should not be in LaTeX math mode. 112 | latex_math = _latex_math 113 | 114 | latex_norm = _latex_norm 115 | latex_math_plot = _latex_math 116 | latex_norm_plot = _latex_norm_plot 117 | 118 | _printer = 'any_but_latex' 119 | 120 | @property 121 | def printer(self): 122 | """ 123 | Get or set the preferred display printer. This is a string with one of 124 | the following values: 125 | 126 | "any", "latex", "html", "unicode", "ascii", or "any_but_latex" 127 | 128 | "any" will usually pick html or latex output when running in an IPython 129 | console or Jupyter notebook and unicode otherwise. 130 | 131 | "any_but_latex" will usually pick html when running in an IPython 132 | console or Jupyter notebook and unicode otherwise. 133 | 134 | "latex" and "html" are only available when running under IPython. If 135 | these printers are not available the display will default to "unicode". 136 | """ 137 | return self._printer 138 | @printer.setter 139 | def printer(self,value): 140 | self._printer = _find_printer(value) 141 | 142 | def _repr_html_(self): 143 | if self._printer not in ['any','html','any_but_latex']: 144 | return None 145 | 146 | txt = self.tostring(fmt='html') 147 | 148 | return txt 149 | 150 | def _repr_latex_(self): 151 | if self._printer not in ['any','latex']: 152 | return None 153 | 154 | txt = self.tostring(fmt='latex') 155 | 156 | if self.latex_math is None: 157 | return txt 158 | return type(self).latex_math(txt) 159 | 160 | def _repr_markdown_(self): 161 | return self._repr_latex_() 162 | 163 | def __str__(self): 164 | return self.tostring(fmt='unicode') 165 | 166 | def __repr__(self): 167 | if self. _printer == 'ascii': 168 | return self.tostring(fmt='ascii') 169 | return self.tostring(fmt='unicode') 170 | 171 | def __format__(self,fmt): 172 | return self.tostring(fmt=fmt) 173 | 174 | def tohtml(self,**kwds): 175 | """ 176 | Returns a string representing this object formatted for html; equivalent 177 | to PrettyPrinter.tostring(fmt='html',**kwds). See the tostring method. 178 | """ 179 | return self.tostring(fmt='html',**kwds) 180 | 181 | def tolatex(self,**kwds): 182 | """ 183 | Returns a string representing this object formatted for LaTeX; equivalent 184 | to PrettyPrinter.tostring(fmt='latex',**kwds). See the tostring method. 185 | """ 186 | return self.tostring(fmt='latex',**kwds) 187 | 188 | def tounicode(self,**kwds): 189 | """ 190 | Returns a string representing this object; equivalent to 191 | PrettyPrinter.tostring(fmt='unicode',**kwds) and PrettyPrinter.__str__(). 192 | See the tostring method. 193 | """ 194 | return self.tostring(fmt='unicode',**kwds) 195 | 196 | def toascii(self,**kwds): 197 | """ 198 | Returns a string representing this object formatted using only ASCII 199 | characters; equivalent to PrettyPrinter.tostring(fmt='ascii',**kwds). 200 | See the tostring method. 201 | """ 202 | return self.tostring(fmt='ascii',**kwds) 203 | 204 | def latex(self,math=None,**kwds): 205 | """ 206 | Prints a representation of the object using LaTeX formatting if this method 207 | is called from an IPython console or Juptyer notebook. See the tostring 208 | method. 209 | """ 210 | if math is None: 211 | math = type(self).latex_math 212 | 213 | if math is None: 214 | print_latex(self.tolatex(**kwds)) 215 | else: 216 | print_latex(math(self.tolatex(**kwds))) 217 | 218 | def html(self,**kwds): 219 | """ 220 | Prints a representation of the object using HTML formatting if this method 221 | is called from an IPython console or Juptyer notebook. See the tostring 222 | method. 223 | """ 224 | print_html(self.tohtml(**kwds)) 225 | 226 | def unicode(self,**kwds): 227 | """ 228 | Prints a representation of the object. Equivalent to 229 | print(cls.tostring(fmt='unicode')). See the tostring method. 230 | """ 231 | print(self.tounicode(**kwds)) 232 | 233 | def ascii(self,**kwds): 234 | """ 235 | Prints a representation of the object using only ASCII characters. 236 | Equivalent to print(cls.tostring(fmt='ascii')). See the tostring 237 | method. 238 | """ 239 | print(self.toascii(**kwds)) 240 | 241 | 242 | def set_printer(value): 243 | """ 244 | Sets the preferred default display printer. This is a string with one of 245 | the following values: 246 | 247 | "any", "latex", "html", "unicode", or "ascii" 248 | 249 | "any" will usually pick html or latex output when running in an IPython 250 | console or Jupyter notebook and unicode otherwise. 251 | 252 | "latex" and "html" are only available when running under IPython. If 253 | these printers are not available the display will default to "unicode". 254 | """ 255 | if value is None: 256 | PrettyPrinter._printer = 'any_but_latex' 257 | return 258 | value = value.lower().strip() 259 | if value not in ['latex','html','ascii','unicode','any','any_but_latex']: 260 | raise ValueError('printer ' + str(value) + ' is not recognized') 261 | PrettyPrinter._printer = value 262 | -------------------------------------------------------------------------------- /metrolopy/relunits.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module relunits 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | """ 24 | This module is loaded by the gummy.units module and is not intended be be 25 | imported directly. Dimensionless units are defined here. 26 | """ 27 | from .unit import Unit,Conversion,one 28 | from .ummy import MFraction 29 | 30 | class RatioUnit(Unit): 31 | """RatioUnit is used for dimensionless units like % where powers, e.g. %**2, 32 | are not desired. 33 | """ 34 | def _cpow(self,v): 35 | if v == 1 or v == -1: 36 | return ([[self,v]],1) 37 | c = self.convert(1,one) 38 | if int(v) == v: 39 | if v > 0: 40 | return ([[self,1]],c**(v - 1)) 41 | else: 42 | return ([[self,1]],c**(v + 1)) 43 | return ([[one,1]],c**v) 44 | 45 | with Unit._builtin(): 46 | # The \t at the beggining of the symbol causes the space between the numerical 47 | # value and the unit symbol per the Chicago Manual of Style (but not the 48 | # SI brochure). 49 | RatioUnit('percent','\t%',Conversion(one,MFraction('0.01')),short_name='%', 50 | latex_symbol='\t\\%',add_symbol=False) 51 | 52 | RatioUnit('part per million','ppm',Conversion(one,MFraction('1e-6')),add_symbol=True) 53 | RatioUnit('part per billion','ppb',Conversion(one,MFraction('1e-9')),add_symbol=True) 54 | RatioUnit('part per trillion','ppt',Conversion(one,MFraction('1e-12')),add_symbol=True) 55 | RatioUnit('part per quadrillion','ppq',Conversion(one,MFraction('1e-15')),add_symbol=True) 56 | -------------------------------------------------------------------------------- /metrolopy/siunits.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module siunits 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | """ 24 | This module is loaded by the unit module and is not intended be be 25 | imported directly. 26 | 27 | The most of the units here are from the SI Brochure, 9th edition. 28 | """ 29 | 30 | from numpy import pi 31 | from .ummy import ummy,MFraction 32 | from .unit import Conversion,Unit 33 | from .prefixedunit import PrefixedUnit 34 | from .offsetunit import OffsetUnit,OffsetConversion 35 | 36 | 37 | with Unit._builtin(): 38 | #SI Base units 39 | _m = PrefixedUnit('metre','m',additional_names=('meter',),add_symbol=True, 40 | order=1,description='SI unit of length', 41 | base_description='SI base unit of length') 42 | Unit.alias('micron','um') 43 | _cm = Unit.unit('cm') 44 | _cm.description = 'SI unit of length and CGS base unit' 45 | 46 | _kg = PrefixedUnit('gram','g',add_symbol=True,order=1,base_prefix='kilo', 47 | description='SI unit of mass', 48 | base_description='SI base unit of mass') 49 | Unit.unit('g').description = 'SI unit of mass and CGS base unit' 50 | 51 | _s = PrefixedUnit('second','s',add_symbol=True,order=3, 52 | description='SI unit of time', 53 | base_description='SI and CGS base unit of time') 54 | 55 | _A = PrefixedUnit('ampere','A',add_symbol=True,order=4, 56 | description='SI unit of electrical current', 57 | base_description='SI base unit of electrical current') 58 | 59 | _K = PrefixedUnit('kelvin','K',add_symbol=True,order=5, 60 | description='SI unit of temperature', 61 | base_description='SI base unit of temperature') 62 | 63 | _mol = PrefixedUnit('mole','mol',add_symbol=True,order=6, 64 | description='SI unit for amount of substance', 65 | base_description='SI base unit for amount of substance') 66 | 67 | _cd = PrefixedUnit('candela','cd',add_symbol=True,order=7, 68 | description='SI unit of luminosity', 69 | base_description='SI base unit of luminosity') 70 | 71 | _ipk = Unit('international prototype kilogram','m(K)', 72 | Conversion(_kg,ummy(1,1.2e-8)),add_symbol=True, 73 | html_symbol='m(𝒦)',latex_symbol='m({\\mathcal {K}})', 74 | description='IPK, le grand k') 75 | Unit.alias('IPK',_ipk) 76 | 77 | #Coherent derived units in the SI with special names and symbols 78 | _rad = PrefixedUnit('radian','rad',Conversion(_m*_m**-1,1),add_symbol=True,order=0, 79 | description='unit of angle, angular unit') 80 | _sr = PrefixedUnit('steradian','sr',Conversion(_m**2*_m**-2,1),add_symbol=True,order=0, 81 | description='unit of solid angle, angular unit') 82 | _Hz = PrefixedUnit('hertz','Hz',Conversion(_s**-1,1),add_symbol=True,order=0, 83 | description='frequency') 84 | _N = PrefixedUnit('newton','N',Conversion(_m*_kg*_s**-2,1),add_symbol=True,order=0, 85 | description='SI derived unit of force') 86 | _Pa = PrefixedUnit('pascal','Pa',Conversion(_N*_m**-2,1),add_symbol=True,order=0, 87 | description='SI derived unit of pressure') 88 | _J = PrefixedUnit('joule','J',Conversion(_N*_m,1),add_symbol=True,order=0, 89 | description='SI derived unit of energy') 90 | _W = PrefixedUnit('watt','W',Conversion(_J*_s**-1,1),add_symbol=True,order=0, 91 | description='SI derived unit of power') 92 | _C = PrefixedUnit('coulomb','C',Conversion(_s*_A,1),add_symbol=True,order=0, 93 | description='SI derived unit of electrical charge') 94 | _V = PrefixedUnit('volt','V',Conversion(_W*_A**-1,1),add_symbol=True,order=0, 95 | description='SI derived unit of electric potential, voltage') 96 | PrefixedUnit('farad','F',Conversion(_C*_V**-1,1),add_symbol=True,order=0, 97 | description='SI derived unit of electrical capacitance') 98 | _ohm = PrefixedUnit('ohm','\u03A9',Conversion(_V*_A**-1,1),add_symbol=True,order=0, 99 | html_symbol='Ω',latex_symbol=r'\Omega',ascii_symbol='ohm', 100 | description='SI derived unit of electrical resistance') 101 | Unit.alias('Ohm',_ohm) 102 | _siemens = PrefixedUnit('siemens','S',Conversion(_A*_V**-1,1),add_symbol=True,order=0, 103 | description='SI derived unit of electrical conductance, susceptance and admittance') 104 | Unit.alias('mho',_siemens) 105 | _Wb = PrefixedUnit('weber','Wb',Conversion(_V*_s,1),add_symbol=True,order=0, 106 | description='SI derived unit of magnetic flux') 107 | _T = PrefixedUnit('tesla','T',Conversion(_Wb*_m**-2,1),add_symbol=True,order=0, 108 | description='SI derived unit of magnetic flux density') 109 | PrefixedUnit('henry','H',Conversion(_Wb*_A**-1,1),add_symbol=True,order=0, 110 | description='SI derived unit of electrical inductance') 111 | 112 | _degC = OffsetUnit('degree Celsius','\u00B0C',OffsetConversion(_K,273.15), 113 | latex_symbol='^{\\circ}C',ascii_symbol = 'degC',add_symbol=True,order=0, 114 | description='unit of temperature') 115 | Unit.alias('degree C',_degC) 116 | Unit.alias('deg C',_degC) 117 | 118 | _lm = PrefixedUnit('lumen','lm',Conversion(_cd*_sr,1),add_symbol=True,order=0, 119 | description='SI derived unit for luminous flux') 120 | PrefixedUnit('lux','lx',Conversion(_lm*_m**-2,1),add_symbol=True,order=0, 121 | description='SI derived unit for illuminance and luminous emittance') 122 | PrefixedUnit('becquerel','Bq',Conversion(_s**-1,1),add_symbol=True,order=0, 123 | description='SI derived unit for radioactivity') 124 | PrefixedUnit('gray','Gy',Conversion(_J*_kg**-1,1),add_symbol=True,order=0, 125 | description='SI derived unit for ionizing radiation') 126 | PrefixedUnit('sievert','Sv',Conversion(_J*_kg**-1,1),add_symbol=True,order=0, 127 | description='SI derived unit for ionizing radiation dose') 128 | PrefixedUnit('katal','kat',Conversion(_mol*_s**-1,1),add_symbol=True,order=0, 129 | description='SI unit for catalytic activity') 130 | 131 | #Non-SI units accepted for use with the International System of Units 132 | _min = Unit('minute','min',Conversion(_s,60),add_symbol=True,order=0, 133 | description='unit of time') 134 | _h = Unit('hour','h',Conversion(_min,60),add_symbol=True,order=0, 135 | description='unit of time') 136 | _d = Unit('day','d',Conversion(_h,24),add_symbol=True,order=0, 137 | description='unit of time') 138 | Unit.alias('D',_d) 139 | _deg = Unit('degree','\t\u00B0',Conversion(_rad,pi/180),add_symbol=True,order=0, 140 | latex_symbol='^{\\circ}',ascii_symbol='deg', 141 | description='unit of angle, angular unit') 142 | _arcmin = Unit('arcminute',"\t'",Conversion(_deg,MFraction(1,60)),add_symbol=True,order=0, 143 | short_name='arcmin',description='unit of angle, angular unit') 144 | Unit('arcsecond','\t"',Conversion(_arcmin,MFraction(1,60)),add_symbol=True,order=0, 145 | short_name='arcsec',description='unit of angle, angular unit') 146 | Unit('hectare','ha',Conversion('hm**2',1),add_symbol=True,order=0, 147 | description='unit of area') 148 | PrefixedUnit('litre','L',Conversion('dm**3',1),add_symbol=True,order=0, 149 | additional_names=('liter',),description='unit of volume') 150 | _tonne = PrefixedUnit('tonne','t',Conversion(_kg,1000),add_symbol=True,order=0, 151 | prefixes=['centi','deci','deca','hecto','kilo','mega', 152 | 'giga','tera','peta','exa','zetta','yotta'], 153 | description='unit of mass') 154 | Unit.alias('metric ton',_tonne) -------------------------------------------------------------------------------- /metrolopy/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from .test_create import * 4 | from .test_operations import * 5 | from .test_ubreakdown import * 6 | from .test_complex import * 7 | from .test_misc import * 8 | from .test_gummy import * -------------------------------------------------------------------------------- /metrolopy/tests/common.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import metrolopy as uc 4 | import numpy as np 5 | from fractions import Fraction 6 | 7 | try: 8 | import mpmath as mp 9 | except: 10 | mp = None 11 | 12 | rand = np.random.RandomState() 13 | 14 | def display(g): 15 | w = rand.randint(5) 16 | 17 | if isinstance(g,uc.immy): 18 | if rand.randint(2): 19 | g.style = 'polar' 20 | 21 | assert '?' not in g.tostring() 22 | 23 | if w == 0: 24 | print(g) 25 | elif w == 1: 26 | assert '?' not in g.tolatex() 27 | g.latex() 28 | elif w == 2: 29 | assert '?' not in g.tohtml() 30 | g.html() 31 | elif w == 3: 32 | assert '?' not in g.tounicode() 33 | g.unicode() 34 | else: 35 | assert '?' not in g.toascii() 36 | g.ascii() 37 | 38 | def make_gummy(sign=None,exp=None,uexp=-6,sometimes_small=True,dof=None, 39 | unit=None,units=None,mpf=False,allowzero=True,allowlargeu=True): 40 | 41 | utypes = ['A','B','D',None] 42 | if units is None: 43 | units = ['m','lb','m**2 s**3/kg**4','m**3','s**-2','1'] 44 | 45 | if rand.randint(10) == 0: 46 | if exp is None: 47 | x = rand.randint(6000) 48 | else: 49 | x = rand.randint(int(10**exp)) 50 | else: 51 | x = rand.rand()*0.9 + 0.1 52 | 53 | if exp is None: 54 | exp = rand.randint(1,6) 55 | if rand.randint(2): 56 | exp = -exp 57 | 58 | x = x*10**exp 59 | 60 | if sign is None: 61 | if rand.randint(2): 62 | x = -x 63 | else: 64 | x *= sign 65 | 66 | if not allowzero and x == 0: 67 | x = x + 1 68 | 69 | if allowlargeu and rand.randint(10) == 0: 70 | u = rand.randint(20) + 1 71 | else: 72 | u = rand.rand()*0.5 + 0.5 73 | if sometimes_small and not rand.randint(10): 74 | uexp -= 4 75 | u = abs(x)*u*10**uexp 76 | 77 | if mpf and mp is not None and not rand.randint(4): 78 | x = mp.mpf(x) 79 | if rand.randint(2): 80 | u = mp.mpf(u) 81 | 82 | if dof is None: 83 | if not rand.randint(4): 84 | dof = float('inf') 85 | else: 86 | dof = rand.randint(5,15) 87 | 88 | if unit is None: 89 | unit = units[rand.randint(len(units))] 90 | 91 | utype = utypes[rand.randint(len(utypes))] 92 | 93 | g = uc.gummy(x,u=u,dof=dof,unit=unit,utype=utype) 94 | 95 | return (g,x,u,dof,unit,utype) 96 | 97 | def make_number(sign=None,gconst=True,exp=None,fionly=True,allowzero=True): 98 | q = rand.randint(4) 99 | if fionly and q > 1: 100 | q = 1 101 | if q == 0: 102 | if exp is not None: 103 | x = rand.randint(10**(exp+1)) 104 | else: 105 | x = rand.randint(100000) 106 | if q == 1 or q == 2: 107 | x = rand.rand()*0.9 + 0.1 108 | if exp is None: 109 | exp = rand.randint(1,6) 110 | if rand.randint(2): 111 | exp = -exp 112 | 113 | x = x*10**exp 114 | if q == 2 and mp is not None: 115 | x = mp.mpf(x) 116 | elif q == 3: 117 | if exp is not None: 118 | a = rand.randint(10**(exp+1)) 119 | b = rand.randint(10**(exp+1)) 120 | else: 121 | a = rand.randint(100000) 122 | b = rand.randint(100000) 123 | if b == 0: 124 | x = Fraction(0) 125 | else: 126 | x = Fraction(a,b) 127 | 128 | 129 | if sign is None: 130 | if rand.randint(2): 131 | x = -x 132 | else: 133 | x *= sign 134 | 135 | if gconst and rand.randint(2): 136 | x = uc.gummy(x) 137 | 138 | if not allowzero and x == 0: 139 | x = x + 1 140 | 141 | return x -------------------------------------------------------------------------------- /metrolopy/tests/test_complex.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module test_complex 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | import numpy as np 24 | import unittest 25 | from metrolopy import immy,ummy,jummy,gummy 26 | from metrolopy.tests.common import display 27 | 28 | rand = np.random.RandomState() 29 | 30 | def make_immy(prnt=False): 31 | if rand.randint(2): 32 | imake = immy 33 | make = ummy 34 | else: 35 | imake = jummy 36 | make = gummy 37 | r = 4*rand.rand() + 1 38 | if rand.randint(2): 39 | r = -r 40 | ru = (0.1*rand.rand() + 0.01)*(abs(r)) 41 | i = 4*rand.rand() + 1 42 | if rand.randint(2): 43 | i = -i 44 | iu = (0.1*rand.rand() + 0.01)*(abs(i)) 45 | c = (2*rand.rand() - 1)*ru*iu 46 | 47 | cov = [[ru**2,c],[c,iu**2]] 48 | real,imag = make.create([r,i],covariance_matrix=cov) 49 | 50 | if rand.randint(2): 51 | ret = imake(real=real,imag=imag) 52 | else: 53 | if rand.randint(2): 54 | ret = imake(real=r,imag=i,cov=cov) 55 | assert abs(ret.real.covariance(ret.imag) - cov[0][1]) < 1e-6 56 | if imake is immy: 57 | real._ref = ret.real._ref 58 | imag._ref = ret.imag._ref 59 | else: 60 | real.value._ref = ret.real.value._ref 61 | imag.value._ref = ret.imag.value._ref 62 | else: 63 | r = np.sqrt(real**2 + imag**2) 64 | phi = np.arctan2(imag,real) 65 | ret = imake(r=r.x,phi=phi.x,cov=make.covariance_matrix([r,phi])) 66 | assert abs(ret.real.covariance(ret.imag) - cov[0][1]) < 1e-6 67 | if imake is immy: 68 | real._ref = ret.real._ref 69 | imag._ref = ret.imag._ref 70 | else: 71 | real.value._ref = ret.real.value._ref 72 | imag.value._ref = ret.imag.value._ref 73 | 74 | if prnt: 75 | display(ret) 76 | 77 | return (ret,real,imag) 78 | 79 | 80 | class TestComplex(unittest.TestCase): 81 | def assert_ummy_close(self,u1,u2): 82 | self.assertTrue(abs(u1.correlation(u2)) > 1 - 1e-4) 83 | u1x = max(u1.x,u1.u,u2.x,u2.u) 84 | self.assertTrue(abs((u1.x - u2.x)/(u1x)) < 1e-10) 85 | self.assertTrue(abs((u1.u - u2.u)/(u1.u)) < 1e-2) 86 | 87 | if u1.dof == float('inf'): 88 | self.assertTrue(u2.dof == float('inf')) 89 | else: 90 | self.assertTrue(abs((u2.dof - u1.dof)/u1.dof) < 1e-2) 91 | 92 | def assert_immy_close(self,i1,i2): 93 | self.assert_ummy_close(i1.real,i2.real) 94 | self.assert_ummy_close(i1.imag,i2.imag) 95 | 96 | def test_immy_init(self,n=1000,prnt=False): 97 | for m in range(n): 98 | x,xr,xi = make_immy(prnt=prnt) 99 | 100 | if rand.randint(2): 101 | if rand.randint(2): 102 | x = type(x)(x) 103 | else: 104 | x = x.copy(formatting=False) 105 | 106 | self.assert_ummy_close(x.real,xr) 107 | self.assert_ummy_close(x.imag,xi) 108 | self.assert_ummy_close(x.angle(),np.arctan2(xi,xr)) 109 | self.assert_ummy_close(abs(x),np.sqrt(xr**2 + xi**2)) 110 | self.assert_immy_close(x.conjugate(),immy(real=xr,imag=-xi)) 111 | self.assert_immy_close(-x,immy(real=-xr,imag=-xi)) 112 | self.assert_immy_close(+x,immy(real=xr,imag=xi)) 113 | 114 | if prnt: 115 | if rand.randint(2): 116 | y =1e12*x 117 | else: 118 | y = x/1e12 119 | display(y) 120 | 121 | def _test_immy_bop(self,f,nf,n=1000,prnt=False,allow_small=True): 122 | m = 0 123 | while m < n: 124 | a,ar,ai = make_immy() 125 | if True:#rand.randint(2): 126 | b,br,bi = make_immy() 127 | else: 128 | if rand.randint(2): 129 | b = 4*rand.rand() + 1 130 | if rand.randint(2): 131 | b = -b 132 | if rand.randint(2): 133 | bu = (0.1*rand.rand()+0.01)*(abs(b)) 134 | b = ummy(b,u=bu) 135 | else: 136 | br = 4*rand.rand() + 1 137 | if rand.randint(2): 138 | br = -br 139 | bi = 4*rand.rand() + 1 140 | if rand.randint(2): 141 | bi = -bi 142 | b = complex(br,bi) 143 | if rand.randint(2): 144 | bb = b 145 | b = a 146 | a = bb 147 | 148 | if isinstance(a,(immy,ummy)): 149 | ax = a.x 150 | else: 151 | ax = a 152 | if isinstance(b,(immy,ummy)): 153 | bx = b.x 154 | else: 155 | bx = b 156 | 157 | 158 | cx = f(ax,bx) 159 | 160 | if allow_small or abs(cx) > 0.1: 161 | m +=1 162 | 163 | c = f(a,b) 164 | cn = type(c).napply(nf,a,b) 165 | 166 | if prnt: 167 | display(a) 168 | display(b) 169 | display(c) 170 | display(cn) 171 | print('---') 172 | 173 | self.assertTrue(abs((c.real.x - cx.real)/cx.real) < 1e-10) 174 | self.assertTrue(abs((c.imag.x - cx.imag)/cx.imag) < 1e-10) 175 | self.assert_immy_close(c,cn) 176 | 177 | def test_immy_add(self,n=1000,prnt=False): 178 | self._test_immy_bop(lambda a,b: a + b,np.add,n,prnt) 179 | 180 | for m in range(10): 181 | i = make_immy()[0] 182 | self.assertTrue(i + 0 == i) 183 | self.assertTrue(0 + i == i) 184 | 185 | def test_immy_sub(self,n=1000,prnt=False): 186 | self._test_immy_bop(lambda a,b: a - b,np.subtract,n,prnt) 187 | 188 | for m in range(10): 189 | i = make_immy()[0] 190 | self.assertTrue(i - 0 == i) 191 | self.assertTrue(0 - i == -i) 192 | 193 | def test_immy_mul(self,n=1000,prnt=False): 194 | self._test_immy_bop(lambda a,b: a*b,np.multiply,n,prnt) 195 | 196 | for m in range(10): 197 | i = make_immy()[0] 198 | self.assertTrue(i*0 == 0) 199 | self.assertTrue(i*immy(0) == 0) 200 | self.assertTrue(i*1 == i) 201 | self.assertTrue(i*immy(1) == i) 202 | self.assertTrue(1*i == i) 203 | self.assertTrue(immy(1)*i == i) 204 | 205 | def test_immy_div(self,n=1000,prnt=False): 206 | self._test_immy_bop(lambda a,b: a/b,np.divide,n,prnt,allow_small=False) 207 | 208 | for m in range(10): 209 | i = make_immy()[0] 210 | self.assertTrue(i/1 == i) 211 | 212 | def test_immy_pow(self,n=1000,prnt=False): 213 | #_test_immy_bop(lambda a,b: a**b,np.power,n,prnt,allow_small=False) 214 | 215 | for m in range(10): 216 | i = make_immy()[0] 217 | self.assertTrue(0**i == immy(0)) 218 | self.assertTrue(0**i == ummy(0)) 219 | self.assertTrue(0**i == 0) 220 | self.assertTrue(i**0 == 1) 221 | 222 | self.assert_immy_close(i**-1,1/i) 223 | self.assert_immy_close(i**2,i*i) 224 | self.assert_immy_close(i**3,i*i*i) 225 | 226 | if __name__ == '__main__': 227 | unittest.main() -------------------------------------------------------------------------------- /metrolopy/tests/test_misc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module test_misc 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | """ 23 | Check that known bugs are fixed. 24 | """ 25 | 26 | import metrolopy as uc 27 | import numpy as np 28 | import unittest 29 | 30 | 31 | class TestMisc(unittest.TestCase): 32 | 33 | def test_reduce(self): 34 | a = uc.gummy(12.367,0.22,unit='mm/m') 35 | a.reduce_unit() 36 | self.assertTrue(abs(a.x - 0.012367) < 1e-15) 37 | self.assertTrue(abs(a.u - 0.00022) < 1e-15) 38 | self.assertTrue(a.unit is uc.one) 39 | 40 | def test_zero_derivative(self): 41 | u = 0.00223 42 | a = uc.gummy(0,u) 43 | b = a**2 44 | 45 | self.assertTrue(b.u == 0) 46 | b.sim() 47 | self.assertTrue(abs((np.sqrt(2)*u**2-b.usim)/b.usim) < 0.1) 48 | b.style = 'pmsim' 49 | self.assertTrue('?' not in b.tostring()) 50 | 51 | def test_triangular(self,plot=False): 52 | a = uc.gummy(uc.TriangularDist(1,1)) 53 | a.sim() 54 | self.assertTrue(abs((a.usim - 1/np.sqrt(6))/a.usim) < 0.1) 55 | if plot: 56 | print('This should be a triangle with mode 1, lower limit 0 and upper limit 1:') 57 | a.hist() 58 | 59 | a = uc.gummy(uc.TriangularDist(-2.5,left_width=0.5,right_width=1.5)) 60 | a.sim() 61 | if plot: 62 | print('this should be a triangle with mode -2.5, lower limit -3 and upper limit -1:') 63 | a.hist() 64 | 65 | a = uc.gummy(uc.TriangularDist(1,lower_limit=0.5,upper_limit=1.5)) 66 | a.sim() 67 | if plot: 68 | print('this should be a triangle with mode 1, lower limit 0.5 and upper limit 1.5:') 69 | a.hist() 70 | 71 | def test_zero_degc(self): 72 | a = uc.gummy(0, 0.15,unit='degC') 73 | a.style='xf' 74 | self.assertTrue(a.tostring() == '0.00') 75 | 76 | def test_ufrom_multiletter(self): 77 | a = uc.gummy(10.0, 1, utype='A') 78 | b = uc.gummy(20.0, 2, utype='DUT') 79 | y = a - b 80 | self.assertTrue(abs(y.ufrom('A') - 1) < 1e-15) 81 | self.assertTrue(abs(y.ufrom('DUT') - 2) < 1e-15) 82 | 83 | def test_uniform_params(self): 84 | # issue 33 85 | g = uc.gummy(uc.UniformDist(lower_limit=6,upper_limit=9),unit='pA') 86 | g.sim() 87 | self.assertTrue(abs(min(g.simdata) - 6) < 0.01) 88 | self.assertTrue(abs(max(g.simdata) - 9) < 0.01) 89 | 90 | g = uc.gummy(uc.UniformDist(center=7.5,half_width=1.5),unit='pA') 91 | g.sim() 92 | self.assertTrue(abs(min(g.simdata) - 6) < 0.01) 93 | self.assertTrue(abs(max(g.simdata) - 9) < 0.01) 94 | 95 | def test_mean_b(self): 96 | # issue 32 97 | import numpy as np 98 | from scipy.stats import t 99 | from scipy import special 100 | 101 | con = special.erf(1/np.sqrt(2)) 102 | def u(x): 103 | return t.ppf(1-(1-con)/2, len(x)-1)*x.std(ddof=1)/np.sqrt(len(x)) 104 | 105 | x = np.random.rand(5) 106 | g = uc.mean(x) 107 | g.p = 'ssd' 108 | self.assertTrue(abs(con-g.p) < 1e-6) 109 | self.assertTrue(abs(g.U - u(x)) < 1e-6) 110 | try: 111 | uc.gummy.bayesian = True 112 | gg = uc.mean(x) 113 | self.assertTrue(abs(gg.u - np.sqrt(2)*g.u) < 1e-6) 114 | gg.p = 'ssd' 115 | self.assertTrue(abs(gg.U - u(x)) < 1e-6) 116 | finally: 117 | uc.gummy.bayesian = False 118 | 119 | def test_uniform_hw(self): 120 | # issue 37 121 | a = uc.gummy(uc.UniformDist(upper_limit=1,lower_limit=-1)) 122 | b = uc.gummy(uc.UniformDist(center=0,half_width=1)) 123 | self.assertTrue(abs(a.u - b.u) < 1e-15) 124 | 125 | 126 | if __name__ == '__main__': 127 | unittest.main() -------------------------------------------------------------------------------- /metrolopy/unitparser.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module unitparser 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | """ 24 | unit parser 25 | """ 26 | 27 | from .exceptions import UnitLibError 28 | import numpy as np 29 | 30 | class _UnitParser: 31 | def __init__(self,txt): 32 | self.txt= txt 33 | self.n = len(txt) 34 | self.i = 0 35 | 36 | def parse(self): 37 | return self.ppar(0,1) 38 | 39 | def ppar(self,lev,es): 40 | cu = '' 41 | ul = [] 42 | sol = False 43 | while self.i < self.n: 44 | c = self.txt[self.i] 45 | if c == ')': 46 | cu = cu.strip() 47 | if cu != '': 48 | ul += [[cu,es]] 49 | if len(ul) == 0: 50 | raise UnitLibError('syntax error in: ' + self.txt) 51 | self.i += 1 52 | e = self.look_for_pow() 53 | if e != 1: 54 | for u in ul: 55 | u[1] *= e 56 | if np.modf(u[1]) == 0: 57 | u[1] = int(u[1]) 58 | return ul 59 | elif c == '(': 60 | cu = cu.strip() 61 | p = self.pch(cu,')',']',self.i) 62 | if p is None: 63 | if cu != '': 64 | ul += [[cu,es]] 65 | cu = '' 66 | self.i += 1 67 | ul += self.ppar(lev+1,es) 68 | if sol: 69 | es = -es 70 | sol = False 71 | else: 72 | cu += p 73 | self.i += len(p) 74 | elif c == '[': 75 | cu = cu.strip() 76 | p = self.pch(cu,']',')',self.i) 77 | if p is None: 78 | if cu != '': 79 | ul += [[cu,es]] 80 | cu = '' 81 | self.i += 1 82 | ul += [self.pbr(es,cu)] 83 | cu = '' 84 | if sol: 85 | es = -es 86 | sol = False 87 | else: 88 | cu += p 89 | self.i += len(p) 90 | elif c.isspace() or c == '*': 91 | cu = cu.strip() 92 | if cu != '': 93 | ul += [[cu,es*self.look_for_pow()]] 94 | cu = '' 95 | if sol: 96 | es = -es 97 | sol = False 98 | elif c == '/': 99 | cu = cu.strip() 100 | if cu != '': 101 | ul += [[cu,es]] 102 | cu = '' 103 | #if sol: 104 | # raise UnitLibError('ambugus use of several soliudses (forward slashes) in: ' + self.txt) 105 | sol = not sol 106 | es = -es 107 | self.i += 1 108 | else: 109 | cu += c 110 | self.i += 1 111 | if lev != 0: 112 | raise UnitLibError('unmatched ")" found in: ' + self.txt) 113 | cu = cu.strip() 114 | if cu != '': 115 | ul += [[cu,es]] 116 | return ul 117 | 118 | def look_for_pow(self): 119 | while self.i < self.n: 120 | c = self.txt[self.i] 121 | if c == '*': 122 | if self.i == (self.n - 1): 123 | raise UnitLibError(self.txt + ' ends with *') 124 | self.i += 1 125 | c = self.txt[self.i] 126 | if not c == '*': 127 | return 1 128 | par = -1 129 | et = '' 130 | self.i += 1 131 | cl = '' 132 | stnum = False 133 | while self.i < self.n: 134 | c = self.txt[self.i] 135 | if c == '(': 136 | if par == 0: 137 | if cl.isspace() or cl == '*': 138 | f = float(et) 139 | if np.modf(f)[0] == 0: 140 | return int(f) 141 | else: 142 | return f 143 | raise UnitLibError('syntax error in: ' + self.txt) 144 | else: 145 | if par == -1: 146 | par = 1 147 | else: 148 | par += 1 149 | elif c == '[': 150 | if cl.isspace() or cl == '*': 151 | f = float(et) 152 | if np.modf(f)[0] == 0: 153 | return int(f) 154 | else: 155 | return f 156 | raise UnitLibError('syntax error in: ' + self.txt ) 157 | elif c == ']': 158 | raise UnitLibError('unmatched bracket: ' + self.txt) 159 | elif c.isalpha(): 160 | if par > 0: 161 | raise UnitLibError('syntax error in: ' + self.txt) 162 | f = float(et) 163 | if np.modf(f)[0] == 0: 164 | return int(f) 165 | else: 166 | return f 167 | elif c == '/': 168 | if par <= 0: 169 | f = float(et) 170 | if np.modf(f)[0] == 0: 171 | return int(f) 172 | else: 173 | return f 174 | elif c == ')': 175 | if par <= 0: 176 | f = float(et) 177 | if np.modf(f)[0] == 0: 178 | return int(f) 179 | else: 180 | return f 181 | else: 182 | par -= 1 183 | elif c.isnumeric(): 184 | stnum = True 185 | elif c == '+' or c == '-': 186 | if stnum and par <= 0: 187 | raise UnitLibError('syntax error in: ' + self.txt) 188 | elif c == '*': 189 | if self.i == self.n - 1: 190 | raise UnitLibError('syntax error in: ' + self.txt) 191 | if par <= 0 and cl != '*' and self.txt[self.i+1] != '*': 192 | self.i += 1 193 | f = float(et) 194 | if np.modf(f)[0] == 0: 195 | return int(f) 196 | else: 197 | return f 198 | elif c.isspace(): 199 | if stnum and par <= 0: 200 | self.i += 1 201 | f = float(et) 202 | if np.modf(f)[0] == 0: 203 | return int(f) 204 | else: 205 | return f 206 | else: 207 | if par <= 0: 208 | raise UnitLibError('syntax error in: ' + self.txt) 209 | self.i += 1 210 | cl = c 211 | et += c 212 | f = float(et) 213 | if np.modf(f)[0] == 0: 214 | return int(f) 215 | else: 216 | return f 217 | 218 | elif not c.isspace(): 219 | return 1 220 | self.i += 1 221 | return 1 222 | 223 | def pbr(self,es,cu): 224 | br = 0 225 | while self.i < self.n: 226 | c = self.txt[self.i] 227 | if c == '[': 228 | br += 1 229 | cu += c 230 | if c == ']': 231 | if br == 0: 232 | self.i += 1 233 | return [cu,es*self.look_for_pow()] 234 | br -= 1 235 | cu += c 236 | self.i += 1 237 | raise UnitLibError('syntax error in: ' + self.txt) 238 | 239 | def pch(self,cu,ech,och,i): 240 | if cu == '': 241 | return None 242 | ret = self.txt[i] 243 | i += 1 244 | while i < self.n: 245 | c = self.txt[i] 246 | 247 | if c == ech: 248 | return ret + c 249 | if c.isspace(): 250 | return None 251 | if c in {och,'*','/'}: 252 | return None 253 | 254 | if c == '(': 255 | r = self.pch('a',')',']',i) 256 | if r is None: 257 | return None 258 | else: 259 | ret += r 260 | i += len(r) - 1 261 | elif c == '[': 262 | r = self.pch('a',']',')',i) 263 | if r is None: 264 | return None 265 | else: 266 | ret += r 267 | i += len(r) - 1 268 | else: 269 | ret += c 270 | 271 | i += 1 272 | 273 | return None 274 | 275 | -------------------------------------------------------------------------------- /metrolopy/usunits.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module usunits 4 | 5 | # Copyright (C) 2019 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | """ 24 | This module is loaded by the gummy.units module and is not intended be be 25 | imported directly. The gummy.siunits module must be loaded before loading 26 | this module. 27 | 28 | Most units here are from: 29 | 30 | NIST Special Publication 1038, "The International System of Units (SI) – 31 | Conversion Factors for General Use", May 2006. 32 | """ 33 | 34 | from .unit import Unit,Conversion 35 | from .offsetunit import OffsetUnit,OffsetConversion 36 | from .prefixedunit import PrefixedUnit 37 | from .ummy import MFraction 38 | 39 | with Unit._builtin(): 40 | _in = PrefixedUnit('inch','in',Conversion('m',MFraction('0.0254')),prefixes=['micro'], 41 | add_symbol=True,description='unit of length') 42 | Unit('hand','hand',Conversion(_in,4),add_symbol=True,description='unit of length') 43 | _ft = Unit('foot','ft',Conversion(_in,12),add_symbol=True,description='unit of length') 44 | _yd = Unit('yard','yd',Conversion(_ft,3),add_symbol=True,description='unit of length') 45 | Unit('mile','mi',Conversion(_yd,1760),add_symbol=True,description='unit of length') 46 | _pica = Unit('pica','P/',Conversion(_in,MFraction(1,6)),add_symbol=True,description='unit of length') 47 | Unit('point','p',Conversion(_pica,MFraction(1,12)),add_symbol=True,description='unit of length') 48 | Unit('link','li',Conversion(_ft,MFraction(33,50)),add_symbol=True,description='unit of length') 49 | Unit('survey foot','ft',Conversion('m',MFraction(1200,3937)),add_symbol=False,description='unit of length') 50 | _rod = Unit('rod','rd',Conversion(_ft,25),add_symbol=True,description='unit of length') 51 | _ch = Unit('chain','ch',Conversion(_rod,4),add_symbol=True,description='unit of length') 52 | _fur = Unit('furlong','fur',Conversion(_ch,10),add_symbol=True,description='unit of length') 53 | _mi = Unit('survey mile','mi',Conversion(_fur,8),add_symbol=False,description='unit of length') 54 | Unit.alias('statute mile',_mi) 55 | Unit('league','lea',Conversion(_mi,3),add_symbol=True,description='unit of length') 56 | _ftm = Unit('fathom','ftm',Conversion(_yd,2),add_symbol=True,description='unit of length') 57 | Unit('cable','cb',Conversion(_ftm,120),add_symbol=True,description='unit of length') 58 | _mil = Unit('thousandth of an inch','mil',Conversion(_in,MFraction(1,1000)),add_symbol=True,description='unit of length') 59 | Unit.alias('thou',_mil) 60 | Unit.alias('thousandth',_mil) 61 | 62 | _acre = Unit('acre','acre',Conversion(_ch**2,10),add_symbol=True,description='unit of area') 63 | _section = Unit('section','section',Conversion(_acre,640),add_symbol=True,description='unit of area') 64 | Unit('survey township','twp',Conversion(_section,36),add_symbol=True,description='unit of area') 65 | 66 | Unit('cubic inch','cu in',Conversion(_in**3,1),add_symbol=True, 67 | short_name='cu-in',description='unit of volume') 68 | Unit('cubic foot','cu ft',Conversion(_ft**3,1),add_symbol=True, 69 | short_name='cu-ft',description='unit of volume') 70 | Unit('cubic yard','cu yd',Conversion(_yd**3,1),add_symbol=True, 71 | short_name='cu-yd',description='unit of volume') 72 | Unit('acre-foot','acre ft',Conversion(_ft**3,43560),add_symbol=True, 73 | short_name='acre-ft',description='unit of volume') 74 | 75 | _gal = Unit('gallon','gal',Conversion(_in**3,231),add_symbol=True,description='unit of volume') 76 | Unit.alias('liquid gallon',_gal) 77 | Unit.alias('liquid gal',_gal) 78 | 79 | _qt = Unit('quart','qt',Conversion(_gal,MFraction(1,4)),add_symbol=True,description='unit of volume') 80 | Unit.alias('liquid quart',_qt) 81 | Unit.alias('liquid qt',_qt) 82 | 83 | _pt = Unit('pint','pt',Conversion(_qt,MFraction(1,2)),add_symbol=True,description='unit of volume') 84 | Unit.alias('liquid pint',_pt) 85 | Unit.alias('liquid pt',_pt) 86 | 87 | _cp = Unit('cup','cp',Conversion(_pt,MFraction(1,2)),add_symbol=True,description='unit of volume') 88 | _gi = Unit('gill','gi',Conversion(_cp,MFraction(1,2)),add_symbol=True,description='unit of volume') 89 | _floz = Unit('fluid ounce','fl oz',Conversion(_gi,MFraction(1,4)),add_symbol=True, 90 | short_name='fl-oz',description='unit of volume') 91 | _tbsp = Unit('tablespoon','Tbsp',Conversion(_floz,MFraction(1,2)),add_symbol=True,description='unit of volume') 92 | _tsp = Unit('teaspoon','tsp',Conversion(_tbsp,MFraction(1,3)),add_symbol=True,description='unit of volume') 93 | _minum = Unit('minim','min',Conversion(_tsp,MFraction('0.125')),add_symbol=False,description='unit of volume') 94 | Unit('fluid dram','fl dr',Conversion(_minum,60),add_symbol=True, 95 | short_name='fl-dr',description='unit of volume') 96 | Unit('shot','jig',Conversion(_tbsp,3),add_symbol=True,description='unit of volume') 97 | 98 | _bbl = Unit('barrel','bbl',Conversion(_gal,MFraction('31.5')),add_symbol=True,description='unit of volume') 99 | Unit.alias('liquid barrel',_bbl) 100 | Unit.alias('liquid bbl',_bbl) 101 | 102 | Unit('oil barrel','bbl',Conversion(_gal,42),add_symbol=False,description='unit of volume') 103 | Unit('hogshead','hogshead',Conversion(_gal,65),add_symbol=True,description='unit of volume') 104 | 105 | _dgal = Unit('dry gallon','gal',Conversion(_in**3,MFraction('268.8025')),add_symbol=False, 106 | short_name='dry-gal',description='unit of volume') 107 | _dqt = Unit('dry quart','qt',Conversion(_dgal,MFraction(1,4)),add_symbol=False, 108 | short_name='dry-qt',description='unit of volume') 109 | Unit('dry pint','pt',Conversion(_dqt,MFraction(1,2)),add_symbol=False, 110 | short_name='dry-pt',description='unit of volume') 111 | _pk = Unit('peck','pk',Conversion(_dgal,2),add_symbol=True,description='unit of volume') 112 | Unit('bushel','bu',Conversion(_pk,4),add_symbol=True,description='unit of volume') 113 | Unit('dry barrel','bu',Conversion(_in**3,7056),add_symbol=False, 114 | short_name='dry-bbl',description='unit of volume') 115 | 116 | _lb = PrefixedUnit('pound','lb',Conversion('kg',MFraction('0.45359237')),add_symbol=True, 117 | prefixes=['micro'],description='unit of mass') 118 | Unit.alias('avoirdupois pound',_lb) 119 | Unit.alias('avdp lb',_lb) 120 | Unit.alias('lbm',_lb) 121 | Unit.alias('pound mass',_lb) 122 | Unit.alias('ulbm','ulb') 123 | Unit.alias('micropound mass','ulb') 124 | 125 | _oz = Unit('ounce','oz',Conversion(_lb,MFraction('0.0625')),add_symbol=True,description='unit of mass') 126 | Unit.alias('avoirdupois ounce',_oz) 127 | Unit.alias('avdp oz',_oz) 128 | 129 | Unit('dram','dr',Conversion(_oz,MFraction('0.0625')),add_symbol=True,description='unit of mass') 130 | 131 | _gr = Unit('grain','gr',Conversion(_lb,MFraction(1,7000)),add_symbol=True,description='unit of mass') 132 | 133 | Unit('hundredweight','cwt',Conversion(_lb,100),add_symbol=True,description='unit of mass') 134 | Unit('long hundredweight','long cwt',Conversion(_lb,112),add_symbol=True,description='unit of mass') 135 | Unit('short ton','tn',Conversion(_lb,2000),add_symbol=True,description='unit of mass') 136 | Unit('long ton','long ton',Conversion(_lb,2240),add_symbol=False,description='unit of mass') 137 | 138 | _dwt = Unit('pennyweight','dwt',Conversion(_gr,24),add_symbol=True,description='unit of mass') 139 | _toz = Unit('troy ounce','oz t',Conversion(_dwt,20),add_symbol=True, 140 | short_name='oz-t',description='unit of mass') 141 | Unit('troy pound','lb t',Conversion(_toz,12),add_symbol=True, 142 | short_name='lb-t',description='unit of mass') 143 | 144 | _lbf = Unit('pound force','lbf',Conversion('lb m s**-2',MFraction('9.80665')),add_symbol=True,description='unit of force') 145 | Unit('slug','slug',Conversion('lbf s**2 ft**-1',1),add_symbol=True,description='unit of force') 146 | 147 | _degR = Unit('degree Rankine','\u00B0R',Conversion('K',MFraction(5,9)), 148 | latex_symbol='^{\\circ}R',ascii_symbol='degR',add_symbol=True, 149 | description='unit of temperature') 150 | Unit.alias('degree R',_degR) 151 | Unit.alias('deg R',_degR) 152 | 153 | _degF = OffsetUnit('degree Fahrenheit','\u00B0F',OffsetConversion('degR',MFraction('459.67')), 154 | latex_symbol='^{\\circ}F',ascii_symbol='degF',add_symbol=True, 155 | description='unit of temperature') 156 | Unit.alias('degree F',_degF) 157 | Unit.alias('deg F',_degF) 158 | 159 | Unit('pound per square inch','psi',Conversion(_lbf*_in**-2),add_symbol=True, 160 | description='unit of pressure') 161 | 162 | Unit('board-foot','board-foot',Conversion(_ft**2*_in,1),add_symbol=True, 163 | short_name='board-ft',description='unit of volume') 164 | 165 | _cal = Unit('calorie','cal',Conversion('J',MFraction('4.184')),add_symbol=True, 166 | description='unit of energy') 167 | Unit.alias('thermochemical calorie',_cal) 168 | Unit.alias('calth',_cal) 169 | 170 | _Cal = Unit('large calorie','Cal',Conversion(_cal,1000),add_symbol=True, 171 | description='unit of energy') 172 | Unit.alias('kilocalorie',_Cal) 173 | Unit.alias('kcal',_Cal) 174 | Unit.alias('dietary calorie',_Cal) 175 | Unit.alias('Calorie',_Cal) 176 | 177 | _btu = Unit('IT British thermal unit','BTU',Conversion('J',MFraction('1055.05585262')), 178 | add_symbol=True,description='unit of energy') 179 | Unit.alias('Btu',_btu) 180 | 181 | Unit('horsepower','hp',Conversion('lbf ft s**-1',550), add_symbol=True, 182 | description='unit of power') 183 | 184 | _ftlb = Unit('foot-pound','ft\u00B7lb',Conversion(_ft*_lbf,1),add_symbol=True, 185 | ascii_symbol='ft-lb',description='unit of work or energy') 186 | Unit.alias('ft\u00B7lbf',_ftlb) 187 | Unit.alias('ft-lbf',_ftlb) 188 | 189 | _lbft = Unit('pound-foot','lb\u00B7ft',Conversion(_ft*_lbf,1),add_symbol=True, 190 | ascii_symbol='lb-ft',description='unit of torque') 191 | Unit.alias('lbf\u00B7ft',_lbft) 192 | Unit.alias('lbf-lft',_lbft) 193 | 194 | Unit('rack unit','U',Conversion(_in,MFraction('1.75')),add_symbol=False, 195 | description='unit of length') 196 | Unit('square','square',Conversion(_ft**2,100),add_symbol=False, 197 | description='unit of area used in construction') 198 | Unit('gasoline gallon equivalent','gasoline-gallon-equivalent', 199 | Conversion('kW h',33.7),add_symbol=True,description='unit of energy') 200 | _ttnt = PrefixedUnit('tons of TNT equivalent','t(TNT)',Conversion('GJ',4.184),add_symbol=True, 201 | description='unit of energy in an explosion',prefixes=['kilo','mega','giga']) 202 | Unit.alias('tons of TNT',_ttnt) 203 | Unit.alias('tons of tnt',_ttnt) 204 | -------------------------------------------------------------------------------- /metrolopy/version.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # module version 4 | 5 | # Copyright (C) 2025 National Research Council Canada 6 | # Author: Harold Parks 7 | 8 | # This file is part of MetroloPy. 9 | 10 | # MetroloPy is free software: you can redistribute it and/or modify it under 11 | # the terms of the GNU General Public License as published by the Free Software 12 | # Foundation, either version 3 of the License, or (at your option) any later 13 | # version. 14 | 15 | # MetroloPy is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | 20 | # You should have received a copy of the GNU General Public License along with 21 | # MetroloPy. If not, see . 22 | 23 | __version__ = '0.6.5' 24 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Wed May 10 09:36:41 2017 4 | 5 | @author: h parks 6 | """ 7 | 8 | from setuptools import setup 9 | 10 | __version__ = None 11 | with open('metrolopy/version.py') as f: 12 | exec(f.read()) 13 | 14 | with open("README.md", "r") as fh: 15 | long_description = fh.read() 16 | 17 | setup(name = 'metrolopy', 18 | version = __version__, 19 | description = 'tools for dealing with measured quantities: uncertainty propagation and unit conversion', 20 | long_description=long_description, 21 | long_description_content_type="text/markdown", 22 | author = 'Harold Parks, National Research Council Canada', 23 | author_email = 'parksh@nrc.ca', 24 | url = 'http://nrc-cnrc.github.io/MetroloPy/', 25 | packages = ['metrolopy','metrolopy.tests'], 26 | package_data = {'metrolopy':['license.txt']}, 27 | python_requires='>=3.5', 28 | install_requires=['numpy>=1.13','scipy','matplotlib','pandas'], 29 | extras_require = {'pretty':['IPython']}, 30 | zip_safe = True, 31 | classifiers=[ 32 | "Programming Language :: Python :: 3", 33 | "Operating System :: OS Independent", 34 | "Development Status :: 4 - Beta", 35 | "Framework :: Jupyter", 36 | "Framework :: IPython", 37 | "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", 38 | "Intended Audience :: Science/Research", 39 | "Intended Audience :: Education", 40 | "Topic :: Scientific/Engineering :: Physics" 41 | ] 42 | ) 43 | 44 | 45 | 46 | 47 | --------------------------------------------------------------------------------