From 03c6acba7bcb99a0c11617521e8e733697ba1e56 Mon Sep 17 00:00:00 2001 From: Juncheng E Date: Mon, 28 Feb 2022 12:13:27 +0100 Subject: [PATCH 01/10] New release 0.1.0 (#52) * Fixing html footer. * Adding more py versions to be supported. * Update gitignore egg files are now ignored. * Added new ci file for github actions. * Removed obsolet travis ci file. * Fixing html footer. * Adding more py versions to be supported. * Update gitignore egg files are now ignored. * Added new ci file for github actions. * Removed obsolet travis ci file. * Carsten (#30) * Fixing version issue in CI setup. * Update ci file. libpyvinyl was not installed into testing environment, this caused ImportError. * Update gitignor Ignore emacs swap files. * Small cosmetic fixes. Co-authored-by: Carsten Fortmann-Grote * Add readthedocs.yaml Configuration of basic rtd settings now live in this file as recommended by readthedocs. * Update readthedocs.yaml Fixed ubuntu version * Update readthedocs.yaml Fixing path to rtd python conf file. * Update readthedocs.yaml Add global requirements and project to install step * Update readthedocs.yaml Trying to fix package install. * Remove readthecods.yaml from git. * Update refman.rst Replace autoclass by automodule statements. Include Collection and Instrument modules. * Update authors. * Update gitignore. json dumps, h5 and tmp files produced by examples and tests are now ignored. * Updated parameters container to Ordered_dict to preserve parameter order. Moved value from an attribute to a property. In connection to this, I made the consequence of entering an illegal value an error instead of it just being ignored. This was chosen as the setter function is now hidden from the user, so they wouldnt necessarily know a check is being made behind the scences. Updated tests to account for removal of set_value function. * using json_tricks in order to support dump and load of numpy arrays in json * instructions to run tests: suggested pytest package for developers * more tests for the Parameter class * - changed logic of interval - modified tests to accomodate new logic for intervals - add_interval and add_option now have an additional argument * small fix to ParameterTest * Suggested changes by Junchen: setup.py taking requirements from requirements.txt file * Replace interval and option with _interval and _option * Using closed intervals on both sides * Fixing logic of is_legal to simplify the reading of the code * Fixing and adding more tests for checking validity of values * More meaningful error message when looking for a parameter that does not exist * Addressing Carsten comments * Added __iter__ and __next__ methods to CalculatorParameters which use the underlying parameters.values() __iter__ and __next__ methods. If we have a CalculatorParameters object called A, these two are eqvivalent: for parameter in A.parameters.values(): print(parameter) for parameter in A: print(parameter) It is also possible to get all the parameter objects contained in a CalculatorParameters object into a list with just: parameter_list = list(A) * set_parameters method in base calculator * Updated test to check set_parameters. * removed specialized calculator and removed useless numpy dependency from BaseCalculator * Specializedcalculator moved into the Tests * forgotten SpecializedCalculator in tests/ * Split requirements in prod.txt and dev.txt * github workflow using black also added to the dev requirements * Update ci.yml * Fix CI * reformatted by black * Several changes: - Introduced type checks for values, intervals and options. - Using pint.Quantity for floats and physical quantities with units - Encode and decode pint.Quantity in json * Adding test for using units. * Removed print * Code cleaning and improvements plus more tests * respecting flake8 suggestion as reported by Junchen * fixing typos * Add BaseData.py * add DiffractionData examples * merge * Update ci file. libpyvinyl was not installed into testing environment, this caused ImportError. * Update data and format base classes and example. In this way, we can avoid dynamic module loading. * Adding specs * Update api_spec.py Tried to combine Jun's and my earlier prototype into one. Not entirely happy yet, need to add parameters / collections to get the whole story. * add pseudocode * add pseudocode * modified based on the first interation of reviews. * update BaseData and BaseFormat examples * Add module docstring. * comply snake case naming style * cleaned up the pseudo code for discussion * nice examples * add BaseDataTest.py * clean up unnecessary test and add integration test * NumberCalculatorsFinished * update PlusCalculator * Add test_ArrayCalculators.py * add test_Instrument.py * Update BaseCalculator in plusminus * the new proposed BaseCalculator * No need input_keys for calculator init * Format: Predicble return object from write * add initialization check * minor: error raise info updated * fix errors for test_ArrayCalculators * Black format * improve BaseDataTest * add list format test * make mapping_type() consistent * fix else in __get_dict_data and __get_file_data * Add docstrings to BaseData * add DataCollection to_list test * Update plusminus test * Update BaseFormat convert example * Update BaseFormat convert example * Temporary RandomImageCalculator.py for CI fixing * implement Optional hint * update BaseFormat placeholder functions and correct typos * Fix typos and tests for duplicating file output * Update format return style * Remove unnecessary tests More comprehensive tests are added in PR #47 * Format correction * Update ci.yml to include testing pytest scripts * update docstrings of basecalculator * clean up BaseCalculator * finish BaseCalcualtor, working on Test * fix base_dir * cleaned up BaseCalculatorTest * set DataCollection setitem * fixed all tests * add pytest for integration * uncomment missed calculator test * remove SpecializedCalculator.py * add edit parameter tests in BaseCalculatorTest.py * fix ci * add | to ci.yml * Parameters.to_dict(): Deepcopy to not modify the original parameters * Update README Add installation and testing instructions. * Update BaseCalculatorTest * Renamed 'pointer' to 'reference' (there are no pointers in python) * Removed commented code * Update Test. Remove unused modules Remove travis check pep8 fixes * Syntax fix * Update BaseCalculatorTest Removed logging since not used. * Update BaseCalculatorTest Adding class docstring to class. * Update BaseCalculator Typo in authors list Remove implementation of init_parameters(), it's an abstract class, so raise NotImplementedError. TODO: test init_parameters() * Update README Make summary more concise. * Update BaseCalculator black reformatting. * Update example notebook Adjust to new API (libpyvinyl) TODO: fix BaseCalculator, see error in cell 7) * Add Parameter class to module. * Seperate unit tests and integration tests * update tests in README.md * update ci.yml with the new test file structure * Fix BaseCalculator output consistensy check * check expected_data can be reached, then allow extra data to be read * expose BaseData in libpyvinyl __init__ * update setup.py toward 0.1.0 * bump version in setup.py * Update CI badge in README.md Replace the outdated Travis badge with current github CI badge. * Add Parameters test corresponding to #51 * Method to retrieve the parameter value as a pint Quantity * Support for numpy floats as input with conversion to pint.Quantity * numpy now required by Parameter class in order to accept numpy floats as value * Allow BaseCalculator to accept None input. * Fix #50 by increasing ljust and adding a space To deal with very long parameter names, we increasted the ljust and added a space after the name, value and unit. * Remove example calculators, which are not compatible with the new BaseCalculator class * Remove unnecessary docs of the integration test - Remove the license, history.rst and contributing - Add graphs explaining the plusminus integration test * Fix setup.py author format Co-authored-by: Carsten Fortmann-Grote Co-authored-by: Carsten Fortmann-Grote Co-authored-by: Shervin Nourbakhsh Co-authored-by: Carsten Fortmann-Grote Co-authored-by: Mads Bertelsen Co-authored-by: mads-bertelsen Co-authored-by: shervin86 --- .github/workflows/ci.yml | 27 + .gitignore | 13 +- .travis.yml | 31 - DEVEL.md | 22 + README.md | 102 ++- doc/source/_templates/footer.html | 2 +- doc/source/conf.py | 4 +- doc/source/include/notebooks/example-01.ipynb | 440 +++++++------ doc/source/include/refman.rst | 16 +- libpyvinyl/AbstractBaseClass.py | 2 +- libpyvinyl/BaseCalculator.py | 473 ++++++++------ libpyvinyl/BaseData.py | 489 ++++++++++++++ libpyvinyl/BaseFormat.py | 109 ++++ libpyvinyl/BeamlinePropagator.py | 47 -- libpyvinyl/Detector.py | 47 -- libpyvinyl/Instrument.py | 50 +- libpyvinyl/Parameters/Collections.py | 128 +++- libpyvinyl/Parameters/Parameter.py | 485 ++++++++++---- libpyvinyl/Parameters/__init__.py | 2 +- libpyvinyl/SignalGenerator.py | 47 -- libpyvinyl/__init__.py | 6 + requirements.txt | 7 +- requirements/dev.txt | 4 + requirements/prod.txt | 7 + setup.cfg | 4 +- setup.py | 56 +- tests/BaseCalculatorTest.py | 381 ----------- tests/BeamlinePropagatorTest.py | 85 --- tests/DetectorTest.py | 49 -- tests/InstrumentTest.py | 119 ---- tests/ParametersTest.py | 266 -------- tests/RadiationSampleInteractorTest.py | 49 -- tests/RandomImageCalculator.py | 38 -- tests/SignalGeneratorTest.py | 50 -- tests/Test.py | 69 -- .../plusminus/.github/ISSUE_TEMPLATE.md | 15 + tests/integration/plusminus/.gitignore | 105 +++ tests/integration/plusminus/README.rst | 18 + .../plusminus/docs/01-data_structure.png | Bin 0 -> 218354 bytes .../plusminus/docs/02-instrument_example.png | Bin 0 -> 171726 bytes .../ArrayCalculators/ArrayCalculator.py | 59 ++ .../plusminus/ArrayCalculators/__init__.py | 1 + .../plusminus/ArrayData/ArrayData.py | 36 ++ .../plusminus/plusminus/ArrayData/H5Format.py | 47 ++ .../plusminus/ArrayData/TXTFormat.py | 45 ++ .../plusminus/plusminus/ArrayData/__init__.py | 3 + .../plusminus/plusminus/BaseCalculator.py | 243 +++++++ .../NumberCalculators/MinusCalculator.py | 55 ++ .../NumberCalculators/PlusCalculator.py | 52 ++ .../plusminus/NumberCalculators/__init__.py | 2 + .../plusminus/NumberData/H5Format.py | 47 ++ .../plusminus/NumberData/NumberData.py | 52 ++ .../plusminus/NumberData/TXTFormat.py | 45 ++ .../plusminus/NumberData/__init__.py | 3 + .../plusminus/plusminus/__init__.py | 8 + .../plusminus/plusminus/plusminus.py | 1 + .../plusminus/requirements.txt} | 0 .../plusminus/requirements_dev.txt | 13 + tests/integration/plusminus/setup.cfg | 23 + tests/integration/plusminus/setup.py | 53 ++ tests/integration/plusminus/tests/__init__.py | 1 + .../plusminus/tests/test_ArrayCalculators.py | 29 + .../plusminus/tests/test_Instrument.py | 38 ++ .../plusminus/tests/test_NumberCalculators.py | 55 ++ .../plusminus/tests/test_NumberData.py | 106 ++++ tests/integration/plusminus/tox.ini | 26 + .../unit/Test.py | 47 +- tests/unit/test_BaseCalculator.py | 304 +++++++++ tests/unit/test_BaseData.py | 422 +++++++++++++ tests/unit/test_Instrument.py | 119 ++++ tests/unit/test_Parameters.py | 596 ++++++++++++++++++ 71 files changed, 4531 insertions(+), 1864 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml create mode 100644 DEVEL.md create mode 100644 libpyvinyl/BaseData.py create mode 100644 libpyvinyl/BaseFormat.py delete mode 100644 libpyvinyl/BeamlinePropagator.py delete mode 100644 libpyvinyl/Detector.py delete mode 100644 libpyvinyl/SignalGenerator.py create mode 100644 requirements/dev.txt create mode 100644 requirements/prod.txt delete mode 100644 tests/BaseCalculatorTest.py delete mode 100644 tests/BeamlinePropagatorTest.py delete mode 100644 tests/DetectorTest.py delete mode 100644 tests/InstrumentTest.py delete mode 100644 tests/ParametersTest.py delete mode 100644 tests/RadiationSampleInteractorTest.py delete mode 100644 tests/RandomImageCalculator.py delete mode 100644 tests/SignalGeneratorTest.py delete mode 100644 tests/Test.py create mode 100644 tests/integration/plusminus/.github/ISSUE_TEMPLATE.md create mode 100644 tests/integration/plusminus/.gitignore create mode 100644 tests/integration/plusminus/README.rst create mode 100644 tests/integration/plusminus/docs/01-data_structure.png create mode 100644 tests/integration/plusminus/docs/02-instrument_example.png create mode 100644 tests/integration/plusminus/plusminus/ArrayCalculators/ArrayCalculator.py create mode 100644 tests/integration/plusminus/plusminus/ArrayCalculators/__init__.py create mode 100644 tests/integration/plusminus/plusminus/ArrayData/ArrayData.py create mode 100644 tests/integration/plusminus/plusminus/ArrayData/H5Format.py create mode 100644 tests/integration/plusminus/plusminus/ArrayData/TXTFormat.py create mode 100644 tests/integration/plusminus/plusminus/ArrayData/__init__.py create mode 100644 tests/integration/plusminus/plusminus/BaseCalculator.py create mode 100644 tests/integration/plusminus/plusminus/NumberCalculators/MinusCalculator.py create mode 100644 tests/integration/plusminus/plusminus/NumberCalculators/PlusCalculator.py create mode 100644 tests/integration/plusminus/plusminus/NumberCalculators/__init__.py create mode 100644 tests/integration/plusminus/plusminus/NumberData/H5Format.py create mode 100644 tests/integration/plusminus/plusminus/NumberData/NumberData.py create mode 100644 tests/integration/plusminus/plusminus/NumberData/TXTFormat.py create mode 100644 tests/integration/plusminus/plusminus/NumberData/__init__.py create mode 100644 tests/integration/plusminus/plusminus/__init__.py create mode 100644 tests/integration/plusminus/plusminus/plusminus.py rename tests/{__init__Test.py => integration/plusminus/requirements.txt} (100%) create mode 100644 tests/integration/plusminus/requirements_dev.txt create mode 100644 tests/integration/plusminus/setup.cfg create mode 100644 tests/integration/plusminus/setup.py create mode 100644 tests/integration/plusminus/tests/__init__.py create mode 100644 tests/integration/plusminus/tests/test_ArrayCalculators.py create mode 100644 tests/integration/plusminus/tests/test_Instrument.py create mode 100644 tests/integration/plusminus/tests/test_NumberCalculators.py create mode 100644 tests/integration/plusminus/tests/test_NumberData.py create mode 100644 tests/integration/plusminus/tox.ini rename libpyvinyl/RadiationSampleInteractor.py => tests/unit/Test.py (63%) create mode 100644 tests/unit/test_BaseCalculator.py create mode 100644 tests/unit/test_BaseData.py create mode 100644 tests/unit/test_Instrument.py create mode 100644 tests/unit/test_Parameters.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a94a800 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: CI +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements/dev.txt + pip install . + - name: unit testing + run: | + cd tests + pytest . + - name: Code formatting + run: | + black --check libpyvinyl/ diff --git a/.gitignore b/.gitignore index 7c5019f..fd798ed 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,16 @@ *.code-workspace .ropeproject tags -pyvinyl.egg-info/ doc/build +libpyvinyl.egg-info +.#*.* +.readthedocs.yaml +**/notebooks/*.json +**/notebooks/*.h5 +**/notebooks/tmp* +**/notebooks/.ipynb_checkpoints/ +tests/*.json +tests/*.h5 +tests/tmp* +dist/ +build/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b7a0d4f..0000000 --- a/.travis.yml +++ /dev/null @@ -1,31 +0,0 @@ -language: python -python: - - "3.5" - - "3.6" - - "3.7" - - "3.8" - - "nightly" - -sudo: required -dist: xenial - -matrix: - allow_failures: - - python: "3.5" - - python: "3.6" - - python: "nightly" - - -cache: - apt: false - directories: - - $HOME/.cache/pip - - $HOME/lib - -install: - - cd $TRAVIS_BUILD_DIR - - pip install -r requirements.txt - - pip install . - -script: - - python tests/Test.py diff --git a/DEVEL.md b/DEVEL.md new file mode 100644 index 0000000..f72c24d --- /dev/null +++ b/DEVEL.md @@ -0,0 +1,22 @@ +How to test +------------------------------ + +Minimally needed: +``` +pip install -e ./ +cd tests/unit +python Test.py +``` + +Recommended: +``` +pip install --user pytest +pip install -e ./ +cd tests +# Test all +pytest ./ +# Unit test only +pytest ./unit +# Integration test only +pytest ./integration +``` diff --git a/README.md b/README.md index 48bc2af..9d01fb4 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,110 @@ # libpyvinyl - The python APIs for Virtual Neutron and x-raY Laboratory -[![Build Status](https://travis-ci.com/PaNOSC-ViNYL/libpyvinyl.svg?branch=master)](https://travis-ci.com/PaNOSC-ViNYL/libpyvinyl) +[![CI](https://github.com/PaNOSC-ViNYL/libpyvinyl/actions/workflows/ci.yml/badge.svg)](https://github.com/PaNOSC-ViNYL/libpyvinyl/actions/workflows/ci.yml) [![Documentation Status](https://readthedocs.org/projects/libpyvinyl/badge/?version=latest)](https://libpyvinyl.readthedocs.io/en/latest/?badge=latest) - + ## Summary + The python package `libpyvinyl` exposes the high level API for simulation codes under -the umbrella of the Virtual Neutron and x-raY Laboratory (ViNYL). +the umbrella of the Virtual Neutron and x-raY Laboratory (ViNYL). The fundamental class is the `BaseCalculator` and its sister class `Parameters`. While `Parameters` is a pure state engine, i.e. it's sole purpose is to encapsulate the physical, numerical, and computational parameters of a simulation, the `BaseCalculator` -exposes the interface to +exposes the interface to -- Configure a simulation (through the corresponding `Parameters` instance) -- Launch the simulation run -- Collect the simulation output data and make it queriable as a class attribute -- Snapshoot a simulation by dumping the object to disk (using the `dill` library). +- Configure a simulation. +- Launch the simulation run. +- Collect the simulation output data. +- Construct a `Data` instance that represents the simulation output data. +- Snapshoot a simulation by dumping the object to disk. - Reload a simulation run from disk and continue the run with optionally modified parameters. -The `BaseCalculaton` is an abstract base class, it shall not be instantiated as such. +The `BaseCalculator` is an abstract base class, it shall not be instantiated as such. The anticipated use is to inherit specialised `Calculators` from `BaseCalculator` and to implement the core functionality in the derived class. In particular, this is required -for the methods responsible to launch a simulation (`run()`) . +for the methods responsible to launch a simulation through the `backengine()` method. As an example, we demonstrate in an [accompanying notebook](https://github.com/PaNOSC-ViNYL/libpyvinyl/blob/master/doc/source/include/notebooks/example-01.ipynb) how to declare a derived `Calculator` and implement a `backengine` method. The example then -shows how to run the simulation, store the results in a `hdf5` file, snapshot the simulation +shows how to run the simulation, store the results in a `hdf5` file, snapshot the simulation and reload the simulation into memory. -## Acknowledgement -This project has received funding from the European Union's Horizon 2020 research and innovation programme under grant agreement No. 823852. +## Installation + +We recommend installation in a virtual environment, either `conda` or `pyenv`. + +### Create a `conda` environment + +``` +$> conda create -n libpyvinyl +``` + +### Common users + +``` +$> pip install libpyvinyl +``` + +### Developers + +We provide a requirements file for developers in _requirements/dev.txt_. + +``` +$> cd requirements +$> pip install -r dev.txt +``` + +`conda install` is currently not supported. + +Then, install `libpyvinyl` into the same environment. The `-e` flag links the installed library to +the source code in the repository, such that changes in the latter are immediately effective in the installed version. +``` +$> cd .. +$> pip install -e . +``` +## Testing + +We recommend to run the unittests and integration tests. + +``` +$> pytest tests +``` + +You should see a test report similar to this: + +``` +=============================================================== test session starts ================================================================ +platform linux -- Python 3.8.10, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 +rootdir: /home/juncheng/Projects/libpyvinyl +collected 100 items + +integration/plusminus/tests/test_ArrayCalculators.py . [ 1%] +integration/plusminus/tests/test_Instrument.py . [ 2%] +integration/plusminus/tests/test_NumberCalculators.py ... [ 5%] +integration/plusminus/tests/test_NumberData.py ........... [ 16%] +unit/test_BaseCalculator.py .......... [ 26%] +unit/test_BaseData.py ........................... [ 53%] +unit/test_Instrument.py ....... [ 60%] +unit/test_Parameters.py ........................................ [100%] + +=============================================================== 100 passed in 0.56s ================================================================ +``` + +You can also run unittests only: + +``` +pytest tests/unit +``` + +Or to run integration tests only: + +``` +pytest tests/integration +``` + +## Acknowledgement + +This project has received funding from the European Union's Horizon 2020 research and innovation programme under grant agreement No. 823852. diff --git a/doc/source/_templates/footer.html b/doc/source/_templates/footer.html index ccb00fa..af67528 100644 --- a/doc/source/_templates/footer.html +++ b/doc/source/_templates/footer.html @@ -10,7 +10,7 @@

The software - libpyvinyl is licensed under the LGPL version 3 or later. + libpyvinyl is licensed under the LGPL version 3 or later.

This project has received funding from the European Union's Horizon 2020 research and innovation programme under grant agreement No. 823852 diff --git a/doc/source/conf.py b/doc/source/conf.py index d7951ea..3e09a77 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -23,8 +23,8 @@ # -- Project information ----------------------------------------------------- project = 'libpyvinyl' -copyright = '2020, Carsten Fortmann-Grote, Mads Bertelsen, Juncheng E' -author = 'Carsten Fortmann-Grote, Mads Bertelsen, Juncheng E' +copyright = '2020-2021, Carsten Fortmann-Grote, Mads Bertelsen, Juncheng E, Shervin Nourbakhsh' +author = 'Carsten Fortmann-Grote, Mads Bertelsen, Juncheng E, Shervin Nourbakhsh' # The short X.Y version version = '0.0.2' diff --git a/doc/source/include/notebooks/example-01.ipynb b/doc/source/include/notebooks/example-01.ipynb index 8709a7e..6a95225 100644 --- a/doc/source/include/notebooks/example-01.ipynb +++ b/doc/source/include/notebooks/example-01.ipynb @@ -9,107 +9,93 @@ }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Imports " - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, + "metadata": {}, "outputs": [], "source": [ - "from libpyvinyl.BaseCalculator import BaseCalculator, Parameters\n", - "import os\n", - "import h5py\n", - "import numpy" - ], + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": 2, "metadata": { "collapsed": false, + "jupyter": { + "outputs_hidden": false + }, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "from libpyvinyl import BaseCalculator, CalculatorParameters, Parameter\n", + "import os\n", + "import h5py\n", + "import numpy" + ] }, { "cell_type": "markdown", - "source": [ - "## Implement a Calculator that derives from `BaseCalculator`." - ], "metadata": { - "collapsed": false, "pycharm": { "name": "#%% md\n" } - } - }, - { - "cell_type": "code", - "execution_count": 27, - "outputs": [], + }, "source": [ - "from libpyvinyl.BaseCalculator import BaseCalculator, Parameters\n", - "import numpy\n", - "import h5py\n", - "import sys" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + "## Implement a Calculator that derives from `BaseCalculator`." + ] }, { "cell_type": "code", - "execution_count": 30, - "outputs": [], - "source": [ - "sys.path.insert(0,'../../../../tests')\n", - "\n", - "from RandomImageCalculator import RandomImageCalculator" - ], + "execution_count": 3, "metadata": { "collapsed": false, + "jupyter": { + "outputs_hidden": false + }, "pycharm": { "name": "#%%\n" } - } - }, - { - "cell_type": "code", - "execution_count": null, + }, "outputs": [], "source": [ - "class RandomImageCalculatorNB(BaseCalculator):\n", + "class RandomImageCalculator(BaseCalculator):\n", " \"\"\" class: Implements simulation of a rondom image for demonstration purposes. \"\"\"\n", - " def __init__(self, parameters=None, dumpfile=None, input_path=None, output_path=None):\n", + " def __init__(self, \n", + " *args,\n", + " **kwargs\n", + " ):\n", " \"\"\" Constructor of the RandomImageCalculator class. \"\"\"\n", - " super().__init__(parameters=parameters, dumpfile=dumpfile, output_path=output_path)\n", + " super().__init__(*args, **kwargs)\n", + " \n", + " self.__data = None\n", + " \n", "\n", " def backengine(self):\n", " \"\"\" Method to do the actual calculation.\"\"\"\n", - " tmpdata = numpy.random.random((self.parameters.grid_size_x, self.parameters.grid_size_y))\n", - "\n", - " self._set_data(tmpdata)\n", - " return 0\n", + " self.__data = [numpy.random.random((self.parameters.grid_size_x, self.parameters.grid_size_y))]\n", + " \n", + " self.saveH5()\n", "\n", " def saveH5(self, openpmd=False):\n", " \"\"\" Save image to hdf5 file 'output_path'. \"\"\"\n", - " with h5py.File(self.output_path, \"w\") as h5:\n", - " ds = h5.create_dataset(\"/data\", data=self.data)\n", - "\n", - " h5.close()\n", - "\n" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + " for i,fname in enumerate(self.output_filenames):\n", + " with h5py.File(fname, \"w\") as h5:\n", + " ds = h5.create_dataset(\"/data\", data=self.__data[i])\n", + " \n", + " def init_parameters():\n", + " pass" + ] }, { "cell_type": "markdown", @@ -120,52 +106,101 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ - "parameters = Parameters(photon_energy=6e3, pulse_energy=1.0e-6, grid_size_x=128, grid_size_y=128)" + "photon_energy = Parameter(name='photon_energy', unit='keV', comment=\"The photon energy in units of kilo electronvolt (keV)\")\n", + "pulse_energy = Parameter(name='pulse_energy', unit='J')\n", + "grid_size_x = Parameter(name='grid_size_x', unit=\"\")\n", + "grid_size_y = Parameter(name='grid_size_y', unit=\"\")\n" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], "source": [ - "### Setup the calculator" - ], - "metadata": { - "collapsed": false - } + "photon_energy.value = 6.0\n", + "pulse_energy.value = 5.0e-6\n", + "grid_size_x.value = 128\n", + "grid_size_y.value = 256\n" + ] }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 6, + "metadata": {}, "outputs": [], "source": [ - "calculator = RandomImageCalculator(parameters, output_path=\"out.h5\")" - ], + "parameters = CalculatorParameters([photon_energy, pulse_energy, grid_size_x, grid_size_y])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Setup the calculator" + ] + }, + { + "cell_type": "code", + "execution_count": 7, "metadata": { "collapsed": false, + "jupyter": { + "outputs_hidden": false + }, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [ + { + "ename": "ValueError", + "evalue": "len(output_keys) = 1 is not equal to len(output_data_types) = 1", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/tmp/ipykernel_3697194/3811637111.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mcalculator\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mRandomImageCalculator\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mparameters\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparameters\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'RandomImageCalculator'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moutput_keys\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'random_image.h5'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moutput_data_types\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0minput\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m/tmp/ipykernel_3697194/1285912060.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 6\u001b[0m ):\n\u001b[1;32m 7\u001b[0m \u001b[0;34m\"\"\" Constructor of the RandomImageCalculator class. \"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0msuper\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 9\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__data\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/libpyvinyl/libpyvinyl/BaseCalculator.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, name, input, output_keys, output_data_types, output_filenames, instrument_base_dir, calculator_base_dir, parameters)\u001b[0m\n\u001b[1;32m 127\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mparameters\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mparameters\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 128\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 129\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__check_consistency\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 130\u001b[0m \u001b[0;31m# Create output data objects according to the output_data_classes\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 131\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__init_output\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/Repositories/libpyvinyl/libpyvinyl/BaseCalculator.py\u001b[0m in \u001b[0;36m__check_consistency\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 134\u001b[0m \u001b[0;34m\"\"\"Check the consistency of the input parameters\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 135\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moutput_keys\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0moutput_data_types\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 136\u001b[0;31m raise ValueError(\n\u001b[0m\u001b[1;32m 137\u001b[0m \u001b[0;34mf\"len(output_keys) = {len(self.output_keys)} is not equal to len(output_data_types) = {len(self.output_keys)}\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 138\u001b[0m )\n", + "\u001b[0;31mValueError\u001b[0m: len(output_keys) = 1 is not equal to len(output_data_types) = 1" + ] + } + ], + "source": [ + "calculator = RandomImageCalculator(parameters=parameters, name='RandomImageCalculator', output_keys='random_image.h5', output_data_types=[], input=[] )" + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "### Run the backengine" - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": 33, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + }, + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "data": { - "text/plain": "0" + "text/plain": [ + "0" + ] }, "execution_count": 33, "metadata": {}, @@ -174,30 +209,45 @@ ], "source": [ "calculator.backengine()" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "### Look at the data and store as hdf5" - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": 34, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + }, + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "data": { - "text/plain": "array([[0.07471297, 0.00703423, 0.92835525, ..., 0.83050226, 0.93011749,\n 0.10575778],\n [0.30465388, 0.36400513, 0.48903381, ..., 0.0438568 , 0.39087367,\n 0.97940832],\n [0.61994805, 0.84566645, 0.42535347, ..., 0.94919735, 0.17939005,\n 0.74872113],\n ...,\n [0.22103305, 0.07844426, 0.8127275 , ..., 0.4273249 , 0.78210725,\n 0.59653636],\n [0.00889755, 0.40566176, 0.33960702, ..., 0.2634355 , 0.34068678,\n 0.99275201],\n [0.99495603, 0.18621833, 0.25057866, ..., 0.33598942, 0.10660242,\n 0.20565293]])" + "text/plain": [ + "array([[0.07471297, 0.00703423, 0.92835525, ..., 0.83050226, 0.93011749,\n", + " 0.10575778],\n", + " [0.30465388, 0.36400513, 0.48903381, ..., 0.0438568 , 0.39087367,\n", + " 0.97940832],\n", + " [0.61994805, 0.84566645, 0.42535347, ..., 0.94919735, 0.17939005,\n", + " 0.74872113],\n", + " ...,\n", + " [0.22103305, 0.07844426, 0.8127275 , ..., 0.4273249 , 0.78210725,\n", + " 0.59653636],\n", + " [0.00889755, 0.40566176, 0.33960702, ..., 0.2634355 , 0.34068678,\n", + " 0.99275201],\n", + " [0.99495603, 0.18621833, 0.25057866, ..., 0.33598942, 0.10660242,\n", + " 0.20565293]])" + ] }, "execution_count": 34, "metadata": {}, @@ -206,90 +256,98 @@ ], "source": [ "calculator.data" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "code", "execution_count": 35, - "outputs": [], - "source": [ - "calculator.saveH5(calculator.output_path)" - ], "metadata": { "collapsed": false, + "jupyter": { + "outputs_hidden": false + }, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "calculator.saveH5(calculator.output_path)" + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "### Save the parameters to a human readable json file." - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": 36, - "outputs": [], - "source": [ - "parameters.to_json(\"my_parameters.json\")" - ], "metadata": { "collapsed": false, + "jupyter": { + "outputs_hidden": false + }, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "parameters.to_json(\"my_parameters.json\")" + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "### Save calculator to binary dump." - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": 37, - "outputs": [], - "source": [ - "dumpfile = calculator.dump()" - ], "metadata": { "collapsed": false, + "jupyter": { + "outputs_hidden": false + }, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "dumpfile = calculator.dump()" + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "### Load back parameters" - ], - "metadata": { - "collapsed": false - } + ] }, { "cell_type": "code", "execution_count": 38, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + }, + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "data": { - "text/plain": "6000.0" + "text/plain": [ + "6000.0" + ] }, "execution_count": 38, "metadata": {}, @@ -298,111 +356,121 @@ ], "source": [ "new_parameters = Parameters.from_json(\"my_parameters.json\")" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "markdown", - "source": [ - "### Look ath the photon energy of the restored parameters." - ], "metadata": { - "collapsed": false, "pycharm": { "name": "#%% md\n" } - } + }, + "source": [ + "### Look ath the photon energy of the restored parameters." + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "new_parameters.photon_energy" - ], "metadata": { "collapsed": false, + "jupyter": { + "outputs_hidden": false + }, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "new_parameters.photon_energy" + ] }, { "cell_type": "markdown", - "source": [ - "### Reconstruct the dumped calculator." - ], "metadata": { - "collapsed": false, "pycharm": { "name": "#%% md\n" } - } + }, + "source": [ + "### Reconstruct the dumped calculator." + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "reloaded_calculator = RandomImageCalculator(dumpfile=dumpfile)" - ], "metadata": { "collapsed": false, + "jupyter": { + "outputs_hidden": false + }, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "reloaded_calculator = RandomImageCalculator(dumpfile=dumpfile)" + ] }, { "cell_type": "markdown", - "source": [ - "### Query the data from the reconstructed calculator." - ], "metadata": { - "collapsed": false, "pycharm": { "name": "#%% md\n" } - } + }, + "source": [ + "### Query the data from the reconstructed calculator." + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [ - "reloaded_calculator.data" - ], "metadata": { "collapsed": false, + "jupyter": { + "outputs_hidden": false + }, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [ + "reloaded_calculator.data" + ] }, { "cell_type": "markdown", - "source": [ - "### Look at the photon energy of the reconstructed calculator." - ], "metadata": { - "collapsed": false, "pycharm": { "name": "#%% md\n" } - } + }, + "source": [ + "### Look at the photon energy of the reconstructed calculator." + ] }, { "cell_type": "code", "execution_count": 39, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + }, + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "data": { - "text/plain": "6000.0" + "text/plain": [ + "6000.0" + ] }, "execution_count": 39, "metadata": {}, @@ -411,32 +479,29 @@ ], "source": [ "reloaded_calculator.parameters.photon_energy\n" - ], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } + ] }, { "cell_type": "code", "execution_count": null, - "outputs": [], - "source": [], "metadata": { "collapsed": false, + "jupyter": { + "outputs_hidden": false + }, "pycharm": { "name": "#%%\n" } - } + }, + "outputs": [], + "source": [] } ], "metadata": { "kernelspec": { - "name": "pycharm-44f7cfec", + "display_name": "pyvinyl", "language": "python", - "display_name": "PyCharm (libpyvinyl)" + "name": "pyvinyl" }, "language_info": { "codemirror_mode": { @@ -448,9 +513,16 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.9.7" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": {}, + "version_major": 2, + "version_minor": 0 + } } }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} diff --git a/doc/source/include/refman.rst b/doc/source/include/refman.rst index 38cf3be..9f293e0 100644 --- a/doc/source/include/refman.rst +++ b/doc/source/include/refman.rst @@ -1,12 +1,22 @@ API Reference Manual ==================== -.. autoclass:: libpyvinyl.BaseCalculator +.. automodule:: libpyvinyl.BaseCalculator :members: :undoc-members: :show-inheritance: -.. autoclass:: libpyvinyl.Parameters +.. automodule:: libpyvinyl.Parameters.Collection :members: :undoc-members: - :show-inheritance: \ No newline at end of file + :show-inheritance: + +.. automodule:: libpyvinyl.Parameters.Parameter + :members: + :undoc-members: + :show-inheritance: + +.. automodule:: libpyvinyl.Instrument + :members: + :undoc-members: + :show-inheritance: diff --git a/libpyvinyl/AbstractBaseClass.py b/libpyvinyl/AbstractBaseClass.py index 475ff98..c5bf935 100644 --- a/libpyvinyl/AbstractBaseClass.py +++ b/libpyvinyl/AbstractBaseClass.py @@ -25,6 +25,7 @@ #################################################################################### from abc import ABCMeta, abstractmethod + class AbstractBaseClass(object, metaclass=ABCMeta): """ :class AbstractBaseClass: Base class of libpyvinyl @@ -33,4 +34,3 @@ class AbstractBaseClass(object, metaclass=ABCMeta): @abstractmethod def __init__(self): pass - diff --git a/libpyvinyl/BaseCalculator.py b/libpyvinyl/BaseCalculator.py index 12d5716..b914fa9 100644 --- a/libpyvinyl/BaseCalculator.py +++ b/libpyvinyl/BaseCalculator.py @@ -1,14 +1,14 @@ """ -:module BaseCalculator: Module hosting the BaseCalculator and Parameters classes. +:module BaseCalculator: Module hosting the BaseCalculator class. """ #################################################################################### # # -# This file is part of libpyvinyl - The APIs for Virtual Neutron and x-raY # +# This file is part of libpyvinyl - The APIs for Virtual Neutron and x-raY # # Laboratory. # # # -# Copyright (C) 2020 Carsten Fortmann-Grote # +# Copyright (C) 2021 Carsten Fortmann-Grote, Juncheng E # # # # This program is free software: you can redistribute it and/or modify it under # # the terms of the GNU Lesser General Public License as published by the Free # @@ -25,19 +25,22 @@ #################################################################################### from abc import abstractmethod -from libpyvinyl.AbstractBaseClass import AbstractBaseClass -from libpyvinyl.Parameters import CalculatorParameters +from typing import Union, Optional from tempfile import mkstemp import copy import dill -import h5py -import sys +from pathlib import Path import logging -import numpy import os -logging.basicConfig(format='%(asctime)s %(levelname)s:%(message)s', - level=logging.WARNING) +from libpyvinyl.AbstractBaseClass import AbstractBaseClass +from libpyvinyl.BaseData import BaseData, DataCollection +from libpyvinyl.Parameters import CalculatorParameters + + +logging.basicConfig( + format="%(asctime)s %(levelname)s:%(message)s", level=logging.WARNING +) class BaseCalculator(AbstractBaseClass): @@ -50,77 +53,293 @@ class BaseCalculator(AbstractBaseClass): This class is to be used as a base class for all calculators that implement a special simulation module, such as a photon diffraction calculator. Such a - specialized Calculator than has the same interface to the simulation - backengine as all other ViNyL Calculators. + specialized Calculator has the same interface to the simulation + backengine as all other ViNYL Calculators. + + A Complete example including a instrument and calculators can be found in + `test/integration/plusminus` """ - @abstractmethod - def __init__(self, name: str, parameters=None, dumpfile=None, **kwargs): + + def __init__( + self, + name: str, + input: Union[DataCollection, list, BaseData], + output_keys: Union[list, str], + output_data_types: list, + output_filenames: Union[list, str, None] = None, + instrument_base_dir: str = "./", + calculator_base_dir: str = "BaseCalculator", + parameters: CalculatorParameters = None, + ): """ - :param name: The name for this calculator. - :type name: str + :param name: The name of this calculator. + :type name: str + + :param name: The input of this calculator. It can be a `DataCollection`, + a list of `DataCollection`s or a single Data Object. + :type name: DataCollection, list or BaseData + + :param output_keys: The key(s) of this calculator's output data. It's a list of `str`s or + a single str. + :type output_keys: list or str + + :param output_data_types: The data type(s), i.e., classes, of each output. It's a list of the + data classes or a single data class. The available data classes are based on `BaseData`. + :type output_data_types: list or DataClass + + :param output_filenames: The name(s) of the output file(s). It can be a str of a filename or + a list of filenames. If the mapping is dict mapping, the name is `None`. Defaults to None. + :type output_filenames: list or str + + :param instrument_base_dir: The base directory for the instrument to which this calculator + belongs. Defaults to "./". The final exact output file path depends on `instrument_base_dir` + and `calculator_base_dir`: `instrument_base_dir`/`calculator_base_dir`/filename + :type instrument_base_dir: str + + :param calculator_base_dir: The base directory for this calculator. Defaults to "./". The final + exact output file path depends on `instrument_base_dir` and + `calculator_base_dir`: `instrument_base_dir`/`calculator_base_dir`/filename + :type instrument_base_dir: str :param parameters: The parameters for this calculator. :type parameters: Parameters - :param dumpfile: If given, load a previously dumped (aka pickled) calculator. + """ + # Initialize the variables + self.__name = None + self.__instrument_base_dir = None + self.__calculator_base_dir = None + self.__input = None + self.__output_keys = None + self.__output_data_types = None + self.__output_filenames = None + self.__parameters = None + + self.name = name + self.input = input + self.output_keys = output_keys + self.output_data_types = output_data_types + self.output_filenames = output_filenames + self.instrument_base_dir = instrument_base_dir + self.calculator_base_dir = calculator_base_dir + self.parameters = parameters + + self.__check_consistency() + # Create output data objects according to the output_data_classes + self.__init_output() + + def __check_consistency(self): + """Check the consistency of the input parameters""" + if len(self.output_keys) != len(self.output_data_types): + raise ValueError( + f"len(output_keys) = {len(self.output_keys)} is not equal to len(output_data_types) = {len(self.output_data_types)}" + ) + + def __check_output_filenames(self): + """Since output_filenames can be None for output in dict mapping, only check output_files when necessary""" + if len(self.output_data_types) != len(self.output_filenames): + raise ValueError( + f"len(output_filenames) = {len(self.output_filenames)} is not equal to len(output_data_types) = {len(self.output_data_types)}" + ) + + @property + def name(self) -> str: + return self.__name + + @name.setter + def name(self, value): + if isinstance(value, str): + self.__name = value + else: + raise TypeError( + f"Calculator: `name` is expected to be a str, not {type(value)}" + ) - :param kwargs: (key, value) pairs of further arguments to the calculator, e.g input_path, output_path. + @property + def parameters(self) -> CalculatorParameters: + return self.__parameters + + @parameters.setter + def parameters(self, value: CalculatorParameters): + self.set_parameters(value) + + def set_parameters(self, value: CalculatorParameters): + """Set the calculator parameters""" + if isinstance(value, CalculatorParameters): + self.__parameters = value + elif value is None: + self.init_parameters() + else: + raise TypeError( + f"Calculator: `parameters` is expected to be CalculatorParameters, not {type(value)}" + ) - If both 'parameters' and 'dumpfile' are given, the dumpfile is loaded - first. Passing a parameters object may be used to update some - parameters. + @property + def instrument_base_dir(self) -> str: + return self.__instrument_base_dir - Example: - ``` - # Define a specialized calculator. - class MyCalculator(BaseCalculator): + @instrument_base_dir.setter + def instrument_base_dir(self, value): + self.set_instrument_base_dir(value) - def __init__(self, parameters=None, dumpfile=None, **kwargs): - super()__init__(parameters, dumpfile, **kwargs) + def set_instrument_base_dir(self, value: str): + """Set the instrument base directory""" + if isinstance(value, str): + self.__instrument_base_dir = value + else: + raise TypeError( + f"Calculator: `instrument_base_dir` is expected to be a str, not {type(value)}" + ) - def backengine(self): - os.system("my_simulation_backengine_call") + @property + def calculator_base_dir(self) -> str: + return self.__calculator_base_dir - def saveH5(self): - # Format output into openpmd hdf5 format. + @calculator_base_dir.setter + def calculator_base_dir(self, value): + self.set_calculator_base_dir(value) - class MyParameters(Parameters): - pass + def set_calculator_base_dir(self, value: str): + """Set the calculator base directory""" + if isinstance(value, str): + self.__calculator_base_dir = value + else: + raise TypeError( + f"Calculator: `calculator_base_dir` is expected to be a str, not {type(value)}" + ) - my_calculator = MyCalculator(my_parameters) + @property + def input(self) -> DataCollection: + return self.__input + + @input.setter + def input(self, value): + self.set_input(value) + + def set_input(self, value: Union[DataCollection, list, BaseData, None]): + """Set the calculator input data. It can be a DataCollection, list or BaseData object.""" + if isinstance(value, (DataCollection, type(None))): + self.__input = value + elif isinstance(value, list): + self.__input = DataCollection(*value) + elif isinstance(value, BaseData): + self.__input = DataCollection(value) + else: + raise TypeError( + f"Calculator: `input` can be a DataCollection, list or BaseData object, and will be treated as a DataCollection. Your input type: {type(value)} is not accepted." + ) - my_calculator.backengine() + @property + def output_keys(self) -> list: + return self.__output_keys - my_calculator.saveH5("my_sim_output.h5") - my_calculater.dump("my_calculator.dill") - ``` + @output_keys.setter + def output_keys(self, value): + self.set_output_keys(value) - """ + @property + def base_dir(self): + """The base path for the output files of this calculator in consideration of instrument_base_dir and calculator_base_dir""" + base_dir = Path(self.instrument_base_dir) / self.calculator_base_dir + return str(base_dir) - if isinstance(name, str): - self.name = name + @property + def output_file_paths(self): + """The final output file paths considering base_dir""" + self.__check_output_filenames() + paths = [] + + for filename in self.output_filenames: + path = Path(self.base_dir) / filename + # Make sure the file directory exists + path.parent.mkdir(parents=True, exist_ok=True) + paths.append(str(path)) + return paths + + def set_output_keys(self, value: Union[list, str]): + """Set the calculator output keys. It can be a list of str or a single str.""" + if isinstance(value, list): + for item in value: + assert type(item) is str + self.__output_keys = value + elif isinstance(value, str): + self.__output_keys = [value] else: - raise TypeError("name should be in str type.") - # Set data - self.__data = None + raise TypeError( + f"Calculator: `output_keys` can be a list or str, and will be treated as a list. Your input type: {type(value)} is not accepted." + ) - if isinstance(parameters, (type(None), CalculatorParameters)): - self.parameters = parameters + @property + def output_data_types(self) -> list: + return self.__output_data_types + + @output_data_types.setter + def output_data_types(self, value): + self.set_output_data_types(value) + + def set_output_data_types(self, value: Union[list, BaseData]): + """Set the calculator output data type. It can be a list of DataClass or a single DataClass.""" + if isinstance(value, list): + for item in value: + assert issubclass(item, BaseData) + self.__output_data_types = value + elif issubclass(value, BaseData): + self.__output_data_types = [value] else: raise TypeError( - "parameters should be in CalculatorParameters type.") + f"Calculator: `output_data_types` can be a list or a subclass of BaseData, and will be treated as a list. Your input type: {type(value)} is not accepted." + ) - # Must load after setting paramters to avoid being overrode by empty parameters. - if dumpfile is not None: - self.__load_from_dump(dumpfile) + @property + def output_filenames(self) -> list: + return self.__output_filenames + + @output_filenames.setter + def output_filenames(self, value): + self.set_output_filenames(value) + + def set_output_filenames(self, value: Union[list, str, None]): + """Set the calculator output filenames. It can be a list of filenames or just a single str.""" + if isinstance(value, list): + for item in value: + assert type(item) is str or type(None) + self.__output_filenames = value + elif isinstance(value, (str, type(None))): + self.__output_filenames = [value] + else: + raise TypeError( + f"Calculator: `output_filenames` can be a list or just a str or None, and will be treated as a list. Your input type: {type(value)} is not accepted." + ) - if "output_path" in kwargs: - self.output_path = kwargs["output_path"] + @property + def output(self): + """The output of this calculator""" + return self.__output + + @property + def data(self): + """The alias of output. It's not recommended to use this variable name due to it's ambiguity.""" + return self.__output + + @abstractmethod + def init_parameters(self): + """Virtual method to initialize all parameters. Must be implemented on the + specialized class.""" + + raise NotImplementedError + + def __init_output(self): + """Create output data objects according to the output_data_types""" + output = DataCollection() + for i, key in enumerate(self.output_keys): + output_data = self.output_data_types[i](key) + output.add_data(output_data) + self.__output = output def __call__(self, parameters=None, **kwargs): - """ The copy constructor + """The copy constructor :param parameters: The parameters for the new calculator. :type parameters: CalculatorParameters @@ -135,51 +354,42 @@ def __call__(self, parameters=None, **kwargs): new.__dict__.update(kwargs) - if parameters is not None: + if parameters is None: + new.parameters = copy.deepcopy(new.parameters) + else: new.parameters = parameters - return new - def __load_from_dump(self, dumpfile): - """ """ - """ - Load a dill dump and initialize self's internals. + @classmethod + def from_dump(cls, dumpfile: str): + """Load a dill dump from a dumpfile. + :param dumpfile: The file name of the dumpfile. + :type dumpfile: str + :return: The calculator object restored from the dumpfile. + :rtype: CalcualtorClass """ - with open(dumpfile, 'rb') as fhandle: + with open(dumpfile, "rb") as fhandle: try: tmp = dill.load(fhandle) except: - raise IOError( - "Cannot load calculator from {}.".format(dumpfile)) + raise IOError("Cannot load calculator from {}.".format(dumpfile)) - self.__dict__ = copy.deepcopy(tmp.__dict__) + if not isinstance(tmp, cls): + raise TypeError(f"The object in the file {dumpfile} is not a {cls}") - del tmp - - @property - def parameters(self): - """ The parameters of this calculator. """ + return tmp - return self.__parameters - - @parameters.setter - def parameters(self, val): - - if not isinstance(val, (type(None), CalculatorParameters)): - raise TypeError( - """Passed argument 'parameters' has wrong type. Expected CalculatorParameters, found {}.""" - .format(type(val))) - - self.__parameters = val - - def dump(self, fname=None): + def dump(self, fname: Optional[str] = None) -> str: """ Dump class instance to file. :param fname: Filename (path) of the file to write. + :type fname: str + :return: The filename of the dumpfile + :rtype: str """ if fname is None: @@ -188,109 +398,14 @@ def dump(self, fname=None): prefix=self.__class__.__name__[-1], dir=os.getcwd(), ) - try: - with open(fname, "wb") as file_handle: - dill.dump(self, file_handle) - except: - raise + with open(fname, "wb") as file_handle: + dill.dump(self, file_handle) return fname - @abstractmethod - def saveH5(self, fname: str, openpmd: bool = True): - """ Save the simulation data to hdf5 file. - - :param fname: The filename (path) of the file to write the data to. - :type fname: str - - :param openpmd: Flag that controls whether the data is to be written in according to the openpmd metadata standard. Default is True. - - """ - - @property - def data(self): - return self.__data - - @data.setter - def data(self, val): - raise AttributeError("Attribute 'data' is read-only.") - @abstractmethod def backengine(self): - pass - - @classmethod - def run_from_cli(cls): - """ - Method to start calculator computations from command line. - - :return: exit with status code - - """ - if len(sys.argv) == 2: - fname = sys.argv[1] - calculator = cls(fname) - status = calculator._run() - sys.exit(status) - - def _run(self): - """ - Method to do computations. By default starts backengine. - - :return: status code. - - """ - result = self.backengine() - - if result is None: - result = 0 - - return result - - def _set_data(self, data): - """ """ - """ Private method to store the data on the object. - - :param data: The data to store. - - """ - - self.__data = data - - -# Mocks for testing. Have to be here to work around bug in dill that does not -# like classes to be defined outside of __main__. -class SpecializedCalculator(BaseCalculator): - def __init__(self, name, parameters=None, dumpfile=None, **kwargs): - - super().__init__(name, parameters, dumpfile, **kwargs) - - def setParams(self, photon_energy: float = 10, pulse_energy: float = 1e-3): - if not isinstance(self.parameters, CalculatorParameters): - self.parameters = CalculatorParameters() - self.parameters.new_parameter("photon_energy", - unit="eV", - comment="Photon energy") - self.parameters['photon_energy'].set_value(photon_energy) - - self.parameters.new_parameter("pulse_energy", - unit="joule", - comment="Pulse energy") - self.parameters['pulse_energy'].set_value(pulse_energy) - - def backengine(self): - self._BaseCalculator__data = numpy.random.normal( - loc=self.parameters['photon_energy'].value, - scale=0.001 * self.parameters['photon_energy'].value, - size=(100, )) - - return 0 - - def saveH5(self, openpmd=False): - with h5py.File(self.output_path, "w") as h5: - ds = h5.create_dataset("/data", data=self.data) - - h5.close() + raise NotImplementedError # This project has received funding from the European Union's Horizon 2020 research and innovation programme under grant agreement No. 823852. diff --git a/libpyvinyl/BaseData.py b/libpyvinyl/BaseData.py new file mode 100644 index 0000000..cb06948 --- /dev/null +++ b/libpyvinyl/BaseData.py @@ -0,0 +1,489 @@ +""" :module BaseData: Module hosts the BaseData class.""" +from typing import Union, Optional +from abc import abstractmethod, ABCMeta +from libpyvinyl.AbstractBaseClass import AbstractBaseClass + + +class BaseData(AbstractBaseClass): + """The abstract data class. Inheriting classes represent simulation input and/or output + data and provide a harmonized user interface to simulation data of various kinds rather than a data format. + Their purpose is to provide a harmonized user interface to common data operations such as reading/writing from/to disk. + + :param key: The key to identify the Data Object. + :type key: str + :param expected_data: A placeholder dict for expected data. The keys of this dict are expected to be found during the execution of `get_data()`. + The value for each key can be `None`. + :type expected_data: dict + :param data_dict: The dict to map by this DataClass. It has to be `None` if a file mapping was already set, defaults to None. + :type data_dict: dict, optional + :param filename: The filename of the file to map by this DataClass. It has to be `None` if a dict mapping was already set, defaults to None. + :type filename: str, optional + :param file_format_class: The FormatClass to map the file by this DataClass, It has to be `None` if a dict mapping was already set, defaults to None + :type file_format_class: class, optional + :param file_format_kwargs: The kwargs needed to map the file, defaults to None. + :type file_format_kwargs: dict, optional + """ + + def __init__( + self, + key: str, + expected_data: dict, + data_dict: Optional[dict] = None, + filename: Optional[str] = None, + file_format_class=None, + file_format_kwargs: Optional[dict] = None, + ): + self.__key = None + self.__expected_data = None + self.__data_dict = None + self.__filename = None + self.__file_format_class = None + self.__file_format_kwargs = None + + self.key = key + # Expected_data is checked when `self.get_data()` + self.expected_data = expected_data + # This will be always be None if the data class is mapped to a file + self.data_dict = data_dict + # These will be always be None if the data class is mapped to a python data dict object + self.filename = filename + self.file_format_class = file_format_class + self.file_format_kwargs = file_format_kwargs + + self.__check_consistency() + + @property + def key(self) -> str: + """The key of the class instance for calculator usage""" + return self.__key + + @key.setter + def key(self, value: str): + if isinstance(value, str): + self.__key = value + else: + raise TypeError(f"Data Class: key should be a str, not {type(value)}") + + @property + def expected_data(self): + """The expected_data of the class instance for calculator usage""" + return self.__expected_data + + @expected_data.setter + def expected_data(self, value): + if isinstance(value, dict): + self.__expected_data = value + else: + raise TypeError( + f"Data Class: expected_data should be a dict, not {type(value)}" + ) + + @property + def data_dict(self): + """The data_dict of the class instance for calculator usage""" + return self.__data_dict + + @data_dict.setter + def data_dict(self, value): + if isinstance(value, dict): + self.__data_dict = value + elif value is None: + self.__data_dict = None + else: + raise TypeError( + f"Data Class: data_dict should be None or a dict, not {type(value)}" + ) + self.__check_consistency() + + def set_dict(self, data_dict: dict): + """Set a mapping dict for this DataClass. + + :param data_dict: The data dict to map + :type data_dict: dict + """ + self.data_dict = data_dict + + def set_file(self, filename: str, format_class, **kwargs): + """Set a mapping file for this DataClass. + + :param filename: The filename of the file to map. + :type filename: str + :param format_class: The FormatClass to map the file + :type format_class: class + """ + self.filename = filename + self.file_format_class = format_class + self.file_format_kwargs = kwargs + self.__check_consistency() + + @property + def filename(self): + """The filename of the file to map by this DataClass.""" + return self.__filename + + @filename.setter + def filename(self, value): + if isinstance(value, str): + self.__filename = value + elif value is None: + self.__filename = None + else: + raise TypeError( + f"Data Class: filename should be None or a str, not {type(value)}" + ) + + @property + def file_format_class(self): + """The FormatClass to map the file by this DataClass""" + return self.__file_format_class + + @file_format_class.setter + def file_format_class(self, value): + if isinstance(value, ABCMeta): + self.__file_format_class = value + elif value is None: + self.__file_format_class = None + else: + raise TypeError( + f"Data Class: format_class should be None or a format class, not {type(value)}" + ) + + @property + def file_format_kwargs(self): + """The kwargs needed to map the file""" + return self.__file_format_kwargs + + @file_format_kwargs.setter + def file_format_kwargs(self, value): + if isinstance(value, dict): + self.__file_format_kwargs = value + elif value is None: + self.__file_format_kwargs = None + else: + raise TypeError( + f"Data Class: file_format_kwargs should be None or a dict, not {type(value)}" + ) + + @property + def mapping_type(self): + """If this data class is a file mapping or python dict mapping.""" + return self.__check_mapping_type() + + def __check_mapping_type(self): + """Check the mapping_type of this class.""" + if self.data_dict is not None: + return dict + elif self.filename is not None: + return self.file_format_class + else: + raise TypeError("Neither self.__data_dict or self.__filename was found.") + + @property + def mapping_content(self): + """Returns an overview of the keys of the mapped dict or the filename of the mapped file""" + if self.mapping_type == dict: + return self.data_dict.keys() + else: + return self.filename + + @staticmethod + def _add_ioformat(format_dict, format_class): + """Register an ioformat to a `format_dict` listing the formats supported by this DataClass. + + :param format_dict: The dict listing the supported formats. + :type format_dict: dict + :param format_class: The FormatClass to add. + :type format_class: class + """ + register = format_class.format_register() + for key, val in register.items(): + if key == "key": + this_format = val + format_dict[val] = {} + else: + format_dict[this_format][key] = val + + @classmethod + @abstractmethod + def supported_formats(self): + format_dict = {} + # Add the supported format classes when creating a concrete class. + # See the example at `tests/BaseDataTest.py` + self._add_ioformat(format_dict, FormatClass) + return format_dict + + @classmethod + def list_formats(self): + """Print supported formats""" + out_string = "" + supported_formats = self.supported_formats() + for key in supported_formats: + dicts = supported_formats[key] + format_class = dicts["format_class"] + if format_class: + out_string += "Format class: {}\n".format(format_class) + out_string += "Key: {}\n".format(key) + out_string += "Description: {}\n".format(dicts["description"]) + ext = dicts["ext"] + if ext != "": + out_string += "File extension: {}\n".format(ext) + kwargs = dicts["read_kwargs"] + if kwargs != [""]: + out_string += "Extra reading keywords: {}\n".format(kwargs) + kwargs = dicts["write_kwargs"] + if kwargs != [""]: + out_string += "Extra writing keywords: {}\n".format(kwargs) + out_string += "\n" + print(out_string) + + def __check_consistency(self): + # If all of the file-related parameters are set: + if all([self.filename, self.file_format_class]): + # If the data_dict is also set: + if self.data_dict is not None: + raise RuntimeError( + "self.data_dict and self.filename can not be set for one data class at the same time." + ) + else: + pass + # If any one of the file-related parameters is None: + elif ( + self.filename is None + and self.file_format_class is None + and self.file_format_kwargs is None + ): + pass + # If some of the file-related parameters is None and some is not None: + else: + raise RuntimeError( + "self.filename, self.file_format_class, self.file_format_kwargs are not consistent." + ) + + @classmethod + def from_file(cls, filename: str, format_class, key: dict, **kwargs): + """Create a Data Object mapping a file. + + :param filename: The filename of the file to map by this DataClass. It has to be `None` if a dict mapping was already set, defaults to None. + :type filename: str, optional + :param file_format_class: The FormatClass to map the file by this DataClass, It has to be `None` if a dict mapping was already set, defaults to None + :type file_format_class: class, optional + :param file_format_kwargs: The kwargs needed to map the file, defaults to None. + :type file_format_kwargs: dict, optional + :param key: The key to identify the Data Object. + :type key: str + + :return: A Data Object + :rtype: BaseData + """ + return cls( + key, + filename=filename, + file_format_class=format_class, + file_format_kwargs=kwargs, + ) + + @classmethod + def from_dict(cls, data_dict: dict, key: str): + """Create a Data Object mapping a data dict. + + :param data_dict: The dict to map by this DataClass. It has to be `None` if a file mapping was already set, defaults to None. + :type data_dict: dict + :param key: The key to identify the Data Object. + :type key: str + :return: A Data Object + :rtype: BaseData + """ + return cls(key, data_dict=data_dict) + + def write(self, filename: str, format_class, key: str = None, **kwargs): + """Write the data mapped by the Data Object into a file and return a Data Object + mapping the file. It converts either a file or a python object to a file + The behavior related to a file will always be handled by the format class. + If it's a python dictionary mapping, write with the specified format_class + directly. + + :param filename: The filename of the file to be written. + :type filename: str + :param file_format_class: The FormatClass to write the file. + :type file_format_class: class + :param key: The identification key of the new Data Object. When it's `None`, a new key will + be generated with a suffix added to the previous identification key by the FormatClass. Defaults to None. + :type key: str, optional + :return: A Data Object + :rtype: BaseData + """ + if self.mapping_type == dict: + return format_class.write(self, filename, key, **kwargs) + elif format_class in self.file_format_class.direct_convert_formats(): + return self.file_format_class.convert( + self, filename, format_class, key, **kwargs + ) + # If it's a file mapping and would like to write in the same file format of the + # mapping, it will let the user know that a file containing the data in the same format already existed. + elif format_class == self.file_format_class: + print( + f"Hint: This data already existed in the file {self.__filename} in format {self.__file_format_class}. `cp {self.__filename} {filename}` could be faster." + ) + print( + f"Will still write the data into the file {filename} in format {format_class}" + ) + return format_class.write(self, filename, key, **kwargs) + else: + return format_class.write(self, filename, key, **kwargs) + + def __check_for_expected_data(self, data_to_read): + """Check if the `data_to_read` contains the data we have""" + for key in self.expected_data.keys(): + try: + data_to_read[key] + except KeyError: + raise KeyError( + f"Expected data dict key '{key}' is not found." + ) from None + + def __get_dict_data(self): + """Get the data dict from a dict mapping""" + if self.__data_dict is not None: + # It will automatically check the data needed to be extracted. + self.__check_for_expected_data(self.__data_dict) + return self.data_dict + else: + raise RuntimeError( + "__get_dict_data() should not be called when self.__data_dict is None" + ) + + def __get_file_data(self): + """Get the data dict from a file mapping""" + if self.__filename is not None: + data_to_read = self.__file_format_class.read( + self.__filename, **self.__file_format_kwargs + ) + # It will automatically check the data needed to be extracted. + self.__check_for_expected_data(data_to_read) + data_to_return = {} + for key in data_to_read.keys(): + data_to_return[key] = data_to_read[key] + return data_to_return + else: + raise RuntimeError( + "__get_file_data() should not be called when self.__filename is None" + ) + + def get_data(self): + """Return the data in a dictionary""" + # From either a file or a python object to a python object + if self.__data_dict is not None: + return self.__get_dict_data() + elif self.__filename is not None: + return self.__get_file_data() + + def __str__(self): + """Returns strings of Data objects info""" + string = f"key = {self.key}\n" + string += f"mapping = {self.mapping_type}: {self.mapping_content}" + return string + + +# DataCollection class +class DataCollection: + """A collection of Data Objects""" + + def __init__(self, *args): + self.data_object_dict = {} + self.add_data(*args) + + def __len__(self): + return len(self.data_object_dict) + + def __setitem__(self, key, value): + if key != value.key: + print( + f"Warning: the key '{key}' of this DataCollection will be replaced by the key '{value.key}' set in the input data." + ) + del self.data_object_dict[key] + self.add_data(value) + + def __getitem__(self, keys): + if isinstance(keys, str): + return self.get_data_object(keys) + elif isinstance(keys, list): + subset = [] + for key in keys: + subset.append(self.get_data_object(key)) + return DataCollection(*subset) + + def add_data(self, *args): + """Add data objects to the data colletion""" + for data in args: + assert isinstance(data, BaseData) + self.data_object_dict[data.key] = data + + def get_data(self): + """Get the data of the data object(s). + When there is only one item in the DataCollection, it returns the data dict, + When there are more then one items, it returns a dictionary of the data dicts""" + if len(self.data_object_dict) == 1: + return next(iter(self.data_object_dict.values())).get_data() + else: + data_dicts = {} + for key, obj in self.data_object_dict.items(): + data_dicts[key] = obj.get_data() + return data_dicts + + def write( + self, + filename: Union[str, dict], + format_class, + key: Union[str, dict] = None, + **kwargs, + ): + """Write the data object(s) to the file(s). + When there is only one item in the DataCollection, it returns the data object mapping the file which was wirttern, + When there are more then one items, it returns a dictionary of the data objects. + + :param filename: The name(s) of the file(s) to write. When there are multiple items, they are expected in + a dict where the keys corresponding to the data in this collection. + :type filename: str or dict + :param format_class: The format class of the file(s). When there are multiple items, they are expected in + a dict where the keys corresponding to the data in this collection. + :type format_class: class or dict + :param key: The key(s) of the data object(s) mapping the written file(s), defaults to None. + :type key: str or dict, optional + :return: A data object or a dict of data objects. + :rtype: DataClass or dict + """ + + if len(self.data_object_dict) == 1: + obj = next(iter(self.data_object_dict.values())) + return obj.write(filename, format_class, key, **kwargs) + else: + assert isinstance(key, dict) + data_dicts = {} + for col_key, obj in self.data_object_dict.items(): + written_data = obj.write( + filename[col_key], format_class[col_key], key[col_key], **kwargs + ) + data_dicts[written_data.key] = written_data + return data_dicts + + def get_data_object(self, key: str): + """Get one data object by its key + + :param key: The key of the data object to get. + :type key: str + :return: A data object + :rtype: DataClass + """ + return self.data_object_dict[key] + + def to_list(self): + """Return a list of the data objects in the data collection""" + return [value for value in self.data_object_dict.values()] + + def __str__(self): + """Returns strings of the data object info""" + string = "Data collection:\n" + string += "key - mapping\n\n" + for data_object in self.data_object_dict.values(): + string += f"{data_object.key} - {data_object.mapping_type}: {data_object.mapping_content}\n" + return string diff --git a/libpyvinyl/BaseFormat.py b/libpyvinyl/BaseFormat.py new file mode 100644 index 0000000..abdaac3 --- /dev/null +++ b/libpyvinyl/BaseFormat.py @@ -0,0 +1,109 @@ +from abc import abstractmethod +from libpyvinyl.AbstractBaseClass import AbstractBaseClass +from libpyvinyl.BaseData import BaseData + + +class BaseFormat(AbstractBaseClass): + """The abstract format class. It's the interface of a certain data format.""" + + def __init__(self): + # Nothing needs to be done here. + pass + + @classmethod + @abstractmethod + def format_register(self): + # Override this `format_register` method in a concrete format class. + key = "Base" + desciption = "Base data format" + file_extension = "base" + read_kwargs = [""] + write_kwargs = [""] + return self._create_format_register( + key, desciption, file_extension, read_kwargs, write_kwargs + ) + + @classmethod + def _create_format_register( + cls, + key: str, + desciption: str, + file_extension: str, + read_kwargs=[""], + write_kwargs=[""], + ): + format_register = { + "key": key, # FORMAT KEY + "description": desciption, # FORMAT DESCRIPTION + "ext": file_extension, # FORMAT EXTENSION + "format_class": cls, # CLASS NAME OF THE FORMAT + "read_kwargs": read_kwargs, # KEYWORDS LIST NEEDED TO READ + "write_kwargs": write_kwargs, # KEYWORDS LIST NEEDED TO WRITE + } + return format_register + + @classmethod + @abstractmethod + def read(self, filename: str, **kwargs) -> dict: + """Read the data from the file with the `filename` to a dictionary. The dictionary will + be used by its corresponding data class.""" + # Example codes. Override this function in a concrete class. + data_dict = {} + with h5py.File(filename, "r") as h5: + for key, val in h5.items(): + data_dict[key] = val[()] + return data_dict + + @classmethod + @abstractmethod + def write(cls, object: BaseData, filename: str, key: str, **kwargs): + """Save the data with the `filename`.""" + # Example codes. Override this function in a concrete class. + data_dict = object.get_data() + arr = np.array([data_dict["number"]]) + np.savetxt(filename, arr, fmt="%.3f") + if key is None: + original_key = object.key + key = original_key + "_to_TXTFormat" + return object.from_file(filename, cls, key) + else: + return object.from_file(filename, cls, key) + + @staticmethod + @abstractmethod + def direct_convert_formats(): + # Assume the format can be converted directly to the formats supported by these classes: + # AFormat, BFormat + # Override this `direct_convert_formats` in a concrete format class + return [Aformat, BFormat] + + @classmethod + @abstractmethod + def convert( + cls, obj: BaseData, output: str, output_format_class: str, key, **kwargs + ): + """Direct convert method, if the default converting would be too slow or not suitable for the output_format""" + # If there is no direct converting supported: + raise NotImplementedError + if output_format_class is AFormat: + return cls.convert_to_AFormat(obj.filename, output) + else: + raise TypeError( + "Direct converting to format {} is not supported".format( + output_format_class + ) + ) + # Set the key of the returned object + if key is None: + original_key = obj.key + key = original_key + "_from_BaseFormat" + return obj.from_file(output, output_format_class, key) + + # Example convert_to_AFormat() + # @classmethod + # def convert_to_AFormat(cls, input: str, output: str): + # """The engine of convert method.""" + # print("Directly converting BaseFormat to AFormat") + # number = float(np.loadtxt(input)) + # with h5py.File(output, "w") as h5: + # h5["number"] = number diff --git a/libpyvinyl/BeamlinePropagator.py b/libpyvinyl/BeamlinePropagator.py deleted file mode 100644 index b5f3193..0000000 --- a/libpyvinyl/BeamlinePropagator.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -:module BeamlinePropagator: Module hosting the BeamlinePropagator and BeamlinePropagatorParameters -abstract classes. -""" - - -#################################################################################### -# # -# This file is part of libpyvinyl - The APIs for Virtual Neutron and x-raY # -# Laboratory. # -# # -# Copyright (C) 2020 Carsten Fortmann-Grote # -# # -# This program is free software: you can redistribute it and/or modify it under # -# the terms of the GNU Lesser General Public License as published by the Free # -# Software Foundation, either version 3 of the License, or (at your option) any # -# later version. # -# # -# This program is distributed in the hope that it will be useful, but WITHOUT ANY # -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # -# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # -# # -# You should have received a copy of the GNU Lesser General Public License along # -# with this program. If not, see str: + """Returning the units as a string""" + return str(self.__unit) + + @unit.setter + def unit(self, uni): """ - Sets a legal interval for this parameter, None for infinite + Assignment of the units + + A pint.Unit is used if the string is recognized as a valid unit in the registry. + It is stored as a string otherwise. """ - if min_value is None: - min_value = -math.inf - if max_value is None: - max_value = math.inf + try: + self.__unit = Unit(uni) + except pint.errors.UndefinedUnitError: + self.__unit = uni + + @property + def value_no_conversion(self): + """ + Returning the object stored in value with no conversions + """ + return self.__value + + @property + def pint_value(self): + """Returning the value as a pint object if available, an error otherwise""" + if not isinstance(self.__value, Quantity): + raise TypeError("The parameter value is not of pint.Quantity type") + return self.__value + + @property + def value(self): + if isinstance(self.__value, Quantity): + return self.__value.m_as(self.__unit) + else: + return self.__value + + @staticmethod + def __is_type_compatible(t1: type, t2: Union[None, type]) -> bool: + """ + Check type compatibility + + :param t1: first type + :type t1: type + + :param t2: second type + :type t2: type + + :return: bool + + True if t1 and t2 are of the same type or if one is int and the other float + False otherwise + """ + if t1 == type(None) or t2 == type(None): + return True + if t1 == None or t2 == None: + return True + + # promote any int or float to pint.Quantity + if t1 == float or t1 == int or t1 == numpy.float64: + t1 = Quantity + if t2 == float or t2 == int or t2 == numpy.float64: + t2 = Quantity + + if "quantity" in str(t1): + t1 = Quantity + if "quantity" in str(t2): + t2 = Quantity + + if t1 == t2: + return True + + return False + + def __to_quantity(self, value: Any) -> Union[Quantity, Any]: + """ + Converts value into a pint.Quantity if this Parameter is defined to be a Quantity. + It returns value unaltered otherwise. + """ + + if self.__value_type == Quantity and not isinstance(value, Quantity): + return Quantity(value, self.__unit) + + return value + + def __set_value_type(self, value: Any) -> None: + """ + Sets the type for the parameter. + It should always be preceded by a __check_compatibility to avoid chaning the type for the Parameter - self.legal_intervals.append([min_value, max_value]) + :param value: a value that might be assigned as Parameter value or in an interval or option + :type value: any type - def add_illegal_interval(self, min_value, max_value): + It will raise an exception if the type is not coherent to what previously is declared. """ - Sets an illegal interval for this parameter, None for infinite + if ( + hasattr(value, "__iter__") + and not isinstance(value, str) + and not isinstance(value, Quantity) + ): + value = value[0] + + # if an integer has units, then it is a quantity -> promotion + if isinstance(value, int) and self.__unit != "": + self.__value_type = Quantity + # if value is a float, than can be used as a quantity -> promotion + elif isinstance(value, float): + self.__value_type = Quantity + else: # cannot be treated as a quantity + self.__value_type = type(value) + + def __check_compatibility(self, value: Any) -> None: """ + Raises an error if this parameter and the given value are not of the same type or compatible + :param value: a value that might be assigned as Parameter value or in an interval or option + :type value: any type + + It will raise an exception if the type is not coherent to what previously is declared. + """ + + vtype = type(value) + assert vtype != None + v = value + # First case: value is a list, it might be good to double check + # that all the members are of the same type + if isinstance(value, list): + vtype = type(value[0]) + for v in value: + if not self.__is_type_compatible(vtype, type(v)): + raise TypeError( + "Iterable object passed as value for the parameter, but it is made of inhomogeneous types: ", + vtype, + type(v), + ) + elif isinstance(value, dict): + raise NotImplementedError("Dictionaries are not accepted") + + # check that the value is compatible with what previously defined + if not self.__is_type_compatible(vtype, self.__value_type): + raise TypeError( + "New value of type {} is different from {} previously defined".format( + type(value), self.__value_type + ) + ) + + @value.setter + def value(self, value): + """ + Sets value of this parameter if value is legal, + an exception is raised otherwise. + + :param value: value + :type value: str | boolean | int | float | object | pint.Quantity + If value is a float, it is internally converted to a pint.Quantity + """ + self.__check_compatibility(value) + self.__set_value_type(value) + value = self.__to_quantity(value) + + if self.is_legal(value): + self.__value = value + else: + raise ValueError("Value of parameter '" + self.name + "' illegal.") + + def add_interval(self, min_value, max_value, intervals_are_legal): + """ + Sets an interval for this parameter: [min_value, max_value] + The interval is closed on both sides: min_value and and max_value are included. + + :param min_value: minimum value of the interval + :type min_value: float or None for infinite + + :param max_value: maximum value of the interval + :type max_value: float or None for infinite + + :param intervals_are_legal: if not done previously, it defines if all the intervals of this parameter should be considered as allowed or forbidden intervals. + :type intervals_are_legal: boolean + + """ + if min_value is None: min_value = -math.inf if max_value is None: max_value = math.inf - self.illegal_intervals.append([min_value, max_value]) + self.__check_compatibility(min_value) + self.__check_compatibility(max_value) + + self.__set_value_type(min_value) # it could have been max_value - def add_option(self, option): + if self.__intervals_are_legal is None: + self.__intervals_are_legal = intervals_are_legal + else: + if self.__intervals_are_legal != intervals_are_legal: + print("WARNING: All intervals should be either legal or illegal.") + print( + " Interval: [" + + str(min_value) + + ":" + + str(max_value) + + "] is declared differently w.r.t. to the previous intervals" + ) + # should it throw an expection? + raise ValueError("Parameter", "interval", "multiple validities") + + self.__intervals.append( + [self.__to_quantity(min_value), self.__to_quantity(max_value)] + ) + + # if the interval has been added after assignement of the value of the parameter, + # the latter should be checked + if not self.value_no_conversion is None: + if self.is_legal(self.value) is False: + raise ValueError( + "Value " + + str(self.value) + + " is now illegal based on the newly added interval" + ) + + def add_option(self, option, options_are_legal): """ Sets allowed values for this parameter """ - if isinstance(option, list): - self.options += option + + if self.__options_are_legal is None: + self.__options_are_legal = options_are_legal else: - self.options.append(option) + if self.__options_are_legal != options_are_legal: + print("ERROR: All options should be either legal or illegal.") + print( + " This option is declared differently w.r.t. to the previous ones" + ) + # should it throw an expection? + raise ValueError("Parameter", "options", "multiple validities") - def set_value(self, value): - """ - Sets value of this parameter if value is legal, otherwise warning is shown + self.__check_compatibility(option) + self.__set_value_type(option) # it could have been max_value - This could be expanded to raise an exception, or such could be in is_legal - """ - if self.is_legal(value): - self.value = value + if isinstance(option, list): + for op in option: + self.__options.append(self.__to_quantity(op)) else: - print("WARNING: Value of parameter '" + self.name - + "' illegal, ignored.") - - def is_legal(self, value=None): + self.__options.append(self.__to_quantity(option)) + + # if the option has been added after assignement of the value of the parameter, + # the latter should be checked + if not self.value_no_conversion is None: + if self.is_legal(self.value) is False: + raise ValueError( + "Value " + + str(self.value) + + " is now illegal based on the newly added option" + ) + + def is_legal(self, values=None): """ Checks whether or not given or contained value is legal given constraints. - Illegal intervals have the highest priority to be checked. Then it will check the - legal intervals and options. The overlaps among the constrains will be overridden by - the constrain of higher priority. """ - if value is None: - value = self.value - # Check illegal intervals - for illegal_interval in self.illegal_intervals: - if illegal_interval[0] < value < illegal_interval[1]: - return False + if values is None: + values = self.__value - # Check legal intervals - is_inside_a_legal_interval = False - for legal_interval in self.legal_intervals: - if legal_interval[0] < value < legal_interval[1]: - is_inside_a_legal_interval = True + if ( + not hasattr(values, "__iter__") + or isinstance(values, str) + or isinstance(values, Quantity) + ): + # print(str(hasattr(values, "__iter__")) + str(values)) + # first if types are compatible - if not is_inside_a_legal_interval and len(self.legal_intervals) > 0: - return False + if self.__is_type_compatible(type(values), self.__value_type) is False: + return False - # checked intervals, can return if options not used (frequent case) - if len(self.options) == 0: - return True + value = self.__to_quantity(values) - for option in self.options: - if option == value: - # If the value matches any option, it is legal + # obvious, if no conditions are defined, the value is always legal + if len(self.__options) == 0 and len(self.__intervals) == 0: return True - # Since no options matched the parameter, it is illegal - return False + # first check if the value is in any defined discrete value + for option in self.__options: + if option == value: + return self.__options_are_legal + + # secondly check if it is in any defined interval + for interval in self.__intervals: + if interval[0] <= value <= interval[1]: + return self.__intervals_are_legal + + # at this point the value has not been found in any interval + # if intervals where defined and were forbidden intervals, the value should be accepted + if len(self.__intervals) > 0: + return not self.__intervals_are_legal + + # if there where no intervals defined, then it depends if the discrete values were forbidden or allowed + return not self.__options_are_legal + + # else + # all values have to be True + + for value in values: + if not self.is_legal(value): + return False + + return True def print_paramter_constraints(self): """ - Print the legal and illegal intervals of this parameter. + Print the legal and illegal intervals of this parameter. FIXME """ print(self.name) - print('illegal intervals:', self.illegal_intervals) - print('legal intervals:', self.legal_intervals) - print('options', self.options) + print("intervals:", self.__intervals) + print("intervals are legal:", self.__intervals_are_legal) + print("options", self.__options) + print("options are legal:", self.__options_are_legal) - def clear_legal_intervals(self): + def clear_intervals(self): """ - Clear the legal intervals of this parameter. + Clear the intervals of this parameter. """ - self.legal_intervals = [] - - def clear_illegal_intervals(self): - """ - Clear the illegal intervals of this parameter. - """ - self.illegal_intervals = [] + self.__intervals = [] def clear_options(self): """ Clear the option values of this parameter. """ - self.options = [] + self.__options = [] def print_line(self): """ returns string with one line description of parameter """ - if self.unit is None: + if self.__unit is None or self.__unit == Unit(""): unit_string = "" else: - unit_string = "[" + self.unit + "]" + unit_string = "[" + str(self.__unit) + "] " - if self.value is None: - string = self.name.ljust(20) + if self.value_no_conversion is None: + string = self.name.ljust(40) + " " else: - string = self.name.ljust(15) - string += str(self.value).ljust(5) + string = self.name.ljust(35) + " " + string += str(self.value).ljust(10) + " " - string += unit_string.ljust(10) + string += unit_string.ljust(20) + " " if self.comment is not None: string += self.comment string += 3 * " " - for legal_interval in self.legal_intervals: - interval = "L[" + str(legal_interval[0]) + ", " + str( - legal_interval[1]) + "]" - string += interval.ljust(10) - - for illegal_interval in self.illegal_intervals: - interval = "I[" + str(illegal_interval[0]) + ", " + str( - illegal_interval[1]) + "]" + for interval in self.__intervals: + legal = "L" if self.__intervals_are_legal else "I" + interval = legal + "[" + str(interval[0]) + ", " + str(interval[1]) + "]" string += interval.ljust(10) - if len(self.options) > 0: + if len(self.__options) > 0: values = "(" - for option in self.options: + for option in self.__options: values += str(option) + ", " values = values.strip(", ") values += ")" @@ -180,32 +454,29 @@ def __repr__(self): Returns string with thorough description of parameter """ string = "Parameter named: '" + self.name + "'" - if self.value is None: + if self.value_no_conversion is None: string += " without set value.\n" else: string += " with value: " + str(self.value) + "\n" - if self.unit is not None: - string += " [" + self.unit + "]\n" + if self.__unit is not None: + string += " [" + str(self.__unit) + "]\n" if self.comment is not None: string += " " + self.comment + "\n" - if len(self.legal_intervals) > 0: - string += " Legal intervals:\n" - for legal_interval in self.legal_intervals: - string += " [" + str(legal_interval[0]) + "," + str( - legal_interval[1]) + "]\n" - - if len(self.illegal_intervals) > 0: - string += " Illegal intervals:\n" - for illegal_interval in self.illegal_intervals: - string += " [" + str(illegal_interval[0]) + ", " + str( - illegal_interval[1]) + "]\n" - - if len(self.options) > 0: - string += " Allowed values:\n" - for option in self.options: + if len(self.__intervals) > 0: + string += ( + " Legal intervals:\n" + if self.__intervals_are_legal + else " Illegal intervals:\n" + ) + for interval in self.__intervals: + string += " [" + str(interval[0]) + "," + str(interval[1]) + "]\n" + + if len(self.__options) > 0: + string += " Allowed values:\n" # FIXME + for option in self.__options: string += " " + str(option) + "\n" return string diff --git a/libpyvinyl/Parameters/__init__.py b/libpyvinyl/Parameters/__init__.py index b6f1c9a..3f66957 100644 --- a/libpyvinyl/Parameters/__init__.py +++ b/libpyvinyl/Parameters/__init__.py @@ -1,2 +1,2 @@ from .Parameter import Parameter -from .Collections import InstrumentParameters, CalculatorParameters, MasterParameter \ No newline at end of file +from .Collections import InstrumentParameters, CalculatorParameters, MasterParameter diff --git a/libpyvinyl/SignalGenerator.py b/libpyvinyl/SignalGenerator.py deleted file mode 100644 index 2a5304b..0000000 --- a/libpyvinyl/SignalGenerator.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -:module SignalGenerator: Module hosting the SignalGenerator and SignalGeneratorParameters -abstract classes. -""" - - -#################################################################################### -# # -# This file is part of libpyvinyl - The APIs for Virtual Neutron and x-raY # -# Laboratory. # -# # -# Copyright (C) 2020 Carsten Fortmann-Grote # -# # -# This program is free software: you can redistribute it and/or modify it under # -# the terms of the GNU Lesser General Public License as published by the Free # -# Software Foundation, either version 3 of the License, or (at your option) any # -# later version. # -# # -# This program is distributed in the hope that it will be useful, but WITHOUT ANY # -# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # -# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # -# # -# You should have received a copy of the GNU Lesser General Public License along # -# with this program. If not, see OK <---') - sys.exit(0) - - sys.exit(1) diff --git a/tests/integration/plusminus/.github/ISSUE_TEMPLATE.md b/tests/integration/plusminus/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..92fcec9 --- /dev/null +++ b/tests/integration/plusminus/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,15 @@ +* PlusMinus version: +* Python version: +* Operating System: + +### Description + +Describe what you were trying to get done. +Tell us what happened, what went wrong, and what you expected to happen. + +### What I Did + +``` +Paste the command(s) you ran and the output. +If there was a crash, please include the traceback here. +``` diff --git a/tests/integration/plusminus/.gitignore b/tests/integration/plusminus/.gitignore new file mode 100644 index 0000000..43091aa --- /dev/null +++ b/tests/integration/plusminus/.gitignore @@ -0,0 +1,105 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# dotenv +.env + +# virtualenv +.venv +venv/ +ENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +# IDE settings +.vscode/ \ No newline at end of file diff --git a/tests/integration/plusminus/README.rst b/tests/integration/plusminus/README.rst new file mode 100644 index 0000000..f362d3b --- /dev/null +++ b/tests/integration/plusminus/README.rst @@ -0,0 +1,18 @@ +========= +PlusMinus +========= + +An example of a small platform implementing libpyvinyl. + +Data structure +############## +.. image:: ./docs/01-data_structure.png + +Instrument example +################## +.. image:: ./docs/02-instrument_example.png + +This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template. + +.. _Cookiecutter: https://github.com/audreyr/cookiecutter +.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage diff --git a/tests/integration/plusminus/docs/01-data_structure.png b/tests/integration/plusminus/docs/01-data_structure.png new file mode 100644 index 0000000000000000000000000000000000000000..39778312df45756357840344dc5859542a6c8dc4 GIT binary patch literal 218354 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⁡Hv$^o!NLb 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/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 X9mGUDqg6;Cz&|N5Inj!b1_A#c{HvL& literal 0 HcmV?d00001 diff --git a/tests/integration/plusminus/docs/02-instrument_example.png b/tests/integration/plusminus/docs/02-instrument_example.png new file mode 100644 index 0000000000000000000000000000000000000000..391311c8a6629ee0b742b55502baeca4271a861e GIT binary patch literal 171726 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≺rD*vB)+yYfKw35>iiz-` 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ⅅ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 literal 0 HcmV?d00001 diff --git a/tests/integration/plusminus/plusminus/ArrayCalculators/ArrayCalculator.py b/tests/integration/plusminus/plusminus/ArrayCalculators/ArrayCalculator.py new file mode 100644 index 0000000..c2f66de --- /dev/null +++ b/tests/integration/plusminus/plusminus/ArrayCalculators/ArrayCalculator.py @@ -0,0 +1,59 @@ +from typing import Union +from pathlib import Path +import numpy as np +from libpyvinyl.BaseData import DataCollection +from libpyvinyl.BaseCalculator import BaseCalculator, CalculatorParameters +from plusminus.NumberData import NumberData +from plusminus.ArrayData import ArrayData + + +class ArrayCalculator(BaseCalculator): + def __init__( + self, + name: str, + input: Union[DataCollection, list, NumberData], + output_keys: Union[list, str] = ["array_result"], + output_data_types=[ArrayData], + output_filenames=[], + instrument_base_dir="./", + calculator_base_dir="ArrayCalculator", + parameters: CalculatorParameters = None, + ): + """A python dict calculator to create an array from two inputs.""" + super().__init__( + name, + input, + output_keys, + output_data_types=output_data_types, + output_filenames=output_filenames, + instrument_base_dir=instrument_base_dir, + calculator_base_dir=calculator_base_dir, + parameters=parameters, + ) + + def init_parameters(self): + parameters = CalculatorParameters() + # Calculator developer edit + multiply = parameters.new_parameter( + "multiply", comment="Multiply the array by a value" + ) + multiply.value = 1 + # Calculator developer end + self.parameters = parameters + + def backengine(self): + Path(self.base_dir).mkdir(parents=True, exist_ok=True) + input_data0 = self.input.to_list()[0] + assert type(input_data0) is NumberData + input_num0 = input_data0.get_data()["number"] + input_data1 = self.input.to_list()[1] + assert type(input_data1) is NumberData + input_num1 = input_data1.get_data()["number"] + output_arr = ( + np.array([input_num0, input_num1]) * self.parameters["multiply"].value + ) + data_dict = {"array": output_arr} + key = self.output_keys[0] + output_data = self.output[key] + output_data.set_dict(data_dict) + return self.output diff --git a/tests/integration/plusminus/plusminus/ArrayCalculators/__init__.py b/tests/integration/plusminus/plusminus/ArrayCalculators/__init__.py new file mode 100644 index 0000000..6f13f6f --- /dev/null +++ b/tests/integration/plusminus/plusminus/ArrayCalculators/__init__.py @@ -0,0 +1 @@ +from .ArrayCalculator import ArrayCalculator diff --git a/tests/integration/plusminus/plusminus/ArrayData/ArrayData.py b/tests/integration/plusminus/plusminus/ArrayData/ArrayData.py new file mode 100644 index 0000000..1e196af --- /dev/null +++ b/tests/integration/plusminus/plusminus/ArrayData/ArrayData.py @@ -0,0 +1,36 @@ +from libpyvinyl.BaseData import BaseData +from plusminus.ArrayData import TXTFormat, H5Format + + +class ArrayData(BaseData): + def __init__( + self, + key, + data_dict=None, + filename=None, + file_format_class=None, + file_format_kwargs=None, + ): + + ### DataClass developer's job start + expected_data = {} + expected_data["array"] = None + ### DataClass developer's job end + + super().__init__( + key, + expected_data, + data_dict, + filename, + file_format_class, + file_format_kwargs, + ) + + @classmethod + def supported_formats(self): + format_dict = {} + ### DataClass developer's job start + self._add_ioformat(format_dict, TXTFormat) + self._add_ioformat(format_dict, H5Format) + ### DataClass developer's job end + return format_dict diff --git a/tests/integration/plusminus/plusminus/ArrayData/H5Format.py b/tests/integration/plusminus/plusminus/ArrayData/H5Format.py new file mode 100644 index 0000000..4155f19 --- /dev/null +++ b/tests/integration/plusminus/plusminus/ArrayData/H5Format.py @@ -0,0 +1,47 @@ +import h5py +from libpyvinyl.BaseFormat import BaseFormat +from plusminus.ArrayData import ArrayData + + +class H5Format(BaseFormat): + def __init__(self) -> None: + super().__init__() + + @classmethod + def format_register(self): + key = "H5" + desciption = "H5 format for ArrayData" + file_extension = ".h5" + read_kwargs = [""] + write_kwargs = [""] + return self._create_format_register( + key, desciption, file_extension, read_kwargs, write_kwargs + ) + + @staticmethod + def direct_convert_formats(): + # Assume the format can be converted directly to the formats supported by these classes: + # AFormat, BFormat + # Redefine this `direct_convert_formats` for a concrete format class + return [] + + @classmethod + def read(cls, filename: str) -> dict: + """Read the data from the file with the `filename` to a dictionary. The dictionary will + be used by its corresponding data class.""" + with h5py.File(filename, "r") as h5: + array = h5["array"][()] + data_dict = {"array": array} + return data_dict + + @classmethod + def write(cls, object: ArrayData, filename: str, key: str = None): + """Save the data with the `filename`.""" + data_dict = object.get_data() + array = data_dict["array"] + with h5py.File(filename, "w") as h5: + h5["array"] = array + if key is None: + original_key = object.key + key = original_key + "_to_H5Format" + return object.from_file(filename, cls, key) diff --git a/tests/integration/plusminus/plusminus/ArrayData/TXTFormat.py b/tests/integration/plusminus/plusminus/ArrayData/TXTFormat.py new file mode 100644 index 0000000..b0454f1 --- /dev/null +++ b/tests/integration/plusminus/plusminus/ArrayData/TXTFormat.py @@ -0,0 +1,45 @@ +import numpy as np +from libpyvinyl.BaseFormat import BaseFormat +from plusminus.ArrayData import ArrayData + + +class TXTFormat(BaseFormat): + def __init__(self) -> None: + super().__init__() + + @classmethod + def format_register(self): + key = "TXT" + desciption = "TXT format for ArrayData" + file_extension = ".txt" + read_kwargs = [""] + write_kwargs = [""] + return self._create_format_register( + key, desciption, file_extension, read_kwargs, write_kwargs + ) + + @staticmethod + def direct_convert_formats(): + # Assume the format can be converted directly to the formats supported by these classes: + # AFormat, BFormat + # Redefine this `direct_convert_formats` for a concrete format class + return [] + + @classmethod + def read(cls, filename: str) -> dict: + """Read the data from the file with the `filename` to a dictionary. The dictionary will + be used by its corresponding data class.""" + array = np.loadtxt(filename) + data_dict = {"array": array} + return data_dict + + @classmethod + def write(cls, object: ArrayData, filename: str, key: str = None): + """Save the data with the `filename`.""" + data_dict = object.get_data() + arr = data_dict["array"] + np.savetxt(filename, arr, fmt="%.3f") + if key is None: + original_key = object.key + key = original_key + "_to_TXTFormat" + return object.from_file(filename, cls, key) diff --git a/tests/integration/plusminus/plusminus/ArrayData/__init__.py b/tests/integration/plusminus/plusminus/ArrayData/__init__.py new file mode 100644 index 0000000..75b656a --- /dev/null +++ b/tests/integration/plusminus/plusminus/ArrayData/__init__.py @@ -0,0 +1,3 @@ +from .ArrayData import ArrayData +from .H5Format import H5Format +from .TXTFormat import TXTFormat diff --git a/tests/integration/plusminus/plusminus/BaseCalculator.py b/tests/integration/plusminus/plusminus/BaseCalculator.py new file mode 100644 index 0000000..27e4c3c --- /dev/null +++ b/tests/integration/plusminus/plusminus/BaseCalculator.py @@ -0,0 +1,243 @@ +""" :module BaseCalculator: Module hosts the BaseData class.""" +from abc import abstractmethod, ABCMeta +from typing import Union +from pathlib import Path +from libpyvinyl.AbstractBaseClass import AbstractBaseClass +from libpyvinyl.BaseData import BaseData, DataCollection +from libpyvinyl.Parameters import CalculatorParameters + + +class BaseCalculator(AbstractBaseClass): + def __init__( + self, + name: str, + input: Union[DataCollection, list, BaseData], + output_keys: Union[list, str], + output_data_types: list, + output_filenames: Union[list, str], + instrument_base_dir="./", + calculator_base_dir="BaseCalculator", + parameters: CalculatorParameters = None, + ): + """A python object calculator example""" + # Initialize properties + self.__name = None + self.__instrument_base_dir = None + self.__calculator_base_dir = None + self.__input = None + self.__input_keys = None + self.__output_keys = None + self.__output_data_types = None + self.__output_filenames = None + self.__parameters = None + + self.name = name + self.input = input + self.output_keys = output_keys + self.output_data_types = output_data_types + self.output_filenames = output_filenames + self.instrument_base_dir = instrument_base_dir + self.calculator_base_dir = calculator_base_dir + self.parameters = parameters + + self.__init_output() + + @abstractmethod + def init_parameters(self): + raise NotImplementedError + + def __init_output(self): + output = DataCollection() + for i, key in enumerate(self.output_keys): + output_data = self.output_data_types[i](key) + output.add_data(output_data) + self.output = output + + @property + def name(self): + return self.__name + + @name.setter + def name(self, value): + if isinstance(value, str): + self.__name = value + else: + raise TypeError( + f"Calculator: `name` is expected to be a str, not {type(value)}" + ) + + @property + def parameters(self): + return self.__parameters + + @parameters.setter + def parameters(self, value): + if isinstance(value, CalculatorParameters): + self.__parameters = value + elif value is None: + self.init_parameters() + else: + raise TypeError( + f"Calculator: `parameters` is expected to be CalculatorParameters, not {type(value)}" + ) + + @property + def input(self): + return self.__input + + @input.setter + def input(self, value): + self.set_input(value) + + def set_input(self, value: Union[DataCollection, list, BaseData]): + if isinstance(value, DataCollection): + self.__input = value + elif isinstance(value, list): + self.__input = DataCollection(*value) + elif isinstance(value, BaseData): + self.__input = DataCollection(value) + else: + raise TypeError( + f"Calculator: `input` can be a DataCollection, list or BaseData object, and will be treated as a DataCollection, but not {type(value)}" + ) + + @property + def input_keys(self): + return self.__input_keys + + @input_keys.setter + def input_keys(self, value): + self.set_input_keys(value) + + def set_input_keys(self, value: Union[list, str]): + if isinstance(value, list): + for item in value: + assert type(item) is str + self.__input_keys = value + elif isinstance(value, str): + self.__input_keys = [value] + else: + raise TypeError( + f"Calculator: `input_keys` can be a list or a string, and will be treated as a list, but not {type(value)}" + ) + + @property + def output_keys(self): + return self.__output_keys + + @output_keys.setter + def output_keys(self, value): + self.set_output_keys(value) + + def set_output_keys(self, value: Union[list, str]): + if isinstance(value, list): + for item in value: + assert type(item) is str + self.__output_keys = value + elif isinstance(value, str): + self.__output_keys = [value] + else: + raise TypeError( + f"Calculator: `output_keys` can be a list or a string, and will be treated as a list, but not {type(value)}" + ) + + @property + def output_data_types(self): + return self.__output_data_types + + @output_data_types.setter + def output_data_types(self, value): + self.set_output_data_types(value) + + def set_output_data_types(self, value): + if isinstance(value, list): + for item in value: + assert type(item) is ABCMeta + self.__output_data_types = value + elif isinstance(value, ABCMeta): + self.__output_data_types = [value] + else: + raise TypeError( + f"Calculator: `output_data_types` can be a list or a DataClass, and will be treated as a list, but not {type(value)}" + ) + + @property + def output_filenames(self): + """Native calculator file names""" + return self.__output_filenames + + @output_filenames.setter + def output_filenames(self, value): + self.set_output_filenames(value) + + def set_output_filenames(self, value: Union[list, str]): + if isinstance(value, str): + self.__output_filenames = [value] + elif isinstance(value, list): + self.__output_filenames = value + else: + raise TypeError( + f"Calculator: `output_filenames` can to be a str or a list, and will be treated as a list, but not {type(value)}" + ) + + @property + def instrument_base_dir(self): + return self.__instrument_base_dir + + @instrument_base_dir.setter + def instrument_base_dir(self, value): + self.set_instrument_base_dir(value) + + def set_instrument_base_dir(self, value: str): + if isinstance(value, str): + self.__instrument_base_dir = value + else: + raise TypeError( + f"Calculator: `instrument_base_dir` is expected to be a str, not {type(value)}" + ) + + @property + def calculator_base_dir(self): + return self.__calculator_base_dir + + @calculator_base_dir.setter + def calculator_base_dir(self, value): + self.set_calculator_base_dir(value) + + def set_calculator_base_dir(self, value: str): + if isinstance(value, str): + self.__calculator_base_dir = value + else: + raise TypeError( + f"Calculator: `calculator_base_dir` is expected to be a str, not {type(value)}" + ) + + @property + def base_dir(self): + base_dir = Path(self.instrument_base_dir) / self.calculator_base_dir + return str(base_dir) + + @property + def output_file_paths(self): + paths = [] + for filename in self.output_filenames: + path = Path(self.base_dir) / filename + # Make sure the file directory exists + path.parent.mkdir(parents=True, exist_ok=True) + paths.append(str(path)) + return paths + + @abstractmethod + def backengine(self): + Path(self.base_dir).mkdir(parents=True, exist_ok=True) + input_num0 = self.input[self.input_keys[0]].get_data()["number"] + input_num1 = self.input[self.input_keys[1]].get_data()["number"] + output_num = float(input_num0) + float(input_num1) + if self.parameters["plus_times"].value > 1: + for i in range(self.parameters["plus_times"].value - 1): + output_num += input_num1 + data_dict = {"number": output_num} + key = self.output_keys[0] + output_data = NumberData.from_dict(data_dict, key) + self.output = DataCollection(output_data) + return self.output diff --git a/tests/integration/plusminus/plusminus/NumberCalculators/MinusCalculator.py b/tests/integration/plusminus/plusminus/NumberCalculators/MinusCalculator.py new file mode 100644 index 0000000..f4b0e41 --- /dev/null +++ b/tests/integration/plusminus/plusminus/NumberCalculators/MinusCalculator.py @@ -0,0 +1,55 @@ +from typing import Union +from pathlib import Path +import numpy as np +from libpyvinyl.BaseData import DataCollection +from plusminus.NumberData import NumberData, TXTFormat +from libpyvinyl.BaseCalculator import BaseCalculator, CalculatorParameters + + +class MinusCalculator(BaseCalculator): + def __init__( + self, + name: str, + input: Union[DataCollection, list, NumberData], + output_keys: Union[list, str] = ["minus_result"], + output_data_types=[NumberData], + output_filenames: Union[list, str] = ["minus_result.txt"], + instrument_base_dir="./", + calculator_base_dir="MinusCalculator", + parameters=None, + ): + """A python object calculator example""" + super().__init__( + name, + input, + output_keys, + output_data_types=output_data_types, + output_filenames=output_filenames, + instrument_base_dir=instrument_base_dir, + calculator_base_dir=calculator_base_dir, + parameters=parameters, + ) + + def init_parameters(self): + parameters = CalculatorParameters() + times = parameters.new_parameter( + "minus_times", comment="How many times to do the minus" + ) + times.value = 1 + self.parameters = parameters + + def backengine(self): + Path(self.base_dir).mkdir(parents=True, exist_ok=True) + input_num0 = self.input.to_list()[0].get_data()["number"] + input_num1 = self.input.to_list()[1].get_data()["number"] + output_num = float(input_num0) - float(input_num1) + if self.parameters["minus_times"].value > 1: + for i in range(self.parameters["minus_times"].value - 1): + output_num -= input_num1 + arr = np.array([output_num]) + file_path = self.output_file_paths[0] + np.savetxt(file_path, arr, fmt="%.3f") + key = self.output_keys[0] + output_data = self.output[key] + output_data.set_file(file_path, TXTFormat) + return self.output diff --git a/tests/integration/plusminus/plusminus/NumberCalculators/PlusCalculator.py b/tests/integration/plusminus/plusminus/NumberCalculators/PlusCalculator.py new file mode 100644 index 0000000..22f5c7f --- /dev/null +++ b/tests/integration/plusminus/plusminus/NumberCalculators/PlusCalculator.py @@ -0,0 +1,52 @@ +from typing import Union +from pathlib import Path +from libpyvinyl.BaseData import DataCollection +from plusminus.NumberData import NumberData +from libpyvinyl.BaseCalculator import BaseCalculator, CalculatorParameters + + +class PlusCalculator(BaseCalculator): + def __init__( + self, + name: str, + input: Union[DataCollection, list, NumberData], + output_keys: Union[list, str] = ["plus_result"], + output_data_types=[NumberData], + output_filenames: Union[list, str] = [], + instrument_base_dir="./", + calculator_base_dir="PlusCalculator", + parameters=None, + ): + """A python object calculator example""" + super().__init__( + name, + input, + output_keys, + output_data_types=output_data_types, + output_filenames=output_filenames, + instrument_base_dir=instrument_base_dir, + calculator_base_dir=calculator_base_dir, + parameters=parameters, + ) + + def init_parameters(self): + parameters = CalculatorParameters() + times = parameters.new_parameter( + "plus_times", comment="How many times to do the plus" + ) + times.value = 1 + self.parameters = parameters + + def backengine(self): + Path(self.base_dir).mkdir(parents=True, exist_ok=True) + input_num0 = self.input.to_list()[0].get_data()["number"] + input_num1 = self.input.to_list()[1].get_data()["number"] + output_num = float(input_num0) + float(input_num1) + if self.parameters["plus_times"].value > 1: + for i in range(self.parameters["plus_times"].value - 1): + output_num += input_num1 + data_dict = {"number": output_num} + key = self.output_keys[0] + output_data = self.output[key] + output_data.set_dict(data_dict) + return self.output diff --git a/tests/integration/plusminus/plusminus/NumberCalculators/__init__.py b/tests/integration/plusminus/plusminus/NumberCalculators/__init__.py new file mode 100644 index 0000000..68ed672 --- /dev/null +++ b/tests/integration/plusminus/plusminus/NumberCalculators/__init__.py @@ -0,0 +1,2 @@ +from .MinusCalculator import MinusCalculator +from .PlusCalculator import PlusCalculator diff --git a/tests/integration/plusminus/plusminus/NumberData/H5Format.py b/tests/integration/plusminus/plusminus/NumberData/H5Format.py new file mode 100644 index 0000000..836d1e5 --- /dev/null +++ b/tests/integration/plusminus/plusminus/NumberData/H5Format.py @@ -0,0 +1,47 @@ +import h5py +from libpyvinyl.BaseFormat import BaseFormat +from plusminus.NumberData import NumberData + + +class H5Format(BaseFormat): + def __init__(self) -> None: + super().__init__() + + @classmethod + def format_register(self): + key = "H5" + desciption = "H5 format for NumberData" + file_extension = ".h5" + read_kwargs = [""] + write_kwargs = [""] + return self._create_format_register( + key, desciption, file_extension, read_kwargs, write_kwargs + ) + + @staticmethod + def direct_convert_formats(): + # Assume the format can be converted directly to the formats supported by these classes: + # AFormat, BFormat + # Redefine this `direct_convert_formats` for a concrete format class + return [] + + @classmethod + def read(cls, filename: str) -> dict: + """Read the data from the file with the `filename` to a dictionary. The dictionary will + be used by its corresponding data class.""" + with h5py.File(filename, "r") as h5: + number = h5["number"][()] + data_dict = {"number": number} + return data_dict + + @classmethod + def write(cls, object: NumberData, filename: str, key: str = None): + """Save the data with the `filename`.""" + data_dict = object.get_data() + number = data_dict["number"] + with h5py.File(filename, "w") as h5: + h5["number"] = number + if key is None: + original_key = object.key + key = original_key + "_to_H5Format" + return object.from_file(filename, cls, key) diff --git a/tests/integration/plusminus/plusminus/NumberData/NumberData.py b/tests/integration/plusminus/plusminus/NumberData/NumberData.py new file mode 100644 index 0000000..cb19668 --- /dev/null +++ b/tests/integration/plusminus/plusminus/NumberData/NumberData.py @@ -0,0 +1,52 @@ +from libpyvinyl.BaseData import BaseData +from plusminus.NumberData import TXTFormat, H5Format + + +class NumberData(BaseData): + def __init__( + self, + key, + data_dict=None, + filename=None, + file_format_class=None, + file_format_kwargs=None, + ): + + expected_data = {} + + ### DataClass developer's job start + expected_data["number"] = None + ### DataClass developer's job end + + super().__init__( + key, + expected_data, + data_dict, + filename, + file_format_class, + file_format_kwargs, + ) + + @classmethod + def supported_formats(self): + format_dict = {} + ### DataClass developer's job start + self._add_ioformat(format_dict, TXTFormat.TXTFormat) + self._add_ioformat(format_dict, H5Format.H5Format) + ### DataClass developer's job end + return format_dict + + @classmethod + def from_file(cls, filename: str, format_class, key, **kwargs): + """Create the data class by the file in the `format`.""" + return cls( + key, + filename=filename, + file_format_class=format_class, + file_format_kwargs=kwargs, + ) + + @classmethod + def from_dict(cls, data_dict, key): + """Create the data class by a python dictionary.""" + return cls(key, data_dict=data_dict) diff --git a/tests/integration/plusminus/plusminus/NumberData/TXTFormat.py b/tests/integration/plusminus/plusminus/NumberData/TXTFormat.py new file mode 100644 index 0000000..c614aa6 --- /dev/null +++ b/tests/integration/plusminus/plusminus/NumberData/TXTFormat.py @@ -0,0 +1,45 @@ +import numpy as np +from libpyvinyl.BaseFormat import BaseFormat +from plusminus.NumberData import NumberData + + +class TXTFormat(BaseFormat): + def __init__(self) -> None: + super().__init__() + + @classmethod + def format_register(self): + key = "TXT" + desciption = "TXT format for NumberData" + file_extension = ".txt" + read_kwargs = [""] + write_kwargs = [""] + return self._create_format_register( + key, desciption, file_extension, read_kwargs, write_kwargs + ) + + @staticmethod + def direct_convert_formats(): + # Assume the format can be converted directly to the formats supported by these classes: + # AFormat, BFormat + # Redefine this `direct_convert_formats` for a concrete format class + return [] + + @classmethod + def read(cls, filename: str) -> dict: + """Read the data from the file with the `filename` to a dictionary. The dictionary will + be used by its corresponding data class.""" + number = float(np.loadtxt(filename)) + data_dict = {"number": number} + return data_dict + + @classmethod + def write(cls, object: NumberData, filename: str, key: str = None): + """Save the data with the `filename`.""" + data_dict = object.get_data() + arr = np.array([data_dict["number"]]) + np.savetxt(filename, arr, fmt="%.3f") + if key is None: + original_key = object.key + key = original_key + "_to_TXTFormat" + return object.from_file(filename, cls, key) diff --git a/tests/integration/plusminus/plusminus/NumberData/__init__.py b/tests/integration/plusminus/plusminus/NumberData/__init__.py new file mode 100644 index 0000000..f43e39f --- /dev/null +++ b/tests/integration/plusminus/plusminus/NumberData/__init__.py @@ -0,0 +1,3 @@ +from .H5Format import H5Format +from .NumberData import NumberData +from .TXTFormat import TXTFormat diff --git a/tests/integration/plusminus/plusminus/__init__.py b/tests/integration/plusminus/plusminus/__init__.py new file mode 100644 index 0000000..09c834a --- /dev/null +++ b/tests/integration/plusminus/plusminus/__init__.py @@ -0,0 +1,8 @@ +"""Top-level package for PlusMinus.""" + +__author__ = """Juncheng E""" +__email__ = "juncheng.e@xfel.eu" +__version__ = "0.1.0" + + +from libpyvinyl.BaseData import DataCollection diff --git a/tests/integration/plusminus/plusminus/plusminus.py b/tests/integration/plusminus/plusminus/plusminus.py new file mode 100644 index 0000000..dd0b80e --- /dev/null +++ b/tests/integration/plusminus/plusminus/plusminus.py @@ -0,0 +1 @@ +"""Main module.""" diff --git a/tests/__init__Test.py b/tests/integration/plusminus/requirements.txt similarity index 100% rename from tests/__init__Test.py rename to tests/integration/plusminus/requirements.txt diff --git a/tests/integration/plusminus/requirements_dev.txt b/tests/integration/plusminus/requirements_dev.txt new file mode 100644 index 0000000..8a62c17 --- /dev/null +++ b/tests/integration/plusminus/requirements_dev.txt @@ -0,0 +1,13 @@ +pip==19.2.3 +bump2version==0.5.11 +wheel==0.33.6 +watchdog==0.9.0 +flake8==3.7.8 +tox==3.14.0 +coverage==4.5.4 +Sphinx==3.5.2 +twine==1.14.0 +sphinx_rtd_theme==0.5.1 + +pytest==4.6.5 +pytest-runner==5.1 \ No newline at end of file diff --git a/tests/integration/plusminus/setup.cfg b/tests/integration/plusminus/setup.cfg new file mode 100644 index 0000000..476a919 --- /dev/null +++ b/tests/integration/plusminus/setup.cfg @@ -0,0 +1,23 @@ +[bumpversion] +current_version = 0.1.0 +commit = True +tag = True + +[bumpversion:file:setup.py] +search = version='{current_version}' +replace = version='{new_version}' + +[bumpversion:file:plusminus/__init__.py] +search = __version__ = '{current_version}' +replace = __version__ = '{new_version}' + +[bdist_wheel] +universal = 1 + +[flake8] +exclude = docs + +[aliases] +# Define setup.py command aliases here +test = pytest + diff --git a/tests/integration/plusminus/setup.py b/tests/integration/plusminus/setup.py new file mode 100644 index 0000000..4047cd4 --- /dev/null +++ b/tests/integration/plusminus/setup.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +"""The setup script.""" + +from setuptools import setup, find_packages + +with open("README.rst") as readme_file: + readme = readme_file.read() + +with open("HISTORY.rst") as history_file: + history = history_file.read() + +with open("requirements.txt") as requirements_file: + require = requirements_file.read() + requirements = require.split() + +setup_requirements = [ + "pytest-runner", +] + +test_requirements = [ + "pytest>=3", +] + +setup( + author="Juncheng E", + author_email="juncheng.e@xfel.eu", + python_requires=">=3.6", + classifiers=[ + "Development Status :: 2 - Pre-Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + ], + description="An example of a small platform implementing libpynyl", + install_requires=requirements, + license="MIT license", + long_description=readme + "\n\n" + history, + include_package_data=True, + keywords="PlusMinus", + name="PlusMinus", + packages=find_packages(include=["plusminus", "plusminus.*"]), + setup_requires=setup_requirements, + test_suite="tests", + tests_require=test_requirements, + url="https://github.com/JunCEEE/PlusMinus", + version="0.1.0", + zip_safe=False, +) diff --git a/tests/integration/plusminus/tests/__init__.py b/tests/integration/plusminus/tests/__init__.py new file mode 100644 index 0000000..c1a5b10 --- /dev/null +++ b/tests/integration/plusminus/tests/__init__.py @@ -0,0 +1 @@ +"""Unit test package for plusminus.""" diff --git a/tests/integration/plusminus/tests/test_ArrayCalculators.py b/tests/integration/plusminus/tests/test_ArrayCalculators.py new file mode 100644 index 0000000..8ffa5dc --- /dev/null +++ b/tests/integration/plusminus/tests/test_ArrayCalculators.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +"""Tests for `plusminus.NumberCalculators` package.""" + +import pytest +from plusminus.ArrayCalculators import ArrayCalculator +from plusminus.NumberData import NumberData +from plusminus.ArrayData import TXTFormat +from plusminus import DataCollection + + +def test_ArrayCalculator(tmpdir): + """PlusCalculator test function, the native output of ArrayCalculator is a python dictionary""" + + input1 = NumberData.from_dict({"number": 1}, "input1") + input2 = NumberData.from_dict({"number": 2}, "input2") + input_data = [input1, input2] # This could also be allowed. + input_data = DataCollection(input1, input2) + calculator = ArrayCalculator("plus", input_data) + calculator.set_instrument_base_dir(str(tmpdir)) + output = calculator.backengine() + assert output.get_data()["array"][0] == 1 + assert output.get_data()["array"][1] == 2 + calculator.parameters["multiply"] = 5 + output = calculator.backengine() + file_output = output.write( + calculator.base_dir + "/array_5.txt", TXTFormat, key="file_output" + ) + assert file_output.get_data()["array"][0] == 5 + assert file_output.get_data()["array"][1] == 10 diff --git a/tests/integration/plusminus/tests/test_Instrument.py b/tests/integration/plusminus/tests/test_Instrument.py new file mode 100644 index 0000000..dc11a09 --- /dev/null +++ b/tests/integration/plusminus/tests/test_Instrument.py @@ -0,0 +1,38 @@ +import pytest +from libpyvinyl.Instrument import Instrument +from plusminus.ArrayCalculators import ArrayCalculator +from plusminus.NumberCalculators import PlusCalculator, MinusCalculator +from plusminus.NumberData import NumberData +import plusminus.ArrayData as AD +from plusminus import DataCollection + + +def test_CalculationInstrument(tmpdir): + """PlusCalculator test function, the native output of MinusCalculator is a python dictionary""" + + input1 = NumberData.from_dict({"number": 1}, "input1") + input2 = NumberData.from_dict({"number": 2}, "input2") + input_collection = [input1, input2] # This could also be allowed. + input_collection = DataCollection(input1, input2) + calculator1 = PlusCalculator("plus", input_collection, output_keys=["plus_result"]) + calculator2 = MinusCalculator( + "minus", input_collection, output_keys=["minus_result"] + ) + + input_collection = DataCollection( + calculator1.output["plus_result"], calculator2.output["minus_result"] + ) + calculator3 = ArrayCalculator( + "array", input_collection, output_keys=["array_result"] + ) + + calculation_instrument = Instrument("calculation_instrument") + instrument_path = tmpdir / "calculation_instrument" + calculation_instrument.add_calculator(calculator1) + calculation_instrument.add_calculator(calculator2) + calculation_instrument.add_calculator(calculator3) + calculation_instrument.set_instrument_base_dir(str(instrument_path)) + calculation_instrument.run() + print(calculator3.output.get_data()) + calculator3.output.write(str(tmpdir / "final_result.txt"), AD.TXTFormat) + calculator3.output.write(str(tmpdir / "final_result.h5"), AD.H5Format) diff --git a/tests/integration/plusminus/tests/test_NumberCalculators.py b/tests/integration/plusminus/tests/test_NumberCalculators.py new file mode 100644 index 0000000..198e8a2 --- /dev/null +++ b/tests/integration/plusminus/tests/test_NumberCalculators.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +"""Tests for `plusminus.NumberCalculators` package.""" + +import pytest +from plusminus.NumberCalculators import PlusCalculator, MinusCalculator +from plusminus.NumberData import NumberData, TXTFormat +from plusminus import DataCollection + + +def test_PlusCalculator(tmpdir): + """PlusCalculator test function, the native output of PlusCalculator is a python dictionary""" + + input1 = NumberData.from_dict({"number": 1}, "input1") + input2 = NumberData.from_dict({"number": 1}, "input2") + input_data = [input1, input2] # This could also be allowed. + input_data = DataCollection(input1, input2) + plus = PlusCalculator("plus", input_data) + plus.set_instrument_base_dir(str(tmpdir)) + plus_output = plus.backengine() + assert plus_output.get_data()["number"] == 2 + plus_output.write(plus.base_dir + "/1_time.txt", TXTFormat) + plus.parameters["plus_times"] = 5 + plus_output = plus.backengine() + file_output = plus_output.write( + plus.base_dir + "/5_time.txt", TXTFormat, key="file_output" + ) + assert file_output.get_data()["number"] == 6 + + +def test_MinusCalculator(tmpdir): + """MinusCalculator test function. The native output of MinusCalculator is a txt file""" + + input1 = NumberData.from_dict({"number": 1}, "input1") + input2 = NumberData.from_dict({"number": 1}, "input2") + input_data = DataCollection(input1, input2) + calculator = MinusCalculator("minus", input_data) + calculator.set_instrument_base_dir(str(tmpdir)) + assert "MinusCalculator" in calculator.base_dir + calculator.set_output_filenames("minus_res.txt") + output = calculator.backengine() + assert output.get_data()["number"] == 0 + calculator.parameters["minus_times"] = 5 + plus_output = calculator.backengine() + assert plus_output.get_data()["number"] == -4 + + +def test_DataCollection_multiple(): + """PlusCalculator test function""" + + input1 = NumberData.from_dict({"number": 1}, "input1") + input2 = NumberData.from_dict({"number": 1}, "input2") + input_data = DataCollection(input1, input2) + data = input_data.get_data() + assert data["input1"]["number"] == 1 + assert data["input2"]["number"] == 1 diff --git a/tests/integration/plusminus/tests/test_NumberData.py b/tests/integration/plusminus/tests/test_NumberData.py new file mode 100644 index 0000000..fea1774 --- /dev/null +++ b/tests/integration/plusminus/tests/test_NumberData.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python +"""Tests for `plusminus.NumberCalculators` package.""" + +import pytest +import h5py +from plusminus.NumberData import NumberData, TXTFormat, H5Format + + +def test_construct_NumberData(): + """Test the construction of NumberData""" + my_data = NumberData.from_dict({"number": 1}, "input1") + + +def test_list_formats(): + """Test the construction of NumberData""" + my_data = NumberData.from_dict({"number": 1}, "input1") + my_data.list_formats() + + +def test_write_read_txt(tmpdir): + """Test writing to a txt file""" + my_data = NumberData.from_dict({"number": 1}, "input1") + file_name = str(tmpdir / "test.txt") + my_data.write(file_name, TXTFormat) + with open(file_name, "r") as f: + assert float(f.read()) == 1 + read_data = NumberData.from_file(file_name, TXTFormat, "read_data") + assert read_data.get_data()["number"] == 1 + + +def test_write_read_h5(tmpdir): + """Test writing to a h5 file""" + my_data = NumberData.from_dict({"number": 1}, "input1") + file_name = str(tmpdir / "test.h5") + my_data.write(file_name, H5Format) + with h5py.File(file_name, "r") as h5: + assert h5["number"][()] == 1 + read_data = NumberData.from_file(file_name, H5Format, "read_data") + assert read_data.get_data()["number"] == 1 + + +def test_read_txt_write_h5(tmpdir): + """Test read a txt file and write to a h5 file""" + my_data = NumberData.from_dict({"number": 1}, "input1") + file_name = str(tmpdir / "test.txt") + my_data.write(file_name, TXTFormat) + read_data = NumberData.from_file(file_name, TXTFormat, "read_data") + file_name = str(tmpdir / "test.h5") + read_data.write(file_name, H5Format) + with h5py.File(file_name, "r") as h5: + assert h5["number"][()] == 1 + + +def test_txt_file_write_h5(tmpdir): + """Test write a txt file and write to a h5 file""" + my_data = NumberData.from_dict({"number": 1}, "input1") + file_name = str(tmpdir / "test.txt") + read_data = my_data.write(file_name, TXTFormat, "read_data") + file_name = str(tmpdir / "test.h5") + read_data.write(file_name, H5Format) + with h5py.File(file_name, "r") as h5: + assert h5["number"][()] == 1 + + +def test_set_dict(tmpdir): + """Test setting a dict mapping""" + my_data = NumberData("input1") + my_data.set_dict({"number": 1}) + file_name = str(tmpdir / "test.txt") + my_data.write(file_name, TXTFormat) + + +def test_set_file_(tmpdir): + """Test setting a file mapping""" + my_data = NumberData.from_dict({"number": 1}, "input1") + file_name = str(tmpdir / "test.txt") + my_data.write(file_name, TXTFormat) + new_data = NumberData("new_data") + new_data.set_file(file_name, TXTFormat) + assert new_data.get_data()["number"] == 1 + + +def test_set_file_report_double_setting(tmpdir): + """Test write a txt file and write to a h5 file""" + my_data = NumberData.from_dict({"number": 1}, "input1") + file_name = str(tmpdir / "test.txt") + my_data.write(file_name, TXTFormat) + with pytest.raises(RuntimeError): + my_data.set_file(file_name, TXTFormat) + + +def test_return_object_without_key(tmpdir): + """Test write a txt file and write to a h5 file""" + my_data = NumberData.from_dict({"number": 1}, "input1") + file_name = str(tmpdir / "test.txt") + new_data = my_data.write(file_name, TXTFormat) + assert new_data.key == "input1_to_TXTFormat" + + +def test_return_object_with_key(tmpdir): + """Test write a txt file and write to a h5 file""" + my_data = NumberData.from_dict({"number": 1}, "input1") + file_name = str(tmpdir / "test.txt") + key = "test" + new_data = my_data.write(file_name, TXTFormat, key) + assert new_data.key == key diff --git a/tests/integration/plusminus/tox.ini b/tests/integration/plusminus/tox.ini new file mode 100644 index 0000000..6a29de0 --- /dev/null +++ b/tests/integration/plusminus/tox.ini @@ -0,0 +1,26 @@ +[tox] +envlist = py36, py37, py38, flake8 + +[travis] +python = + 3.8: py38 + 3.7: py37 + 3.6: py36 + +[testenv:flake8] +basepython = python +deps = flake8 +commands = flake8 plusminus tests + +[testenv] +setenv = + PYTHONPATH = {toxinidir} +deps = + -r{toxinidir}/requirements_dev.txt +; If you want to make tox run the tests with the same versions, create a +; requirements.txt with the pinned versions and uncomment the following line: +; -r{toxinidir}/requirements.txt +commands = + pip install -U pip + pytest --basetemp={envtmpdir} + diff --git a/libpyvinyl/RadiationSampleInteractor.py b/tests/unit/Test.py similarity index 63% rename from libpyvinyl/RadiationSampleInteractor.py rename to tests/unit/Test.py index 9411bab..6cd35b2 100644 --- a/libpyvinyl/RadiationSampleInteractor.py +++ b/tests/unit/Test.py @@ -1,17 +1,16 @@ +#! /usr/bin/env python3 """ -:module RadiationSampleInteractor: Module hosting the RadiationSampleInteractor and RadiationSampleInteractorParameters -abstract classes. +:module Test: Top level test module hosting all unittest suites. """ - #################################################################################### # # -# This file is part of libpyvinyl - The APIs for Virtual Neutron and x-raY # +# This file is part of libpyvinyl - The APIs for Virtual Neutron and x-raY # # Laboratory. # # # # Copyright (C) 2020 Carsten Fortmann-Grote # # # -# This program is free software: you can redistribute it and/or modify it under # +# This program is free software: you can redistribute it and/or modify it under # # the terms of the GNU Lesser General Public License as published by the Free # # Software Foundation, either version 3 of the License, or (at your option) any # # later version. # @@ -25,24 +24,34 @@ # # #################################################################################### -from libpyvinyl.BaseCalculator import BaseCalculator, CalculatorParameters +import unittest +import sys + +from test_BaseCalculator import BaseCalculatorTest +from test_Parameters import Test_Parameter, Test_Parameters, Test_Instruments +from test_Instrument import InstrumentTest + + +def suite(): + suites = [ + unittest.makeSuite(BaseCalculatorTest, "test"), + unittest.makeSuite(Test_Parameter, "test"), + unittest.makeSuite(Test_Parameters, "test"), + unittest.makeSuite(Test_Instruments, "test"), + unittest.makeSuite(InstrumentTest, "test"), + ] -class RadiationSampleInteractorParameters(CalculatorParameters): - def __init__(self, **kwargs): - - super().__init__(**kwargs) + return unittest.TestSuite(suites) +# Run the suite and return a success status code. This enables running an automated git-bisect. +if __name__ == "__main__": -class RadiationSampleInteractor(BaseCalculator): - def __init__(self,name, parameters=None, dumpfile=None, **kwargs): - - super().__init__(name, parameters, dumpfile, **kwargs) + result = unittest.TextTestRunner(verbosity=2).run(suite()) - def backengine(self): - pass + if result.wasSuccessful(): + print("---> OK <---") + sys.exit(0) - def saveH5(self, fname, openpmd=True): - pass + sys.exit(1) -# This project has received funding from the European Union's Horizon 2020 research and innovation programme under grant agreement No. 823852. diff --git a/tests/unit/test_BaseCalculator.py b/tests/unit/test_BaseCalculator.py new file mode 100644 index 0000000..3f380a4 --- /dev/null +++ b/tests/unit/test_BaseCalculator.py @@ -0,0 +1,304 @@ +import unittest +import pytest +import os +import shutil +from typing import Union +from pathlib import Path + +from libpyvinyl.BaseCalculator import BaseCalculator +from libpyvinyl.BaseData import BaseData, DataCollection +from libpyvinyl.Parameters import CalculatorParameters +from libpyvinyl.AbstractBaseClass import AbstractBaseClass + + +class NumberData(BaseData): + """Example dict mapping data""" + + def __init__( + self, + key, + data_dict=None, + filename=None, + file_format_class=None, + file_format_kwargs=None, + ): + + expected_data = {} + + # DataClass developer's job start + expected_data["number"] = None + # DataClass developer's job end + + super().__init__( + key, + expected_data, + data_dict, + filename, + file_format_class, + file_format_kwargs, + ) + + @classmethod + def supported_formats(self): + return {} + + @classmethod + def from_file(cls, filename: str, format_class, key, **kwargs): + raise NotImplementedError() + + @classmethod + def from_dict(cls, data_dict, key): + """Create the data class by a python dictionary.""" + return cls(key, data_dict=data_dict) + + +class PlusCalculator(BaseCalculator): + """:class: Specialized calculator, calculates the sum of two datasets.""" + + def __init__( + self, + name: str, + input: Union[DataCollection, list, NumberData], + output_keys: Union[list, str] = ["plus_result"], + output_data_types=[NumberData], + output_filenames: Union[list, str] = [], + instrument_base_dir="./", + calculator_base_dir="PlusCalculator", + parameters=None, + ): + """A python object calculator example""" + super().__init__( + name, + input, + output_keys, + output_data_types=output_data_types, + output_filenames=output_filenames, + instrument_base_dir=instrument_base_dir, + calculator_base_dir=calculator_base_dir, + parameters=parameters, + ) + + def init_parameters(self): + parameters = CalculatorParameters() + times = parameters.new_parameter( + "plus_times", comment="How many times to do the plus" + ) + # Set defaults + times.value = 1 + + self.parameters = parameters + + def backengine(self): + Path(self.base_dir).mkdir(parents=True, exist_ok=True) + input_num0 = self.input.to_list()[0].get_data()["number"] + input_num1 = self.input.to_list()[1].get_data()["number"] + output_num = float(input_num0) + float(input_num1) + if self.parameters["plus_times"].value > 1: + for i in range(self.parameters["plus_times"].value - 1): + output_num += input_num1 + data_dict = {"number": output_num} + key = self.output_keys[0] + output_data = self.output[key] + output_data.set_dict(data_dict) + return self.output + + +class BaseCalculatorTest(unittest.TestCase): + """ + Test class for the BaseCalculator class. + """ + + @classmethod + def setUpClass(cls): + """Setting up the test class.""" + + input1 = NumberData.from_dict({"number": 1}, "input1") + input2 = NumberData.from_dict({"number": 1}, "input2") + input_data = [input1, input2] + plus = PlusCalculator("plus", input_data) + cls.__default_calculator = plus + cls.__default_input = input_data + + @classmethod + def tearDownClass(cls): + """Tearing down the test class.""" + del cls.__default_calculator + del cls.__default_input + + def setUp(self): + """Setting up a test.""" + self.__files_to_remove = [] + self.__dirs_to_remove = [] + + def tearDown(self): + """Tearing down a test.""" + + for f in self.__files_to_remove: + if os.path.isfile(f): + os.remove(f) + for d in self.__dirs_to_remove: + if os.path.isdir(d): + shutil.rmtree(d) + + def test_base_class_constructor_raises(self): + """Test that we cannot construct instances of the base class.""" + + self.assertRaises(TypeError, BaseCalculator, "name") + + def test_default_construction(self): + """Testing the default construction of the class.""" + + # Test positional arguments + calculator = PlusCalculator("test", self.__default_input) + + self.assertIsInstance(calculator, PlusCalculator) + self.assertIsInstance(calculator, BaseCalculator) + self.assertIsInstance(calculator, AbstractBaseClass) + + def test_deep_copy(self): + """Test the copy constructor behaves as expected.""" + # Parameters are not deepcopied by itself + calculator_copy = self.__default_calculator() + self.assertEqual(calculator_copy.parameters["plus_times"].value, 1) + new_parameters = calculator_copy.parameters + new_parameters["plus_times"] = 5 + self.assertEqual(new_parameters["plus_times"].value, 5) + self.assertEqual(calculator_copy.parameters["plus_times"].value, 5) + + # Parameters are deepcopied when copy the calculator + calculator_copy = self.__default_calculator() + self.assertEqual(calculator_copy.parameters["plus_times"].value, 1) + calculator_copy.parameters["plus_times"] = 10 + self.assertEqual(calculator_copy.parameters["plus_times"].value, 10) + self.assertEqual(self.__default_calculator.parameters["plus_times"].value, 1) + calculator_copy.input["input1"] = NumberData.from_dict({"number": 5}, "input1") + self.assertEqual(calculator_copy.input["input1"].get_data()["number"], 5) + self.assertEqual( + self.__default_calculator.input["input1"].get_data()["number"], 1 + ) + + # Calculator reference + self.assertEqual(calculator_copy.parameters["plus_times"].value, 10) + calculator_reference = calculator_copy + self.assertEqual(calculator_reference.parameters["plus_times"].value, 10) + calculator_reference.parameters["plus_times"] = 3 + self.assertEqual(calculator_reference.parameters["plus_times"].value, 3) + self.assertEqual(calculator_copy.parameters["plus_times"].value, 3) + + # New parameters can be set while caculator deepcopy + new_parameters = CalculatorParameters() + times = new_parameters.new_parameter( + "plus_times", comment="How many times to do the plus" + ) + times.value = 1 + new_parameters["plus_times"].value = 5 + new_calculator = self.__default_calculator(parameters=new_parameters) + self.assertIsInstance(new_calculator, PlusCalculator) + self.assertIsInstance(new_calculator, BaseCalculator) + self.assertIsInstance(new_calculator, AbstractBaseClass) + self.assertEqual(new_calculator.parameters["plus_times"].value, 5) + self.assertEqual(self.__default_calculator.parameters["plus_times"].value, 1) + + def test_dump(self): + """Test dumping to file.""" + calculator = self.__default_calculator + + self.__files_to_remove.append(calculator.dump()) + self.__files_to_remove.append(calculator.dump("dump.dill")) + + def test_parameters_in_copied_calculator(self): + """Test parameters in a copied calculator""" + + calculator = self.__default_calculator + self.assertEqual(calculator.parameters["plus_times"].value, 1) + calculator.parameters["plus_times"] = 5 + self.assertEqual(self.__default_calculator.parameters["plus_times"].value, 5) + calculator.parameters["plus_times"] = 1 + self.assertEqual(self.__default_calculator.parameters["plus_times"].value, 1) + + def test_resurrect_from_dump(self): + """Test loading from dumpfile.""" + + calculator = self.__default_calculator() + + self.assertEqual(calculator.parameters["plus_times"].value, 1) + output = calculator.backengine() + self.assertEqual(output.get_data()["number"], 2) + self.__dirs_to_remove.append("PlusCalculator") + + # dump + dump = calculator.dump() + self.__files_to_remove.append(dump) + + del calculator + + calculator = PlusCalculator.from_dump(dump) + + self.assertEqual( + calculator.input.get_data(), + self.__default_calculator.input.get_data(), + ) + + calculator.parameters.to_dict() + self.assertEqual( + calculator.parameters.to_dict(), + self.__default_calculator.parameters.to_dict(), + ) + + calculator.parameters["plus_times"] = 5 + self.assertNotEqual( + calculator.parameters.to_dict(), + self.__default_calculator.parameters.to_dict(), + ) + + self.assertIsNotNone(calculator.data) + + def test_attributes(self): + """Test that all required attributes are present.""" + + calculator = self.__default_calculator + + self.assertTrue(hasattr(calculator, "name")) + self.assertTrue(hasattr(calculator, "input")) + self.assertTrue(hasattr(calculator, "output")) + self.assertTrue(hasattr(calculator, "parameters")) + self.assertTrue(hasattr(calculator, "instrument_base_dir")) + self.assertTrue(hasattr(calculator, "calculator_base_dir")) + self.assertTrue(hasattr(calculator, "base_dir")) + self.assertTrue(hasattr(calculator, "backengine")) + self.assertTrue(hasattr(calculator, "data")) + self.assertTrue(hasattr(calculator, "dump")) + self.assertTrue(hasattr(calculator, "from_dump")) + + def test_set_param_values(self): + calculator = self.__default_calculator + + calculator.parameters["plus_times"] = 5 + self.assertEqual(calculator.parameters["plus_times"].value, 5) + + def test_collection_get_data(self): + calculator = self.__default_calculator + print(calculator.input) + input_dict = calculator.input.get_data() + self.assertEqual(input_dict["input1"]["number"], 1) + self.assertEqual(input_dict["input2"]["number"], 1) + + def test_output_file_paths(self): + calculator = self.__default_calculator + with self.assertRaises(ValueError) as exception: + calculator.output_file_paths + + calculator.output_filenames = "bingo.txt" + self.assertEqual(calculator.output_file_paths[0], "PlusCalculator/bingo.txt") + self.__dirs_to_remove.append("PlusCalculator") + + def test_calculator_output_set_inconsistent(self): + input1 = NumberData.from_dict({"number": 1}, "input1") + with self.assertRaises(ValueError) as exception: + calculator = PlusCalculator( + "test", input1, output_keys=["result"], output_data_types=[] + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/unit/test_BaseData.py b/tests/unit/test_BaseData.py new file mode 100644 index 0000000..d70493e --- /dev/null +++ b/tests/unit/test_BaseData.py @@ -0,0 +1,422 @@ +import pytest +import numpy as np +import h5py +from libpyvinyl.BaseData import BaseData, DataCollection +from libpyvinyl.BaseFormat import BaseFormat + + +class NumberData(BaseData): + def __init__( + self, + key, + data_dict=None, + filename=None, + file_format_class=None, + file_format_kwargs=None, + ): + + ### DataClass developer's job start + expected_data = {} + expected_data["number"] = None + ### DataClass developer's job end + + super().__init__( + key, + expected_data, + data_dict, + filename, + file_format_class, + file_format_kwargs, + ) + + @classmethod + def supported_formats(self): + format_dict = {} + ### DataClass developer's job start + self._add_ioformat(format_dict, TXTFormat) + self._add_ioformat(format_dict, H5Format) + ### DataClass developer's job end + return format_dict + + +class TXTFormat(BaseFormat): + def __init__(self) -> None: + super().__init__() + + @classmethod + def format_register(self): + key = "TXT" + desciption = "TXT format for NumberData" + file_extension = ".txt" + read_kwargs = [""] + write_kwargs = [""] + return self._create_format_register( + key, desciption, file_extension, read_kwargs, write_kwargs + ) + + @classmethod + def read(cls, filename: str) -> dict: + """Read the data from the file with the `filename` to a dictionary. The dictionary will + be used by its corresponding data class.""" + number = float(np.loadtxt(filename)) + data_dict = {"number": number} + return data_dict + + @classmethod + def write(cls, object: NumberData, filename: str, key: str = None): + """Save the data with the `filename`.""" + data_dict = object.get_data() + arr = np.array([data_dict["number"]]) + np.savetxt(filename, arr, fmt="%.3f") + if key is None: + original_key = object.key + key = original_key + "_to_TXTFormat" + return object.from_file(filename, cls, key) + else: + return object.from_file(filename, cls, key) + + @staticmethod + def direct_convert_formats(): + # Assume the format can be converted directly to the formats supported by these classes: + # AFormat, BFormat + # Redefine this `direct_convert_formats` for a concrete format class + return [H5Format] + + @classmethod + def convert( + cls, obj: NumberData, output: str, output_format_class: str, key=None, **kwargs + ): + """Direct convert method, if the default converting would be too slow or not suitable for the output_format""" + if output_format_class is H5Format: + cls.convert_to_H5Format(obj.filename, output) + else: + raise TypeError( + "Direct converting to format {} is not supported".format( + output_format_class + ) + ) + # Set the key of the returned object + if key is None: + original_key = obj.key + key = original_key + "_from_TXTFormat" + return obj.from_file(output, output_format_class, key) + else: + return obj.from_file(output, output_format_class, key) + + @classmethod + def convert_to_H5Format(cls, input: str, output: str): + """The engine of convert method.""" + print("Directly converting TXTFormat to H5Format") + number = float(np.loadtxt(input)) + with h5py.File(output, "w") as h5: + h5["number"] = number + + +class H5Format(BaseFormat): + def __init__(self) -> None: + super().__init__() + + @classmethod + def format_register(self): + key = "H5" + desciption = "H5 format for NumberData" + file_extension = ".h5" + read_kwargs = [""] + write_kwargs = [""] + return self._create_format_register( + key, desciption, file_extension, read_kwargs, write_kwargs + ) + + @classmethod + def read(cls, filename: str) -> dict: + """Read the data from the file with the `filename` to a dictionary. The dictionary will + be used by its corresponding data class.""" + with h5py.File(filename, "r") as h5: + number = h5["number"][()] + data_dict = {"number": number} + return data_dict + + @classmethod + def write(cls, object: NumberData, filename: str, key: str = None): + """Save the data with the `filename`.""" + data_dict = object.get_data() + number = data_dict["number"] + with h5py.File(filename, "w") as h5: + h5["number"] = number + if key is None: + original_key = object.key + key = original_key + "_to_H5Format" + return object.from_file(filename, cls, key) + else: + return object.from_file(filename, cls, key) + + @staticmethod + def direct_convert_formats(): + # Assume the format can be converted directly to the formats supported by these classes: + # AFormat, BFormat + # Redefine this `direct_convert_formats` for a concrete format class + return [] + + +@pytest.fixture() +def txt_file(tmp_path_factory): + fn_path = tmp_path_factory.mktemp("test_data") / "test.txt" + txt_file = str(fn_path) + with open(txt_file, "w") as f: + f.write("4") + return txt_file + + +# Data class section +def test_list_formats(capsys): + """Test listing registered format classes""" + NumberData.list_formats() + captured = capsys.readouterr() + assert "Key: TXT" in captured.out + assert "Key: H5" in captured.out + + +def test_create_empty_data_instance(): + """Test creating an empty data instance""" + with pytest.raises(TypeError): + number_data = NumberData() + test_data = NumberData(key="test_data") + assert isinstance(test_data, NumberData) + + +def test_create_data_with_set_dict(): + """Test set dict after in an empty data instance""" + test_data = NumberData(key="test_data") + my_dict = {"number": 4} + test_data.set_dict(my_dict) + assert test_data.get_data()["number"] == 4 + + +def test_create_data_with_set_file(txt_file): + """Test set file after in an empty data instance""" + test_data = NumberData(key="test_data") + test_data.set_file(txt_file, TXTFormat) + assert test_data.get_data()["number"] == 4 + + +def test_create_data_with_set_file_inconsistensy(txt_file): + """Test set dict and file for one data object: expecting an error""" + test_data = NumberData(key="test_data") + my_dict = {"number": 4} + test_data.set_dict(my_dict) + with pytest.raises(RuntimeError): + test_data.set_file(txt_file, TXTFormat) + + +def test_create_data_with_set_file_wrong_param(txt_file): + """Test set file after in an empty data instance with wrong `format_class` param""" + test_data = NumberData(key="test_data") + with pytest.raises(TypeError): + test_data.set_file(txt_file, "txt") + + +def test_create_data_with_set_file_wrong_format(txt_file): + """Test set file after in an empty data instance with wrong `format_class`""" + test_data = NumberData(key="test_data") + test_data.set_file(txt_file, H5Format) + with pytest.raises(OSError): + test_data.get_data() + + +def test_create_data_with_file(): + """Test set dict after in an empty data instance""" + test_data = NumberData(key="test_data") + assert isinstance(test_data, NumberData) + my_dict = {"number": 4} + test_data.set_dict(my_dict) + assert test_data.get_data()["number"] == 4 + + +def test_create_data_from_dict(): + """Test creating a data instance from a dict""" + my_dict = {"number": 4} + test_data = NumberData.from_dict(my_dict, "test_data") + + +def test_check_key_from_dict(): + """Test checking expected data key from dict""" + my_dict = {"number": 4} + test_data = NumberData.from_dict(my_dict, "test_data") + test_data.get_data() + my_dict = {"numberr": 4} + test_data = NumberData.from_dict(my_dict, "test_data") + with pytest.raises(KeyError): + test_data.get_data() + + +def test_create_data_from_file_wrong_param(txt_file): + """Test creating a data instance from a file in a wrong file format type""" + with pytest.raises(TypeError): + test_data = NumberData.from_file(txt_file, "txt", "test_data") + + +def test_create_data_from_TXTFormat(txt_file): + """Test creating a data instance from a file in TXTFormat""" + test_data = NumberData.from_file(txt_file, TXTFormat, "test_data") + assert test_data.get_data()["number"] == 4 + + +def test_create_data_from_wrong_format(txt_file): + """Test creating a data instance from a file in TXTFormat""" + test_data = NumberData.from_file(txt_file, H5Format, "test_data") + with pytest.raises(OSError): + test_data.get_data() + +def test_duplicate_data_TXTFormat(txt_file, tmpdir, capsys): + """Test creating a data instance from a file in TXTFormat""" + test_data = NumberData.from_file(txt_file, TXTFormat, "test_data") + test_data.write(str(tmpdir/"new_data.txt"),TXTFormat) + captured = capsys.readouterr() + assert "data already existed" in captured.out + +def test_save_dict_data_in_TXTFormat(tmpdir): + """Test saving a dict data in TXTFormat""" + my_dict = {"number": 4} + test_data = NumberData.from_dict(my_dict, "test_data") + fn = str(tmpdir / "test.txt") + test_data.write(fn, TXTFormat) + read_data = NumberData.from_file(fn, TXTFormat, "read_data") + assert read_data.get_data()["number"] == 4 + + +def test_save_dict_data_in_TXTFormat_return_data_object(tmpdir): + """Test saving a dict data in TXTFormat returning data object with default key""" + my_dict = {"number": 4} + test_data = NumberData.from_dict(my_dict, "test_data") + fn = str(tmpdir / "test.txt") + return_data = test_data.write(fn, TXTFormat) + assert return_data.get_data()["number"] == 4 + assert return_data.key == "test_data_to_TXTFormat" + + +def test_save_dict_data_in_TXTFormat_return_data_object_key(tmpdir): + """Test saving a dict data in TXTFormat returning data object with custom key""" + my_dict = {"number": 4} + test_data = NumberData.from_dict(my_dict, "test_data") + print(test_data) + # assert False + fn = str(tmpdir / "test.txt") + return_data = test_data.write(fn, TXTFormat, "custom") + assert return_data.get_data()["number"] == 4 + assert return_data.key == "custom" + + +def test_save_file_data_in_another_format_direct(txt_file, tmpdir, capsys): + """Test directly converting a TXTFormat data to H5Format""" + test_data = NumberData.from_file(txt_file, TXTFormat, "test_data") + # print(test_data) + fn = str(tmpdir / "test.h5") + return_data = test_data.write(fn, H5Format) + captured = capsys.readouterr() + assert "Directly converting TXTFormat to H5Format" in captured.out + assert return_data.get_data()["number"] == 4 + assert return_data.key == "test_data_from_TXTFormat" + return_data = test_data.write(fn, H5Format, "txt2h5") + assert return_data.key == "txt2h5" + # print(return_data) + # assert False + + +def test_save_file_data_in_another_format_indirect(tmpdir): + """Test directly converting a TXTFormat data to H5Format""" + my_dict = {"number": 4} + test_data = NumberData.from_dict(my_dict, "test_data") + fn = str(tmpdir / "test.h5") + h5_data = test_data.write(fn, H5Format, "test_data") + fn = str(tmpdir / "test.txt") + return_data = h5_data.write(fn, TXTFormat) + print(return_data) + assert return_data.get_data()["number"] == 4 + assert return_data.key == "test_data_to_TXTFormat" + return_data = test_data.write(fn, H5Format, "txt2h5") + assert return_data.key == "txt2h5" + # print(return_data) + # assert False + + +# Data collection section +def test_DataCollection_instance(): + """Test creating a DataCollection instance""" + collection = DataCollection() + assert isinstance(collection, DataCollection) + + +def test_DataCollection_one_data(txt_file): + """Test a DataCollection instance with one dataset""" + test_data = NumberData.from_file(txt_file, TXTFormat, "test_data") + collection = DataCollection(test_data) + data_in_collection = collection["test_data"] + assert collection.get_data() == data_in_collection.get_data() + + +def test_DataCollection_one_data_write(txt_file, tmpdir): + """Test a DataCollection instance with one dataset""" + test_data = NumberData.from_file(txt_file, TXTFormat, "test_data") + collection = DataCollection(test_data) + fn = str(tmpdir / "data.h5") + written_data = collection.write(fn, H5Format) + assert written_data.mapping_type == H5Format + assert written_data.get_data()["number"] == 4 + + +def test_DataCollection_two_data(txt_file): + """Test creating a DataCollection instance with two datasets""" + my_dict = {"number": 5} + test_data_txt = NumberData.from_file(txt_file, TXTFormat, "test_txt") + test_data_dict = NumberData.from_dict(my_dict, "test_dict") + collection = DataCollection(test_data_txt, test_data_dict) + assert collection["test_dict"].get_data()["number"] == 5 + assert collection["test_txt"].get_data()["number"] == 4 + value_collection = collection.get_data() + assert value_collection["test_dict"]["number"] == 5 + assert value_collection["test_txt"]["number"] == 4 + + +def test_DataCollection_two_data_write(txt_file, tmpdir): + """Test writing a DataCollection instance with two datasets""" + my_dict = {"number": 5} + test_data_txt = NumberData.from_file(txt_file, TXTFormat, "test_txt") + test_data_dict = NumberData.from_dict(my_dict, "test_dict") + collection = DataCollection(test_data_txt, test_data_dict) + fn_txt = str(tmpdir / "data_new.txt") + fn_h5 = str(tmpdir / "data_new.h5") + filenames = {"test_txt": fn_h5, "test_dict": fn_txt} + format_classes = {"test_txt": H5Format, "test_dict": TXTFormat} + keys = {"test_txt": None, "test_dict": None} + written_collection = collection.write(filenames, format_classes, keys) + # Create a new data collection from the collection dict + new_collection = DataCollection(*written_collection.values()) + assert new_collection["test_dict_to_TXTFormat"].get_data()["number"] == 5 + + +def test_DataCollection_add_data(txt_file): + """Test adding data to a DataCollection instance""" + my_dict = {"number": 5} + test_data_dict = NumberData.from_dict(my_dict, "test_dict") + test_data_txt = NumberData.from_file(txt_file, TXTFormat, "test_txt") + collection = DataCollection() + collection.add_data(test_data_dict, test_data_txt) + print(collection) + + +def test_DataCollection_add_wrong_data_type(): + """Test adding data in wrong type to a DataCollection instance""" + collection = DataCollection() + with pytest.raises(AssertionError): + collection.add_data(0) + + +def test_DataCollection_to_list(txt_file): + """Test returning a DataCollection as a list""" + my_dict = {"number": 5} + test_data_dict = NumberData.from_dict(my_dict, "test_dict") + test_data_txt = NumberData.from_file(txt_file, TXTFormat, "test_txt") + collection = DataCollection(test_data_dict, test_data_txt) + my_list = collection.to_list() + assert my_list[0].get_data()["number"] == 5 + assert my_list[1].get_data()["number"] == 4 diff --git a/tests/unit/test_Instrument.py b/tests/unit/test_Instrument.py new file mode 100644 index 0000000..0e6dc7f --- /dev/null +++ b/tests/unit/test_Instrument.py @@ -0,0 +1,119 @@ +import unittest +import os +import shutil + +from test_BaseCalculator import PlusCalculator, NumberData +from libpyvinyl.Instrument import Instrument + + +class InstrumentTest(unittest.TestCase): + """ + Test class for the Detector class. + """ + + @classmethod + def setUpClass(cls): + """Setting up the test class.""" + input1 = NumberData.from_dict({"number": 1}, "input1") + input2 = NumberData.from_dict({"number": 1}, "input2") + calculator1 = PlusCalculator("test1", [input1, input2]) + cls.calculator1 = calculator1 + calculator2 = PlusCalculator("test2", [input1, input2]) + calculator2.parameters["plus_times"] = 12 + cls.calculator2 = calculator2 + + @classmethod + def tearDownClass(cls): + """Tearing down the test class.""" + pass + + def setUp(self): + """Setting up a test.""" + self.__files_to_remove = [] + self.__dirs_to_remove = [] + + def tearDown(self): + """Tearing down a test.""" + + for f in self.__files_to_remove: + if os.path.isfile(f): + os.remove(f) + for d in self.__dirs_to_remove: + if os.path.isdir(d): + shutil.rmtree(d) + + def testInstrumentConstruction(self): + """Testing the default construction of the class.""" + + # Construct the object. + my_instrument = Instrument("myInstrument") + my_instrument.add_calculator(self.calculator1) + my_instrument.add_calculator(self.calculator2) + + def testListCalculator(self): + """Testing list calculators""" + + # Construct the object. + my_instrument = Instrument("myInstrument") + my_instrument.add_calculator(self.calculator1) + my_instrument.add_calculator(self.calculator2) + my_instrument.list_calculators() + + def testListParams(self): + """Testing listing parameters""" + + my_instrument = Instrument("myInstrument") + my_instrument.add_calculator(self.calculator1) + my_instrument.add_calculator(self.calculator2) + my_instrument.list_parameters() + + def testRemoveCalculator(self): + """Testing remove calculator""" + + my_instrument = Instrument("myInstrument") + my_instrument.add_calculator(self.calculator1) + my_instrument.add_calculator(self.calculator2) + self.assertEqual(len(my_instrument.calculators), 2) + my_instrument.remove_calculator(self.calculator1.name) + self.assertEqual(len(my_instrument.calculators), 1) + + def testEditCalculator(self): + """Testing edit calculator""" + my_instrument = Instrument("myInstrument") + my_instrument.add_calculator(self.calculator1) + my_instrument.parameters["test1"]["plus_times"] = 10 + my_instrument.parameters["test1"]["plus_times"] = 15 + energy1 = my_instrument.calculators["test1"].parameters["plus_times"].value + self.assertEqual(energy1, 15) + + def testAddMaster(self): + """Testing remove calculator""" + + my_instrument = Instrument("myInstrument") + my_instrument.add_calculator(self.calculator1) + my_instrument.add_calculator(self.calculator2) + links = {"test1": "plus_times", "test2": "plus_times"} + my_instrument.add_master_parameter("plus_times", links) + my_instrument.master["plus_times"] = 10 + tims1 = my_instrument.calculators["test1"].parameters["plus_times"].value + tims2 = my_instrument.calculators["test2"].parameters["plus_times"].value + self.assertEqual(tims1, 10) + self.assertEqual(tims2, 10) + + def testSetBasePath(self): + """Testing setup base path for calculators""" + + my_instrument = Instrument("myInstrument") + my_instrument.add_calculator(self.calculator1) + my_instrument.add_calculator(self.calculator2) + my_instrument.set_instrument_base_dir("test") + self.assertEqual( + my_instrument.calculators["test1"].base_dir, "test/PlusCalculator" + ) + self.assertEqual( + my_instrument.calculators["test2"].base_dir, "test/PlusCalculator" + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/unit/test_Parameters.py b/tests/unit/test_Parameters.py new file mode 100644 index 0000000..30d2aaf --- /dev/null +++ b/tests/unit/test_Parameters.py @@ -0,0 +1,596 @@ +import unittest +import numpy +import pytest +import os +import tempfile +from pint.quantity import Quantity +from pint.unit import Unit +from libpyvinyl.Parameters import Parameter +from libpyvinyl.Parameters import CalculatorParameters +from libpyvinyl.Parameters import InstrumentParameters + + +class Test_Parameter(unittest.TestCase): + def test_initialize_parameter_simple(self): + par = Parameter("test") + self.assertEqual(par.name, "test") + + def test_initialize_parameter_complex(self): + par = Parameter("test", unit="cm", comment="comment string") + self.assertEqual(par.name, "test") + assert par.unit == str(Unit("cm")) + self.assertEqual(par.comment, "comment string") + + def test_units_assignment(self): + par = Parameter("test", unit="kg") + assert par.unit == Unit("kg") + par.unit = "cm" + assert par.unit == Unit("cm") + par.unit = "meter" + assert par.unit == Unit("m") + assert par.unit == str(Unit("m")) + assert par.unit == "meter" + par.unit = "nounit" + assert par.unit == "nounit" + + def test_check_value_type(self): + par = Parameter("test") + v = 1 + par._Parameter__check_compatibility(v) + par._Parameter__set_value_type(v) + assert par._Parameter__value_type == int + + v = 1.0 + par._Parameter__check_compatibility(v) + par._Parameter__set_value_type(v) + assert par._Parameter__value_type == Quantity + + v = "string" + with pytest.raises(TypeError): + par._Parameter__check_compatibility(v) + par._Parameter__set_value_type(v) + assert par._Parameter__value_type == str + + v = True + par = Parameter("test") + par._Parameter__set_value_type("string") + assert par._Parameter__value_type == str + with pytest.raises(TypeError): + par._Parameter__check_compatibility(v) + + par = Parameter("test") + par._Parameter__set_value_type(True) + assert par._Parameter__value_type == bool + + v = ["ciao", True] + par = Parameter("test") + with pytest.raises(TypeError): + par._Parameter__check_compatibility(v) + par._Parameter__set_value_type([False, True]) + + v = {"ciao": True, "bye": "string"} + par = Parameter("test") + with pytest.raises(NotImplementedError): + par._Parameter__check_compatibility(v) + v = {"ciao": True, "bye": False} + with pytest.raises(NotImplementedError): + par._Parameter__check_compatibility(v) + + v = numpy.random.uniform(0, 1, 10) + par = Parameter("test") + par._Parameter__check_compatibility(v) + par._Parameter__set_value_type(v) + assert par._Parameter__value_type == Quantity + + # no conditions + def test_parameter_no_legal_conditions(self): + par = Parameter("test") + self.assertTrue(par.is_legal(None)) # FIXME how is this supposed to work? + self.assertTrue(par.is_legal(-999)) + self.assertTrue(par.is_legal(-1)) + self.assertTrue(par.is_legal(0)) + self.assertTrue(par.is_legal(1)) + self.assertTrue(par.is_legal("This is a string")) + self.assertTrue(par.is_legal(True)) + self.assertTrue(par.is_legal(False)) + self.assertTrue(par.is_legal([0, "A", True])) + + # case 1: only legal interval + def test_parameter_legal_interval(self): + par = Parameter("test") + par.add_interval(3, 4.5, True) + + self.assertTrue(par.is_legal(3.5)) + self.assertFalse(par.is_legal(1.0)) + + # case 2: only illegal interval + def test_parameter_illegal_interval(self): + par = Parameter("test") + par.add_interval(3, 4.5, False) + + self.assertFalse(par.is_legal(3.5)) + self.assertTrue(par.is_legal(1.0)) + + def test_parameter_multiple_intervals(self): + par = Parameter("test") + par.add_interval(None, 8.5, True) # minus infinite to 8.5 + + self.assertRaises(ValueError, par.add_interval, 3, 4.5, False) + self.assertTrue(par.is_legal(-831.0)) + self.assertTrue(par.is_legal(3.5)) + self.assertTrue(par.is_legal(5.0)) + self.assertFalse(par.is_legal(10.0)) + + def test_values_different_types(self): + par = Parameter("test") + par.add_option(9.8, True) + with pytest.raises(TypeError): + par.add_option(True, True) + + # case 1: only legal option + def test_parameter_legal_option_float(self): + par = Parameter("test") + par.add_option(9.8, True) + + self.assertFalse(par.is_legal(10)) + self.assertTrue(par.is_legal(9.8)) + self.assertFalse(par.is_legal(True)) + self.assertFalse(par.is_legal("A")) + self.assertFalse(par.is_legal(38)) + + # case 1: only legal option + def test_parameter_legal_option_bool(self): + par = Parameter("test") + par.add_option(True, True) + + self.assertFalse(par.is_legal(10)) + self.assertFalse(par.is_legal(9.8)) + self.assertTrue(par.is_legal(True)) + self.assertFalse(par.is_legal("A")) + self.assertFalse(par.is_legal(38)) + + # case 1: only legal option + def test_parameter_legal_option_float_and_int(self): + par = Parameter("test") + par.add_option(9.8, True) + par.add_option(38, True) + + self.assertFalse(par.is_legal(10)) + self.assertTrue(par.is_legal(9.8)) + self.assertFalse(par.is_legal(True)) + self.assertFalse(par.is_legal("A")) + self.assertTrue(par.is_legal(38)) + + # case 1: only legal option + def test_parameter_legal_option_int_and_float(self): + par = Parameter("test") + par.add_option(38, True) + par.add_option(9.8, True) + + self.assertFalse(par.is_legal(10)) + self.assertTrue(par.is_legal(9.8)) + self.assertFalse(par.is_legal(True)) + self.assertFalse(par.is_legal("A")) + self.assertTrue(par.is_legal(38)) + + # case 1: only legal option + def test_parameter_legal_option_fromlist(self): + par = Parameter("test") + par.add_option([9, 8, 38], True) + + self.assertFalse(par.is_legal(10)) + self.assertFalse(par.is_legal(9.8)) + self.assertFalse(par.is_legal(True)) + self.assertFalse(par.is_legal("A")) + self.assertTrue(par.is_legal(38)) + self.assertTrue(par.is_legal(38.0)) + self.assertTrue(par.is_legal(8)) + + # case 1: only legal option + + def test_parameter_legal_option_string(self): + par = Parameter("test") + par.add_option(["B", "A"], True) + + self.assertFalse(par.is_legal(10)) + self.assertFalse(par.is_legal(9.8)) + self.assertFalse(par.is_legal(True)) + self.assertTrue(par.is_legal("A")) + self.assertTrue(par.is_legal("B")) + self.assertFalse(par.is_legal("C")) + self.assertFalse(par.is_legal(38)) + + def test_parameter_multiple_options(self): + par = Parameter("test") + par.add_option(9.8, True) + + self.assertRaises(ValueError, par.add_option, 3, False) + self.assertFalse(par.is_legal(-831.0)) + self.assertTrue(par.is_legal(9.8)) + self.assertFalse(par.is_legal(3)) + + # case 1: legal interval + legal option + def test_parameter_legal_interval_plus_legal_option(self): + par = Parameter("test") + par.add_interval(None, 8.5, True) # minus infinite to 8.5 + par.add_option(5, True) # this is stupid, already accounted in the interval + par.add_option(11, True) + + self.assertTrue(par.is_legal(-831.0)) + self.assertTrue(par.is_legal(8.5)) + self.assertTrue(par.is_legal(5.0)) + self.assertFalse(par.is_legal(10.0)) + self.assertTrue(par.is_legal(11.0)) + + # case 2: illegal interval + illegal option + def test_parameter_illegal_interval_plus_illegal_option(self): + par = Parameter("test") + par.add_interval(None, 8.5, False) # minus infinite to 8.5 + par.add_option(5, False) # this is stupid, already accounted in the interval + par.add_option(11, False) + + self.assertFalse(par.is_legal(-831.0)) + self.assertFalse(par.is_legal(8.5)) # illegal because closed interval + self.assertFalse(par.is_legal(5.0)) + self.assertTrue(par.is_legal(10.0)) + self.assertFalse(par.is_legal(11.0)) + + # case 3: legal interval + illegal option + def test_parameter_legal_interval_plus_illegal_option(self): + par = Parameter("test") + par.add_interval(None, 8.5, True) # minus infinite to 8.5 + par.add_option(5, False) + + self.assertTrue(par.is_legal(-831.0)) + self.assertTrue(par.is_legal(8.5)) + self.assertFalse(par.is_legal(5.0)) + self.assertFalse(par.is_legal(10.0)) + self.assertFalse(par.is_legal(11.0)) + + # case 4: illegal interval + legal option + def test_parameter_illegal_interval_plus_legal_option(self): + par = Parameter("test") + par.add_interval(None, 8.5, False) # minus infinite to 8.5 + par.add_option(5, True) + + self.assertFalse(par.is_legal(-831.0)) + self.assertFalse(par.is_legal(8.5)) + self.assertTrue(par.is_legal(5.0)) + self.assertTrue(par.is_legal(10.0)) + self.assertTrue(par.is_legal(11.0)) + + def test_parameter_value_type(self): + par = Parameter("test") + par.value = 4.0 + assert par._Parameter__value_type == Quantity + + par1 = Parameter("test") + par1.value = 4 + assert par1._Parameter__value_type == int + + par2 = Parameter("test", unit="meV") + par2.value = 4 + assert par2._Parameter__value_type == Quantity + + par3 = Parameter("test", unit="meV") + par3.add_interval(0, 1e6, True) + assert par3._Parameter__value_type == Quantity + + def test_parameter_set_value(self): + par = Parameter("test") + par.add_interval(3, 4.5, True) + + par.value = 4.0 + self.assertEqual(par.value, 4.0) + + with self.assertRaises(ValueError): + par.value = 5.0 # Should throw an error and be ignored + + self.assertEqual(par.value, 4.0) + + def test_add_interval_after_value(self): + par = Parameter("test") + par.value = 4.0 + par.add_interval(3, 4.5, True) + + par.clear_intervals() + par.value = 5.0 + with self.assertRaises(ValueError): + par.add_interval(3, 4.5, True) + + def test_parameter_from_dict(self): + par = Parameter("test") + + par.add_interval(3, 4.5, True) + par.value = 4.0 + par_from_dict = Parameter.from_dict(par.__dict__) + self.assertEqual(par_from_dict.value, 4.0) + + def test_print_legal_interval(self): + par = Parameter("test") + par.add_interval(3, 4.5, True) + par.add_option(9.8, True) + par.print_paramter_constraints() + + def test_clear_intervals(self): # FIXME + par = Parameter("test") + par.add_interval(3, 4.5, True) + # self.assertEqual(par.__intervals, [[3, 4.5]]) #FIXME + + par.clear_intervals() + par.add_option(9.7, True) + # self.assertEqual(par.__options, [9.7]) + par.clear_options() + + # self.assertEqual(par.__options, []) + + def test_print_line(self): + par = Parameter("test") + par.add_interval(3, 4.5, True) + par.add_option(9.8, True) + par.print_line() + + def test_print(self): + par = Parameter("test") + par.add_interval(3, 4.5, True) + par.add_option(9.8, True) + print(par) + + def test_parameter_iterable(self): + par = Parameter("test") + par.add_interval(3, 4.5, True) + par.add_option(7, True) + self.assertFalse(par.is_legal([0.5, 3.2, 5.0])) + self.assertTrue(par.is_legal([3.1, 4.2, 4.4])) + self.assertTrue(par.is_legal([3.1, 4.2, 4.4, 7])) + + def test_parameters_with_quantity(self): + """Test if we can construct and use a Parameter instance passing pint.Quantity and pint.Unit objects to the constructor and interval setter.""" + + # Define the base unit of my parameter object. + meter = Unit("meter") + self.assertIsInstance(meter, Unit) + + minimum_undulator_length = 10.0 * meter + undulator_length = Parameter("undulator_length", meter) + + self.assertIsInstance(undulator_length, Parameter) + self.assertEqual(undulator_length.unit, Unit("meter")) + + undulator_length.add_interval( + min_value=minimum_undulator_length, + max_value=numpy.inf * meter, + intervals_are_legal=True, + ) + + self.assertTrue(undulator_length.is_legal(10.1 * meter)) + self.assertFalse(undulator_length.is_legal(9.0 * meter)) + self.assertTrue(undulator_length.is_legal(5.5e4 * Unit("centimeter"))) + + def test_parameter_set_numpy_value(self): + par = Parameter("test", unit="eV") + par.value = 1e-4 + par.value = numpy.log(10) + + def test_parameters_with_quantity_powers(self): + """Test if we can construct and use a Parameter instance passing pint.Quantity and pint.Unit objects to the constructor and interval setter. Use different powers of 10 in parameter initialization and value assignment.""" + + # Define the base unit of my parameter object. + meter = Unit("meter") + centimeter = Unit("centimeter") + self.assertIsInstance(meter, Unit) + + minimum_undulator_length = 10.0 * meter + undulator_length = Parameter("undulator_length", centimeter) + + self.assertIsInstance(undulator_length, Parameter) + self.assertEqual(undulator_length.unit, Unit("centimeter")) + + undulator_length.add_interval( + min_value=minimum_undulator_length, + max_value=numpy.inf * meter, + intervals_are_legal=True, + ) + + print(undulator_length) + + self.assertTrue(undulator_length.is_legal(10.1 * meter)) + self.assertFalse(undulator_length.is_legal(9.0 * centimeter)) + self.assertTrue(undulator_length.is_legal(5.5e4 * Unit("centimeter"))) + + +class Test_Parameters(unittest.TestCase): + def test_initialize_parameters_from_list(self): + par1 = Parameter("test") + par1.value = 8 + par2 = Parameter("test2", unit="meV") + + parameters = CalculatorParameters([par1, par2]) + + self.assertEqual(parameters["test"].value, 8) + + def test_initialize_parameters_from_add(self): + par1 = Parameter("test") + par1.value = 8 + par2 = Parameter("test2", unit="meV") + par2.value = 10 + + parameters = CalculatorParameters() + parameters.add(par1) + parameters.add(par2) + + self.assertEqual(parameters["test"].value, 8) + self.assertEqual(parameters["test2"].value, 10) + + def test_print_parameters(self): + par1 = Parameter("test") + par1.value = 8 + par2 = Parameter("test2", unit="meV") + par2.value = 10 + parameters = CalculatorParameters() + parameters.add(par1) + parameters.add(par2) + print(parameters) + + def test_json(self): + par1 = Parameter("test") + par1.value = 8.0 + par2 = Parameter("test2", unit="meV") + par2.value = 10 + + parameters = CalculatorParameters() + parameters.add(par1) + parameters.add(par2) + + with tempfile.TemporaryDirectory() as d: + tmp_file = os.path.join(d, "test.json") + parameters.to_json(tmp_file) + params_json = CalculatorParameters.from_json(tmp_file) + self.assertEqual(params_json["test2"].value, 10) + assert params_json["test2"].value_no_conversion == Quantity(10, "meV") + with pytest.raises(TypeError): + params_json["test2"].value = "A" + + def test_json_with_objects(self): + par1 = Parameter("test") + par1.value = 8 + par2 = Parameter("test2", unit="meV") + par2.value = 10 + par3 = Parameter("test3", unit="meV") + par3.value = 3.14 + + parameters = CalculatorParameters() + parameters.add(par1) + parameters.add(par2) + parameters.add(par3) + with tempfile.TemporaryDirectory() as d: + tmp_file = os.path.join(d, "test.json") + tmp_file = "/tmp/test.json" + parameters.to_json(tmp_file) + params_json = CalculatorParameters.from_json(tmp_file) + self.assertEqual(params_json["test2"].value, 10) + print(params_json["test3"]) + assert params_json["test3"].value == par3.value + assert params_json["test3"].value == 3.14 + assert params_json["test3"].value_no_conversion == Quantity(3.14, "meV") + + def test_get_item(self): + par1 = Parameter("test") + par1.value = 8 + par2 = Parameter("test2", unit="meV") + par2.value = 10 + + parameters = CalculatorParameters() + self.assertRaises(KeyError, parameters.__getitem__, "test3") + + +def source_calculator(): + """ + Little dummy calculator that sets up a parameters object for a source + """ + parameters = CalculatorParameters() + parameters.new_parameter("energy", unit="eV", comment="Source energy setting") + parameters["energy"].add_interval(0, 1e6, True) + parameters["energy"].value = 4000 + + parameters.new_parameter("delta_energy", unit="eV", comment="Energy spread fwhm") + parameters["delta_energy"].add_interval(0, 400, True) + + parameters.new_parameter("position", unit="cm", comment="Source center") + parameters["position"].add_interval(-1.5, 1.5, True) + + parameters.new_parameter("gaussian", comment="False for flat, True for gaussian") + parameters["gaussian"].add_option([False, True], True) + + return parameters + + +def sample_calculator(): + """ + Little dummy calculator that sets up a parameters object for a sample + """ + parameters = CalculatorParameters() + parameters.new_parameter("radius", unit="cm", comment="Sample radius") + parameters["radius"].add_interval(0, None, True) # To infinite + + parameters.new_parameter("height", unit="cm", comment="Sample height") + parameters["height"].add_interval(0, None, True) + + absporption = parameters.new_parameter( + "absorption", unit="barns", comment="absorption cross section" + ) + absporption.add_interval(0, None, True) + + return parameters + + +class Test_Instruments(unittest.TestCase): + @classmethod + def setUpClass(cls): + """Setting up the test class.""" + cls.d = tempfile.TemporaryDirectory() + + def setUp(self): + # We start creating our instrument with a InstrumentParameters + self.instr_parameters = InstrumentParameters() + + # We insert a source and get some parameters out + source_pars = source_calculator() + # These are added to the instr_parameters so they can be controlled + self.instr_parameters.add("Source", source_pars) + + # We also add a few sample objects with their parameter objects + top_sample_pars = sample_calculator() + self.instr_parameters.add("Sample top", top_sample_pars) + + bottom_sample_pars = sample_calculator() + self.instr_parameters.add("Sample bottom", bottom_sample_pars) + + @classmethod + def tearDownClass(cls): + """Tearing down the test class.""" + cls.d.cleanup() + + def test_link(self): + description = "Absorption cross section for both samples" + links = {"Sample top": "absorption", "Sample bottom": "absorption"} + master_value = 3.4 + self.instr_parameters.add_master_parameter( + "absorption", links, unit="barns", comment=description + ) + self.instr_parameters.master["absorption"] = master_value + top_value = self.instr_parameters["Sample top"]["absorption"].value + bottom_value = self.instr_parameters["Sample bottom"]["absorption"].value + self.assertEqual(top_value, master_value) + self.assertEqual(bottom_value, master_value) + master_params = self.instr_parameters.master.parameters + self.assertIn("absorption", master_params.keys()) + self.assertEqual(master_value, master_params["absorption"].value) + self.assertEqual(self.instr_parameters.master["absorption"].links, links) + + def test_print(self): + print(self.instr_parameters) + + def test_json(self): + description = "Absorption cross section for both samples" + links = {"Sample top": "absorption", "Sample bottom": "absorption"} + master_value = 3.4 + self.instr_parameters.add_master_parameter( + "absorption", links, unit="barns", comment=description + ) + self.instr_parameters.master["absorption"] = master_value + temp_file = os.path.join(self.d.name, "test.json") + self.instr_parameters.to_json(temp_file) + print(self.instr_parameters) + + # From json + instr_json = InstrumentParameters.from_json(temp_file) + self.assertEqual(instr_json["Source"]["energy"].value, 4000) + master_params = instr_json.master.parameters + self.assertIn("absorption", master_params.keys()) + self.assertEqual(master_value, master_params["absorption"].value) + self.assertEqual(self.instr_parameters.master["absorption"].links, links) + + +if __name__ == "__main__": + unittest.main() From c55106925ad040914e72b22a5f4417d40e1ff014 Mon Sep 17 00:00:00 2001 From: Mads Bertelsen Date: Mon, 14 Mar 2022 13:14:04 +0100 Subject: [PATCH 02/10] BaseCalculator: Renamed current set_parameters to reset_parameters, as it deletes all current parameters. Made new set_parameters method that set_parameters connected to the calculator Have new unit test that use set_parameters with the two available input modes. (kwargs and dict) Parameters: Added get_options and get_options_are_legal methods. --- libpyvinyl/BaseCalculator.py | 18 +++++++++++++++--- libpyvinyl/Parameters/Parameter.py | 6 ++++++ tests/unit/test_BaseCalculator.py | 12 ++++++++++++ tests/unit/test_Parameters.py | 17 +++++++++++++++++ 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/libpyvinyl/BaseCalculator.py b/libpyvinyl/BaseCalculator.py index b914fa9..c4685e0 100644 --- a/libpyvinyl/BaseCalculator.py +++ b/libpyvinyl/BaseCalculator.py @@ -163,10 +163,10 @@ def parameters(self) -> CalculatorParameters: @parameters.setter def parameters(self, value: CalculatorParameters): - self.set_parameters(value) + self.reset_parameters(value) - def set_parameters(self, value: CalculatorParameters): - """Set the calculator parameters""" + def reset_parameters(self, value: CalculatorParameters): + """Resets the calculator parameters""" if isinstance(value, CalculatorParameters): self.__parameters = value elif value is None: @@ -176,6 +176,18 @@ def set_parameters(self, value: CalculatorParameters): f"Calculator: `parameters` is expected to be CalculatorParameters, not {type(value)}" ) + def set_parameters(self, args_as_dict=None, **kwargs): + """ + Sets parameters contained in this calculator using dict or kwargs + """ + if args_as_dict is not None: + parameter_dict = args_as_dict + else: + parameter_dict = kwargs + + for key, parameter_value in parameter_dict.items(): + self.parameters[key].value = parameter_value + @property def instrument_base_dir(self) -> str: return self.__instrument_base_dir diff --git a/libpyvinyl/Parameters/Parameter.py b/libpyvinyl/Parameters/Parameter.py index d07de3c..99029d6 100644 --- a/libpyvinyl/Parameters/Parameter.py +++ b/libpyvinyl/Parameters/Parameter.py @@ -339,6 +339,12 @@ def add_option(self, option, options_are_legal): + " is now illegal based on the newly added option" ) + def get_options(self): + return self.__options + + def get_options_are_legal(self): + return self.__options_are_legal + def is_legal(self, values=None): """ Checks whether or not given or contained value is legal given constraints. diff --git a/tests/unit/test_BaseCalculator.py b/tests/unit/test_BaseCalculator.py index 3f380a4..bcb5dd5 100644 --- a/tests/unit/test_BaseCalculator.py +++ b/tests/unit/test_BaseCalculator.py @@ -276,6 +276,18 @@ def test_set_param_values(self): calculator.parameters["plus_times"] = 5 self.assertEqual(calculator.parameters["plus_times"].value, 5) + def test_set_param_values_with_set_parameters(self): + calculator = self.__default_calculator + + calculator.set_parameters(plus_times=7) + self.assertEqual(calculator.parameters["plus_times"].value, 7) + + def test_set_param_values_with_set_parameters_with_dict(self): + calculator = self.__default_calculator + + calculator.set_parameters({"plus_times": 9}) + self.assertEqual(calculator.parameters["plus_times"].value, 9) + def test_collection_get_data(self): calculator = self.__default_calculator print(calculator.input) diff --git a/tests/unit/test_Parameters.py b/tests/unit/test_Parameters.py index 30d2aaf..e919775 100644 --- a/tests/unit/test_Parameters.py +++ b/tests/unit/test_Parameters.py @@ -259,6 +259,23 @@ def test_parameter_illegal_interval_plus_legal_option(self): self.assertTrue(par.is_legal(10.0)) self.assertTrue(par.is_legal(11.0)) + # case 2: illegal interval + illegal option + def test_parameter_get_options(self): + """ + Ensure get_options returns the options as required + """ + par = Parameter("test") + par.add_interval(None, 8.5, False) # minus infinite to 8.5 + par.add_option(5, True) # this is stupid, already accounted in the interval + par.add_option(11, True) + + retrieved_options = par.get_options() + + self.assertEqual(len(retrieved_options), 2) + self.assertEqual(retrieved_options[0], 5.0) + self.assertEqual(retrieved_options[1], 11.0) + self.assertTrue(par.get_options_are_legal()) + def test_parameter_value_type(self): par = Parameter("test") par.value = 4.0 From f49924cdeba8af4132ed3da2983a722789d2acaa Mon Sep 17 00:00:00 2001 From: Mads Bertelsen Date: Mon, 14 Mar 2022 13:29:58 +0100 Subject: [PATCH 03/10] Included get_intervals and get_intervals_are_legal methods to parameter. --- libpyvinyl/Parameters/Parameter.py | 6 ++++++ tests/unit/test_Parameters.py | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/libpyvinyl/Parameters/Parameter.py b/libpyvinyl/Parameters/Parameter.py index 99029d6..f30af12 100644 --- a/libpyvinyl/Parameters/Parameter.py +++ b/libpyvinyl/Parameters/Parameter.py @@ -345,6 +345,12 @@ def get_options(self): def get_options_are_legal(self): return self.__options_are_legal + def get_intervals(self): + return self.__intervals + + def get_intervals_are_legal(self): + return self.__intervals_are_legal + def is_legal(self, values=None): """ Checks whether or not given or contained value is legal given constraints. diff --git a/tests/unit/test_Parameters.py b/tests/unit/test_Parameters.py index e919775..3d53648 100644 --- a/tests/unit/test_Parameters.py +++ b/tests/unit/test_Parameters.py @@ -361,6 +361,20 @@ def test_parameter_iterable(self): self.assertTrue(par.is_legal([3.1, 4.2, 4.4])) self.assertTrue(par.is_legal([3.1, 4.2, 4.4, 7])) + def test_get_intervals(self): + par = Parameter("test") + par.add_interval(3, 4.5, True) + par.add_interval(8, 10, True) + + retrived_intervals = par.get_intervals() + self.assertEqual(len(retrived_intervals), 2) + self.assertEqual(retrived_intervals[0][0], 3) + self.assertEqual(retrived_intervals[0][1], 4.5) + self.assertEqual(retrived_intervals[1][0], 8) + self.assertEqual(retrived_intervals[1][1], 10) + + self.assertTrue(par.get_intervals_are_legal()) + def test_parameters_with_quantity(self): """Test if we can construct and use a Parameter instance passing pint.Quantity and pint.Unit objects to the constructor and interval setter.""" From 4116ad795462d4479d7d9eb4f74b8229d508fa7b Mon Sep 17 00:00:00 2001 From: Juncheng E Date: Mon, 21 Mar 2022 10:21:03 +0100 Subject: [PATCH 04/10] bump to v1.1.0 --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index facddf2..c7ae5ac 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.1.0 +current_version = 1.1.0 [metadata] description-file = README.md From 1e1b9afee5c19282754e7918a76e8aca32e5f05e Mon Sep 17 00:00:00 2001 From: Juncheng E Date: Mon, 21 Mar 2022 10:35:12 +0100 Subject: [PATCH 05/10] bump to v1.1.0 fix --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index c33e4e6..253c7b7 100644 --- a/setup.py +++ b/setup.py @@ -8,13 +8,13 @@ setup( name="libpyvinyl", packages=find_packages(include=["libpyvinyl", "libpyvinyl.*"]), - version="0.1.0", + version="1.1.0", license="LGPLv3", description="The python API for photon and neutron simulation codes in the Photon and Neutron Open Science Cloud (PaNOSC).", author="Carsten Fortmann-Grote, Juncheng E, Mads Bertelsen, Shervin Nourbakhsh", author_email="carsten.grote@xfel.eu, juncheng.e@xfel.eu, Mads.Bertelsen@ess.eu, nourbakhsh@ill.fr", url="https://github.com/PaNOSC-ViNYL/libpyvinyl", - download_url="https://github.com/PaNOSC-ViNYL/libpyvinyl/archive/v0.1.0.tar.gz", + download_url="https://github.com/PaNOSC-ViNYL/libpyvinyl/archive/v1.1.0.tar.gz", keywords=["photons", "neutrons", "simulations"], install_requires=requirements, classifiers=[ From 94c82358ddf2b6cfbf49ae1c1a4a509c4ce3800c Mon Sep 17 00:00:00 2001 From: Shervin Nourbakhsh Date: Fri, 1 Apr 2022 11:30:35 +0200 Subject: [PATCH 06/10] library version number in the __init__ file --- libpyvinyl/__init__.py | 5 +++++ setup.py | 21 ++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/libpyvinyl/__init__.py b/libpyvinyl/__init__.py index 2e9d607..3e9915d 100644 --- a/libpyvinyl/__init__.py +++ b/libpyvinyl/__init__.py @@ -1,3 +1,8 @@ +__author__ = "Carsten Fortmann-Grote, Mads Bertelsen, Juncheng E, Shervin Nourbakhsh" +__email__ = "carsten.grote@xfel.eu" +__version__ = "1.1.0" + + from .BaseCalculator import BaseCalculator, CalculatorParameters from .BaseData import BaseData from .Parameters.Parameter import Parameter diff --git a/setup.py b/setup.py index 253c7b7..666b02e 100644 --- a/setup.py +++ b/setup.py @@ -5,10 +5,29 @@ require = requirements_file.read() requirements = require.split() +import codecs +import os.path + + +def read(rel_path): + here = os.path.abspath(os.path.dirname(__file__)) + with codecs.open(os.path.join(here, rel_path), "r") as fp: + return fp.read() + + +def get_version(rel_path): + for line in read(rel_path).splitlines(): + if line.startswith("__version__"): + delim = '"' if '"' in line else "'" + return line.split(delim)[1] + else: + raise RuntimeError("Unable to find version string.") + + setup( name="libpyvinyl", packages=find_packages(include=["libpyvinyl", "libpyvinyl.*"]), - version="1.1.0", + version=get_version("libpyvinyl/__init__.py"), license="LGPLv3", description="The python API for photon and neutron simulation codes in the Photon and Neutron Open Science Cloud (PaNOSC).", author="Carsten Fortmann-Grote, Juncheng E, Mads Bertelsen, Shervin Nourbakhsh", From 1bb51dec6478a715585371c363094fa3d6732f31 Mon Sep 17 00:00:00 2001 From: Shervin Nourbakhsh Date: Fri, 1 Apr 2022 11:33:12 +0200 Subject: [PATCH 07/10] moving numpy dependency to installation requirements --- requirements/dev.txt | 2 +- requirements/prod.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements/dev.txt b/requirements/dev.txt index 7c382f3..d66a826 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -1,4 +1,4 @@ -r prod.txt -numpy black pytest +flake8 diff --git a/requirements/prod.txt b/requirements/prod.txt index 9354bc5..50630a3 100644 --- a/requirements/prod.txt +++ b/requirements/prod.txt @@ -5,3 +5,4 @@ jsons h5py json_tricks numpy +typing==3.7.4 From 189be65fb44a85dd801ee4e47550a64529236fef Mon Sep 17 00:00:00 2001 From: Shervin Nourbakhsh Date: Fri, 1 Apr 2022 11:33:57 +0200 Subject: [PATCH 08/10] Reading the library metadata from the __init__ file for the documentation --- doc/source/conf.py | 80 +++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 3e09a77..91aa1ff 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -15,22 +15,23 @@ import os import sys -sys.path.insert(0,'../libpyvinyl') +sys.path.insert(0, "../libpyvinyl") import libpyvinyl import sphinx_rtd_theme # -- Project information ----------------------------------------------------- -project = 'libpyvinyl' -copyright = '2020-2021, Carsten Fortmann-Grote, Mads Bertelsen, Juncheng E, Shervin Nourbakhsh' -author = 'Carsten Fortmann-Grote, Mads Bertelsen, Juncheng E, Shervin Nourbakhsh' +project = "libpyvinyl" +copyright = ( + "2020-2021, Carsten Fortmann-Grote, Mads Bertelsen, Juncheng E, Shervin Nourbakhsh" +) +author = "Carsten Fortmann-Grote, Mads Bertelsen, Juncheng E, Shervin Nourbakhsh" # The short X.Y version -version = '0.0.2' +version = libpyvinyl.__version__ # The full version, including alpha/beta/rc tags -release = '0.0.2-alpha1' - +release = version # -- General configuration --------------------------------------------------- @@ -42,29 +43,29 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.mathjax', - 'sphinx.ext.viewcode', - 'sphinx_rtd_theme', - 'nbsphinx', - 'recommonmark', + "sphinx.ext.autodoc", + "sphinx.ext.doctest", + "sphinx.ext.intersphinx", + "sphinx.ext.todo", + "sphinx.ext.coverage", + "sphinx.ext.mathjax", + "sphinx.ext.viewcode", + "sphinx_rtd_theme", + "nbsphinx", + "recommonmark", ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -87,7 +88,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'sphinx_rtd_theme' +html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -99,7 +100,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] # Custom sidebar templates, must be a dictionary that maps document names # to template names. @@ -115,7 +116,7 @@ # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. -htmlhelp_basename = 'libpyvinyldoc' +htmlhelp_basename = project + "doc" # -- Options for LaTeX output ------------------------------------------------ @@ -124,15 +125,12 @@ # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # 'preamble': '', - # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -142,8 +140,13 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'libpyvinyl.tex', 'libpyvinyl Documentation', - 'Carsten Fortmann-Grote, Mads Bertelsen, Juncheng E', 'manual'), + ( + master_doc, + project + ".tex", + project + " Documentation", + author, + "manual", + ), ] @@ -151,10 +154,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'libpyvinyl', 'libpyvinyl Documentation', - [author], 1) -] +man_pages = [(master_doc, project, project + " Documentation", [author], 1)] # -- Options for Texinfo output ---------------------------------------------- @@ -163,9 +163,15 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'libpyvinyl', 'libpyvinyl Documentation', - author, 'libpyvinyl', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + project, + project + " Documentation", + author, + project, + "One line description of project.", + "Miscellaneous", + ), ] @@ -184,7 +190,7 @@ # epub_uid = '' # A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] +epub_exclude_files = ["search.html"] # -- Extension configuration ------------------------------------------------- @@ -194,7 +200,7 @@ # -- Options for intersphinx extension --------------------------------------- # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} +intersphinx_mapping = {"https://docs.python.org/": None} # -- Options for todo extension ---------------------------------------------- From 4f77216d8ea3f888cf735e59ed39c518b33a8d88 Mon Sep 17 00:00:00 2001 From: Shervin Nourbakhsh Date: Fri, 1 Apr 2022 14:50:39 +0200 Subject: [PATCH 09/10] Adding type hints to Parameter and Instrument modules and improved documentation --- doc/source/conf.py | 1 + doc/source/include/refman.rst | 2 +- libpyvinyl/Instrument.py | 90 ++++++++++++++++++++-------- libpyvinyl/Parameters/Collections.py | 10 +++- libpyvinyl/Parameters/Parameter.py | 85 ++++++++++++++------------ 5 files changed, 124 insertions(+), 64 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 91aa1ff..41ccf63 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -53,6 +53,7 @@ "sphinx_rtd_theme", "nbsphinx", "recommonmark", + "sphinx_autodoc_typehints", ] # Add any paths that contain templates here, relative to this directory. diff --git a/doc/source/include/refman.rst b/doc/source/include/refman.rst index 9f293e0..42c40a2 100644 --- a/doc/source/include/refman.rst +++ b/doc/source/include/refman.rst @@ -6,7 +6,7 @@ API Reference Manual :undoc-members: :show-inheritance: -.. automodule:: libpyvinyl.Parameters.Collection +.. automodule:: libpyvinyl.Parameters.Collections :members: :undoc-members: :show-inheritance: diff --git a/libpyvinyl/Instrument.py b/libpyvinyl/Instrument.py index 1eb31a4..e8b4d49 100644 --- a/libpyvinyl/Instrument.py +++ b/libpyvinyl/Instrument.py @@ -3,42 +3,57 @@ """ from libpyvinyl.Parameters.Collections import InstrumentParameters +from libpyvinyl import BaseCalculator + +# typing +from libpyvinyl.Parameters.Collections import MasterParameters +from typing import Union, Any, Tuple, List, Dict, Optional class Instrument: - """An Instrument class""" + """:class: Class collecting the parameters and calculators representing an entire instrument at a facility""" - def __init__(self, name, calculators=None, instrument_base_dir="./"): - """An Instrument class + def __init__( + self, + name: str, + calculators: Optional[Dict[str, BaseCalculator]] = None, + instrument_base_dir: str = "./", + ): + """Instrument object initialization: :param name: The name of this instrument - :type name: str - :param calculators: A collection of Calculator objects. - :type calculators: dict + :param calculators: a collection of Calculator objects. """ - self.__name = None - self.__instrument_base_dir = None + self.__name: str = "" + self.__instrument_base_dir: str = "" self.__parameters = InstrumentParameters() self.name = name - self.__calculators = {} + self.__calculators: Dict[str, BaseCalculator] = {} if calculators is not None: for calculator in calculators: self.add_calculator(calculator) self.set_instrument_base_dir(instrument_base_dir) - def add_master_parameter(self, name, links, **kwargs): + def add_master_parameter(self, name: str, links: Dict[str, str], **kwargs) -> None: + """ + Add a new parameter with the given name as master parameter. + The goal is to link parameters in multiple calculators that represent the same quantity and that should be all changed at the same time when any of them is changed. This is obtained creating the link and by changing the value of the newly created master parameter. + + :param name: name of the master parameter + :param links: dictionary with the names of the calculators and calculator parameters that represent the same quantity and hence can be changed all at once modifying the master parameter" + """ self.parameters.add_master_parameter(name, links, **kwargs) @property - def name(self): + def name(self) -> str: """The name of this instrument.""" return self.__name @name.setter - def name(self, value: str): + def name(self, value: str) -> None: if isinstance(value, str): self.__name = value else: @@ -47,23 +62,27 @@ def name(self, value: str): ) @property - def calculators(self): + def calculators(self) -> Dict[str, BaseCalculator]: """The list of calculators. It's modified either when constructing the class instance - or using the `add_calculator` function. + or using the :meth:`~libpyvinyl.Instrument.add_calculator` function. """ return self.__calculators @property - def parameters(self): - """The parameter collection of each calculator in the instrument. These parameters are links to the - exact parameters of each calculator.""" + def parameters(self) -> InstrumentParameters: + """ + The parameter collection of each calculator in the instrument. + These parameters are links to the + exact parameters of each calculator. + """ return self.__parameters @property - def master(self): + def master(self) -> MasterParameters: + """Return the master parameters""" return self.parameters.master - def set_instrument_base_dir(self, base: str): + def set_instrument_base_dir(self, base: str) -> None: """Set each calculator's `instrument_base_dir` to '`base`. Each calculator's data file ouput directory will be "`instrument_base_dir`/`calculator_base_dir`". @@ -79,24 +98,47 @@ def set_instrument_base_dir(self, base: str): f"Instrument: instrument_base_dir is expecting a str rather than {type(base)}" ) - def list_calculators(self): + def list_calculators(self) -> None: + """ + Print the list of all defined calculators for this instrument + """ string = f"- Instrument: {self.name} -\n" string += "Calculators:\n" for key in self.calculators: string += f"{key}\n" print(string) - def list_parameters(self): + def list_parameters(self) -> None: + """ + Print the list of all calculator parameters + """ print(self.parameters) - def add_calculator(self, calculator): + def add_calculator(self, calculator: BaseCalculator) -> None: + """ + Append one calculator to the list of calculators. + + N.B. calculators are executed in the same order as they are provided + + :param calculator: calculator + """ self.__calculators[calculator.name] = calculator self.__parameters.add(calculator.name, calculator.parameters) - def remove_calculator(self, calculator_name): + def remove_calculator(self, calculator_name: str) -> None: + """ + Remove the calculator with the given name from the list of calculators + + :param calculator_name: name of one calculator already added to the list + """ + del self.__calculators[calculator_name] del self.__parameters[calculator_name] - def run(self): + def run(self) -> None: + """ + Run the entire simulation, + i.e. all the calculators in the order they have been provided + """ for calculator in self.calculators.values(): calculator.backengine() diff --git a/libpyvinyl/Parameters/Collections.py b/libpyvinyl/Parameters/Collections.py index 6e482eb..e915753 100644 --- a/libpyvinyl/Parameters/Collections.py +++ b/libpyvinyl/Parameters/Collections.py @@ -9,10 +9,16 @@ from pint.quantity import Quantity from pint.unit import Unit, UnitsContainer +from typing import Union -def quantity_encode(obj, primitives=False): + +def quantity_encode( + obj: Union[Quantity, Unit, UnitsContainer, any], primitives: bool = False +): """ - Function to encode pint.Quantity object in json + Function to encode pint.Quantity and pint.Unit objects in json + + It returns obj if the encoding was not possible. """ if isinstance(obj, Quantity): return {"__quantity__": str(obj)} diff --git a/libpyvinyl/Parameters/Parameter.py b/libpyvinyl/Parameters/Parameter.py index f30af12..322beba 100644 --- a/libpyvinyl/Parameters/Parameter.py +++ b/libpyvinyl/Parameters/Parameter.py @@ -1,6 +1,5 @@ # Created by Mads Bertelsen and modified by Juncheng E # Further modified by Shervin Nourbakhsh -from typing import Union, Any import math import numpy @@ -13,6 +12,12 @@ from pint.quantity import Quantity import pint.errors +# typing +from typing import Union, Any, Tuple, List, Dict, Optional + +# ValueTypes: TypeAlias = [str, bool, int, float, object, pint.Quantity] +ValueTypes = Union[str, bool, int, float, pint.Quantity] + class Parameter(AbstractBaseClass): """ @@ -35,33 +40,29 @@ def __init__( Creates parameter with given name, optionally unit and comment :param name: name of the parameter - :type name: str - :param unit: physical units returning the parameter value - :type unit: str - :param comment: brief description of the parameter - :type comment: str """ - self.name = name - self.__unit = Unit(unit) if unit != None else "" - self.comment = comment - self.__value = None - self.__intervals = [] - self.__intervals_are_legal = None - self.__options = [] - self.__options_are_legal = None - self.__value_type = None + self.name: str = name + self.__unit: Union[str, Unit] = Unit(unit) if unit != None else "" + self.comment: Union[str, None] = comment + self.__value: Union[ValueTypes, None] = None + self.__intervals: List[Tuple[Quantity, Quantity]] = [] + self.__intervals_are_legal: Union[bool, None] = None + self.__options: List = [] + self.__options_are_legal: Union[bool, None] = None + self.__value_type: Union[ValueTypes, None] = None @classmethod - def from_dict(cls, param_dict): + def from_dict(cls, param_dict: Dict): """ Helper class method creating a new object from a dictionary providing - name: str MANDATORY - unit: str - comment: str - ... + This class method is mainly used to allow dumping and loading the class from json """ if "name" not in param_dict: @@ -89,10 +90,12 @@ def unit(self) -> str: return str(self.__unit) @unit.setter - def unit(self, uni): + def unit(self, uni: str) -> None: """ Assignment of the units + :param uni: unit + A pint.Unit is used if the string is recognized as a valid unit in the registry. It is stored as a string otherwise. """ @@ -102,21 +105,24 @@ def unit(self, uni): self.__unit = uni @property - def value_no_conversion(self): + def value_no_conversion(self) -> ValueTypes: """ Returning the object stored in value with no conversions """ return self.__value @property - def pint_value(self): + def pint_value(self) -> Quantity: """Returning the value as a pint object if available, an error otherwise""" if not isinstance(self.__value, Quantity): raise TypeError("The parameter value is not of pint.Quantity type") return self.__value @property - def value(self): + def value(self) -> ValueTypes: + """ + Returns the magnitude of a Quantity or the stored value otherwise + """ if isinstance(self.__value, Quantity): return self.__value.m_as(self.__unit) else: @@ -231,7 +237,7 @@ def __check_compatibility(self, value: Any) -> None: ) @value.setter - def value(self, value): + def value(self, value: ValueTypes) -> None: """ Sets value of this parameter if value is legal, an exception is raised otherwise. @@ -249,19 +255,21 @@ def value(self, value): else: raise ValueError("Value of parameter '" + self.name + "' illegal.") - def add_interval(self, min_value, max_value, intervals_are_legal): + def add_interval( + self, + min_value: Union[ValueTypes, None], + max_value: Union[ValueTypes, None], + intervals_are_legal: bool, + ) -> None: """ Sets an interval for this parameter: [min_value, max_value] The interval is closed on both sides: min_value and and max_value are included. - :param min_value: minimum value of the interval - :type min_value: float or None for infinite - :param max_value: maximum value of the interval - :type max_value: float or None for infinite + :param min_value: minimum value of the interval, None for infinity + :param max_value: maximum value of the interval, None for infinity :param intervals_are_legal: if not done previously, it defines if all the intervals of this parameter should be considered as allowed or forbidden intervals. - :type intervals_are_legal: boolean """ @@ -291,7 +299,7 @@ def add_interval(self, min_value, max_value, intervals_are_legal): raise ValueError("Parameter", "interval", "multiple validities") self.__intervals.append( - [self.__to_quantity(min_value), self.__to_quantity(max_value)] + (self.__to_quantity(min_value), self.__to_quantity(max_value)) ) # if the interval has been added after assignement of the value of the parameter, @@ -304,9 +312,12 @@ def add_interval(self, min_value, max_value, intervals_are_legal): + " is now illegal based on the newly added interval" ) - def add_option(self, option, options_are_legal): + def add_option(self, option: Any, options_are_legal: bool) -> None: """ Sets allowed values for this parameter + + :param option: a discrete allowed or forbidden value + :param options_are_legal: defines if the given option is for a legal or illegal discrete value """ if self.__options_are_legal is None: @@ -351,7 +362,7 @@ def get_intervals(self): def get_intervals_are_legal(self): return self.__intervals_are_legal - def is_legal(self, values=None): + def is_legal(self, values: Union[ValueTypes, None] = None) -> bool: """ Checks whether or not given or contained value is legal given constraints. @@ -404,7 +415,7 @@ def is_legal(self, values=None): return True - def print_paramter_constraints(self): + def print_parameter_constraints(self) -> None: """ Print the legal and illegal intervals of this parameter. FIXME """ @@ -414,19 +425,19 @@ def print_paramter_constraints(self): print("options", self.__options) print("options are legal:", self.__options_are_legal) - def clear_intervals(self): + def clear_intervals(self) -> None: """ Clear the intervals of this parameter. """ self.__intervals = [] - def clear_options(self): + def clear_options(self) -> None: """ Clear the option values of this parameter. """ self.__options = [] - def print_line(self): + def print_line(self) -> str: """ returns string with one line description of parameter """ @@ -448,8 +459,8 @@ def print_line(self): for interval in self.__intervals: legal = "L" if self.__intervals_are_legal else "I" - interval = legal + "[" + str(interval[0]) + ", " + str(interval[1]) + "]" - string += interval.ljust(10) + intervalstr = legal + "[" + str(interval[0]) + ", " + str(interval[1]) + "]" + string += intervalstr.ljust(10) if len(self.__options) > 0: values = "(" @@ -461,7 +472,7 @@ def print_line(self): return string - def __repr__(self): + def __repr__(self) -> str: """ Returns string with thorough description of parameter """ From 5d63c2fb6fed3aa80ee3f0781a5b0a1bb2964283 Mon Sep 17 00:00:00 2001 From: Shervin Nourbakhsh Date: Tue, 5 Apr 2022 16:30:59 +0200 Subject: [PATCH 10/10] typo in test --- tests/unit/test_Parameters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/test_Parameters.py b/tests/unit/test_Parameters.py index 3d53648..8ae6792 100644 --- a/tests/unit/test_Parameters.py +++ b/tests/unit/test_Parameters.py @@ -327,7 +327,7 @@ def test_print_legal_interval(self): par = Parameter("test") par.add_interval(3, 4.5, True) par.add_option(9.8, True) - par.print_paramter_constraints() + par.print_parameter_constraints() def test_clear_intervals(self): # FIXME par = Parameter("test")