diff --git a/.gitignore b/.gitignore index 8093dc95..1ddd9474 100644 --- a/.gitignore +++ b/.gitignore @@ -67,8 +67,9 @@ coverage.xml *.log # Sphinx documentation -doc/_build/ -doc/build/ +docs/_build/ +docs/build/ +/docs/output/ # PyBuilder target/ @@ -79,3 +80,6 @@ virt3/ # PyCharm .idea/ + +# MyPy +/.mypy_cache/ diff --git a/.travis.yml b/.travis.yml index e8bdd5ac..4fef3137 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,13 +3,31 @@ language: python cache: pip python: - "2.7" - - "3.3" - "3.4" - "3.5" + - "3.6" + - "3.6-dev" + - "3.7-dev" + - "nightly" +matrix: + allow_failures: + - python: "3.6-dev" + - python: "3.7-dev" + - python: "nightly" +addons: + apt: + packages: + - "build-essential" + - "gfortran" + - "libatlas-base-dev" before_install: - python --version - uname -a - ls -a + - "pip install --upgrade pip setuptools wheel" + - "pip install --upgrade numpy scipy" + - "pip install --upgrade iminuit nestle ruamel.yaml tabulate appdirs" + - "pip install --upgrade fuzzywuzzy python-Levenshtein" - "pip install coveralls --upgrade" - "pip install coverage --upgrade" - "pip install pytest --upgrade" @@ -24,9 +42,6 @@ after_success: - coveralls - head .coverage notifications: - emails: false - slack: - rooms: - - pypwa:qPFpdrleMXOkj6mE18RctZQR + emails: on_success: change on_failure: change diff --git a/CHANGELOG.mg b/CHANGELOG.mg new file mode 100644 index 00000000..fe50489e --- /dev/null +++ b/CHANGELOG.mg @@ -0,0 +1,25 @@ +# Changelog +All changes important to the user will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/) + +## [2.0.0] - 2017-6-5 +### Added + - Plugin Subsystem + - Configurator Subsystem + - Data Plugin + - SV Plugin + - EVIL Plugin + - GAMP Plugin + - Data Caching + - Processing Plugin + - iMinuit plugin + - Nestle likelihood + - PyFit plugin + - Log Likelihood Plugin + - Chi-Squared Likelihood + - PySim plugin + - Packaging + +[2.0.0]: https://github.com/JeffersonLab/PyPWA/compare/v1.1...v2.0.0 diff --git a/CHANGES b/CHANGES deleted file mode 100644 index fdfdfad3..00000000 --- a/CHANGES +++ /dev/null @@ -1,31 +0,0 @@ -PyPWA 2.0.0-Alpha.0: --Boasts a threaded GeneralShell with relatively no bugs in it. --A functioning python packaging system so that the General Shell can be installed with ease. --A Configuration file vs FnTemplate so that users can use the same GeneralShell for all fits. - -Complete changelog since PyPWA 1.1: - -* c27319a : Fixed a typo in the generate_config method of YamlConfig -* 7ee371a : Updated setup.py to the current version and status of PyPWA, updated setup.cfg to point to README.md instead of README.txt, and updated MANIFEST.in to contain root licenese, changes, and readme files. -* 80d27ab : Fixed a series of typos in YamlConfig and DataCalc that prevented GeneralFitting from executing properly. -* 2089c9b : Added ignore for PyCharm files -* edc7939 : Fixed bug #9 and enhancement #7. Fixed some bugs that prevented running, and converted private methods and variables to public. -* fe46418 : Added documentation for undocumented methods and functions, also improved documenation for some methods. -* 431c201 : Removed General Shell from limbo since the threaded general shell is part of the package now. -* cfabc1a : Remove redundant LICENSE and TODO file -* c87f120 : Updated readme to include the state of PyPWA and give a basic example of how to use the GeneralFitting -* 5354d72 : Updated examples to better explain how to propperly use the program. -* 57731cb : Merge branch 'threading-generalShell-resourceImprovement' into development for improved threading. -|\ -| * 193e082 : Merge branch 'development' into threading-generalShell-resourceImprovement -| |\ -| |/ -|/| -* | 760f633 : Fixed setup.py pointing to README.txt over README.md -| * 232d2a5 : Fixed a bug where "Number of threads" was used instead of "Number of Threads". Fixed array splitting. -| * c62f23a : Modified how threads are handled to improve overall performance within the General Shell. Performance increase should be more linear now with the addition of more threads. -|/ -* 5420529 : Removed unintended virtualenv files -* 9be3ec7 : Modified .gitignore to ignore virtualenv files. -* f417348 : Merged in work on threaded GeneralShell with setuptools packaging utils. -* 1773d3c : Removed deprecitated and outdated files. diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 00000000..84ace8a3 --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,15 @@ +# Contributors to PyPWA (in Chronological Order) + +## PyPWA Staff: + - Carlos Salgado + - Will Phelps + - Brandon DeMello + - Stephanie Bramlett + - Josh Pond + - Mark Jones + - LaRay Hare + +High School Interns: + + - Ryan Wright + - Ran Amplitude benchmarks on the XeonPhi diff --git a/PyPWA/__init__.py b/PyPWA/__init__.py index 98a85111..07860947 100644 --- a/PyPWA/__init__.py +++ b/PyPWA/__init__.py @@ -1,38 +1,86 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ -PyPWA is an attempt to have a set multiprocessing tools to easy the -Partial Wave Analysis process. +============ +General Docs +============ + +PyPWA is statistical analysis toolkit that was built with Partial Wave +Analysis in mind, however you should be able to use the tools included for +anything statistical analysis. + +Currently there are 4 different applications defined inside this package: + +- PyFit - Fitting with any likelihood. + +- PyLikelihood - Fitting with the log-likelihood. + +- PyChiSquared - Fitting with the ChiSquared likelihood. + +- PySimulate - Simulation of an amplitude. + +- PyIntensities - Just the calculation half of PySimulate. -Current there is a multiprocessing tool for both the Acceptance Rejection -Model, and the Maximum-Likelihood Estimation for fitting. +- PyRejection - Just the rejection-method half of PySimulate. + +For information about how to use each of the programs, look in the docs folder +included with the source code, or check the user docs at ReadTheDocs.io. -The tools work with Kinematic Variables defined in standard text files, -Comma Separated Variables, and Tab Separated Variables. +Developer Docs +============== + +To attempt to achieve a flexible fitter that could be quickly adapted to +changing needs, we actually built the entire package around a generalized +plugin loader. The "main" objects ore defined as plugins, along with each +task that needed to be solved. This means that fitting, data loading, +the processing module, simulation, optimizers, etc are all defined as +plugins internally. + +Package purposes +---------------- + +- builtin_plugins - This is where each internal plugin is defined, + the optimizers, the processing module, and the builtin parser and reader are + all defined here. + +- core - The true main of the program, this is where all the interfaces are + defined, the plugin loaders, plugin storage modules, and the main execution + logic that takes a simple YML file and translates it into executing code. + +- entries - The various entry points for each program contained in this + package are here, each function defined here is a starting point for + setuptools. + +- shell - This is where PySimulate and PyFit are defined. + +For more information on how each module works, view their documentation +respectively. """ -__author__ = ["Mark Jones"] +__author__ = "PyPWA Team and Contributors" __credits__ = ["Mark Jones"] -__license__ = "GPLv3" -__email__ = "maj@jlab.org" -__status__ = "development" -__maintainer__ = ["Mark Jones"] -__version__ = "2.0.0-rc5" +__version__ = "2.0.0" + +EMAIL = "pypwa@jlab.org" +LICENSE = "GPLv3" +STATUS = "development" +MAINTAINER = "Mark Jones" +AUTHOR = __author__ VERSION = __version__ -STATUS = __status__ -LICENSE = __license__ diff --git a/PyPWA/builtin_plugins/__init__.py b/PyPWA/builtin_plugins/__init__.py index 36d30ef9..4cdc0755 100644 --- a/PyPWA/builtin_plugins/__init__.py +++ b/PyPWA/builtin_plugins/__init__.py @@ -1,31 +1,42 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ -This module holds the built in Plugins for the program along with various -needed libraries. +All the plugins that come packaged with PyPWA by default. +--------------------------------------------------------- + +- data - A not so basic data plugin that supports caching, different file + types, can be extended, and even supports both parsing and iterating. + +- minuit - A python / cython minimizer based on ROOT's PyPWA. + +- nestle - A python maximizer based off of Multinest. + +- process - A Kernel based multiprocessing module. Allows for an + embarrassingly parallel calculation to be expanded across multiple cores. + +For more information about how these plugins work, see their documentation +as well. """ -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION diff --git a/PyPWA/builtin_plugins/data/__init__.py b/PyPWA/builtin_plugins/data/__init__.py index df9391f8..3462ac17 100644 --- a/PyPWA/builtin_plugins/data/__init__.py +++ b/PyPWA/builtin_plugins/data/__init__.py @@ -1,18 +1,20 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ This module loads data from various data types to be used @@ -31,135 +33,79 @@ file.write(path_to_file, the_data) """ -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.builtin_plugins.data import iterator -from PyPWA.builtin_plugins.data import memory -from PyPWA.core.templates import option_templates +from PyPWA import AUTHOR, VERSION +from PyPWA.builtin_plugins.data import _setups +from PyPWA.core.configurator import options -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION -MODULE_NAME = "Builtin Parser" # Name for the module externally. - - -class DataParser(option_templates.PluginsOptionsTemplate): - - def _plugin_name(self): - return "Builtin Parser" - - def _plugin_interface(self): - return memory.Memory - - def _plugin_type(self): - return self._data_parser - - def _user_defined_function(self): - return None - - def _default_options(self): - return { - "enable cache": True, - "clear cache": False, - "fail": False, - "user plugin": "cwd=/path/to/file;" - } - - def _option_levels(self): - return { - "enable cache": self._optional, - "clear cache": self._advanced, - "fail": self._advanced, - "user plugin": self._advanced - } - - def _option_types(self): - return { - "enable cache": bool, - "clear cache": bool, - "fail": bool, - "user plugin": str - } - - def _module_comment(self): - return "This is the builtin data parser, you can replace " \ - "this with your own data parser if you wish." - - def _option_comments(self): - return { - "enable cache": - "Should Cache be enabled? The cache will automatically " - "clear if it detects a change in any of your data and " - "should be safe to leave enabled.", - "clear cache": - "Should we force the cache to clear? This will destroy " - "all of your caches, this means loading your data will " - "take much longer, its recommended to leave this off " - "unless you are certain its a cache issue.", - "fail": - "Should the program stop if it fails to load the file? " - "The program will already fail if the data is needed for " - "parsing to happen, if this is set to true even files " - "that are optional will cause the program to stop.", - "user plugin": - "A plugin that can be loaded into the the " + - MODULE_NAME + " for parsing, see the " - "documentation on the " + MODULE_NAME + - " plugin for more information." - } - - -class DataIterator(option_templates.PluginsOptionsTemplate): - - def _plugin_name(self): - return "Builtin Reader" - - def _plugin_interface(self): - return iterator.Iterator - - def _plugin_type(self): - return self._data_reader - - def _user_defined_function(self): - return None - - def _default_options(self): - return { - "fail": False, - "user plugin": "cwd=/path/to/file;" - } - - def _option_levels(self): - return { - "fail": self._advanced, - "user plugin": self._advanced - } - - def _option_types(self): - return { - "fail": bool, - "user plugin": str - } - - def _module_comment(self): - return "This is the builtin data parser, you can replace " \ - "this with your own data parser if you wish." - - def _option_comments(self): - return { - "fail": - "Should the program stop if it fails to load the file? " - "The program will already fail if the data is needed for " - "parsing to happen, if this is set to true even files " - "that are optional will cause the program to stop.", - "user plugin": - "A plugin that can be loaded into the the " + - "Builtin Reader for parsing, see the " - "documentation on the Builtin Reader " + - " plugin for more information." - } +class DataParser(options.Plugin): + + plugin_name = "Builtin Parser" + setup = _setups.SetupParser + provides = options.Types.DATA_PARSER + defined_function = None + module_comment = "Parses TSV, CSV, Kvs, and GAMP data." + + default_options = { + "enable cache": True, + "clear cache": False, + "user plugin": None + } + + option_difficulties = { + "enable cache": options.Levels.OPTIONAL, + "clear cache": options.Levels.ADVANCED, + "user plugin": options.Levels.ADVANCED + } + + option_types = { + "enable cache": bool, + "clear cache": bool, + "user plugin": str + } + + option_comments = { + "enable cache": "Enable caching of all read data.", + "clear cache": + "Force cache to be cleared even if the data file hasn't changed.", + "user plugin": + "Directory that has potential plugins for the data parser in " + "it. Read the docs for more information." + } + + +class DataIterator(options.Plugin): + + plugin_name = "Builtin Reader" + setup = _setups.SetupIterator + provides = options.Types.DATA_READER + defined_function = None + module_comment = "Iterates over TSV, CSV, Kvs, and GAMP data." + + default_options = { + "fail": False, + "user plugin": None + } + + option_difficulties = { + "fail": options.Levels.ADVANCED, + "user plugin": options.Levels.ADVANCED + } + + option_types = { + "fail": bool, + "user plugin": str + } + + option_comments = { + "fail": + "Force Parser to crash when it fails to read a file even if " + "a fallback exists.", + "user plugin": + "Directory that has potential plugins for the data parser in " + "it. Read the docs for more information." + } diff --git a/PyPWA/builtin_plugins/data/_plugin_finder.py b/PyPWA/builtin_plugins/data/_plugin_finder.py index cf92b587..a4f93638 100644 --- a/PyPWA/builtin_plugins/data/_plugin_finder.py +++ b/PyPWA/builtin_plugins/data/_plugin_finder.py @@ -1,90 +1,114 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ Contains PluginSearch and helper private classes. This file is used to load the data plugins and user plugins then return one of them that can read/write whatever data needs to be read/written. + +- PluginSearch - Searches for data plugins that can read or write the provided + data. + +- _FindReadPlugins - searches for a plugin that can read the provided data. + +- _FindWritePlugins - Searches for a plugin that can write the given data + to the given file extension. """ import logging import os +from typing import List +import numpy + +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data import builtin from PyPWA.builtin_plugins.data import data_templates from PyPWA.builtin_plugins.data import exceptions -from PyPWA.core import plugin_loader +from PyPWA.core.shared import plugin_loader + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION class PluginSearch(object): - _logger = logging.getLogger(__name__) - _found_plugins = plugin_loader.PluginLoading + __LOGGER = logging.getLogger(__name__ + ".PluginSearch") def __init__(self, user_plugin_dir=""): - self._logger.addHandler(logging.NullHandler()) - self._setup_plugin_storage(user_plugin_dir) + # type: (str) -> None + self.__found_plugins = None + self.__setup_plugin_storage(user_plugin_dir) + self.__log_found_plugins() + + def __setup_plugin_storage(self, user_plugin_dir): + # type: (str) -> None + plugin_storage = plugin_loader.PluginLoader() + plugin_storage.add_plugin_location([builtin, user_plugin_dir]) - def _setup_plugin_storage(self, user_plugin_dir): - plugin_storage = plugin_loader.PluginLoading( + found_plugins = plugin_storage.get_by_class( data_templates.TemplateDataPlugin ) - found_plugins = plugin_storage.fetch_plugin( - [builtin, user_plugin_dir] - ) + self.__found_plugins = found_plugins - self._found_plugins = found_plugins + def __log_found_plugins(self): + self.__LOGGER.debug("Loaded Data Plugins: %s" % self.__found_plugins) def get_read_plugin(self, file_location): - plugin_finder = _FindReadPlugins(self._found_plugins) + # type: (str) -> data_templates.TemplateDataPlugin + plugin_finder = _FindReadPlugins(self.__found_plugins) return plugin_finder.get_plugin(file_location) def get_write_plugin(self, file_location, data): - plugin_finder = _FindWritePlugins(self._found_plugins) + # type: (str, numpy.ndarray) -> data_templates.TemplateDataPlugin + plugin_finder = _FindWritePlugins(self.__found_plugins) return plugin_finder.get_plugin(file_location, data) class _FindReadPlugins(object): - _logger = logging.getLogger(__name__) - _potential_plugins = plugin_loader.PluginLoading + __LOGGER = logging.getLogger(__name__ + "._FindReadPlugins") def __init__(self, potential_plugins): - self._logger.addHandler(logging.NullHandler()) - self._potential_plugins = potential_plugins + # type: (List[data_templates.TemplateDataPlugin]) -> None + self.__potential_plugins = potential_plugins def get_plugin(self, file_location): - return self._search_plugin_list(file_location) + return self.__search_plugin_list(file_location) - def _search_plugin_list(self, file_location): - for plugin in self._potential_plugins: - if self._plugin_can_read(plugin, file_location): + def __search_plugin_list(self, file_location): + for plugin in self.__potential_plugins: + if self.__plugin_can_read(plugin, file_location): return plugin() raise exceptions.UnknownData( "Unable to find a plugin that can load %s" % file_location ) - def _plugin_can_read(self, plugin, file_location): + def __plugin_can_read(self, plugin, file_location): + # type: (data_templates.TemplateDataPlugin, str) -> bool try: - self._run_read_test(plugin, file_location) + self.__run_read_test(plugin, file_location) return True except exceptions.IncompatibleData: - self._logger.debug( + self.__LOGGER.debug( "Skipping %s for data %s, test failed." % (plugin.__name__, file_location) ) @@ -92,92 +116,109 @@ def _plugin_can_read(self, plugin, file_location): except Exception as Error: # We don't want a plugin to halt execution, but we do want to know # that a plugin failed to load and why. - self._logger.exception(Error) + self.__LOGGER.debug(Error) return False - def _run_read_test(self, plugin, file_location): + def __run_read_test(self, plugin, file_location): + # type: (data_templates.TemplateDataPlugin, str) -> None read_test = plugin().get_plugin_read_test() read_test.quick_test(file_location) - self._logger.info( - "Found %s will load %s" % (plugin.__name__, file_location) + self.__LOGGER.info( + "Found '%s' will load '%s'" % (plugin.__name__, file_location) ) class _FindWritePlugins(object): - _data_is_gamp = False - _data_is_flat = False - _file_extension = "" - _logger = logging.getLogger(__name__) - _potential_plugins = plugin_loader.PluginLoading + __LOGGER = logging.getLogger(__name__ + "._FindWritePlugins") def __init__(self, potential_plugins): - self._logger.addHandler(logging.NullHandler()) - self._potential_plugins = potential_plugins + # type: (List[data_templates.TemplateDataPlugin]) -> None + self.__potential_plugins = potential_plugins + self.__data_is_gamp = False + self.__data_is_flat = False + self.__file_extension = "" + self.__file_name = "" def get_plugin(self, file_location, data): - self._set_data_type(data) - self._set_data_extension(file_location) - return self._search_for_plugins() + # type: (str, numpy.ndarray) -> data_templates.TemplateDataPlugin + self.__set_data_type(data) + self.__set_data_extension(file_location) + return self.__search_for_plugins() - def _set_data_type(self, data): + def __set_data_type(self, data): + # type: (numpy.ndarray) -> None shape_count = len(data.shape) if shape_count == 3: - self._logger.info("Found data type: GAMP") - self._data_is_gamp = True + self.__LOGGER.debug("Found data type: GAMP") + self.__data_is_gamp = True elif shape_count == 1: - self._logger.info("Found data type: Flat") - self._data_is_flat = True + self.__LOGGER.debug("Found data type: Flat") + self.__data_is_flat = True else: - self._logger.info( + self.__LOGGER.error( "Found noise, data shape_count is: " + str(shape_count) ) raise exceptions.UnknownData - def _set_data_extension(self, file_location): + def __set_data_extension(self, file_location): + # type: (str) -> None split_extension = os.path.splitext(file_location) extension = split_extension[1] - self._file_extension = extension - - self._logger.debug("Data's extension is: " + repr(extension)) + self.__file_extension = extension + self.__file_name = file_location + self.__LOGGER.debug("Data's extension is: " + repr(extension)) - def _search_for_plugins(self): - for plugin in self._potential_plugins: + def __search_for_plugins(self): + # type: () -> data_templates.TemplateDataPlugin + for plugin in self.__potential_plugins: the_plugin = plugin() - if self._check_plugin(the_plugin): + if self.__check_plugin(the_plugin): + self.__log_found_plugin(the_plugin) return the_plugin raise exceptions.UnknownData - def _check_plugin(self, the_plugin): + def __check_plugin(self, the_plugin): + # type: (data_templates.TemplateDataPlugin) -> bool supported_extensions = the_plugin.plugin_supported_extensions - if self._supports_data_type(the_plugin): - if self._supports_file_extension(supported_extensions): + if self.__supports_data_type(the_plugin): + if self.__supports_file_extension(supported_extensions): return True return False - def _supports_data_type(self, plugin): - if self._data_is_flat: + def __supports_data_type(self, plugin): + # type: (data_templates.TemplateDataPlugin) -> bool + if self.__data_is_flat: return plugin.plugin_supports_flat_data - elif self._data_is_gamp: + elif self.__data_is_gamp: return plugin.plugin_supports_gamp_data - def _supports_file_extension(self, extensions): - if self._file_extension == "": - self._logger.warn( + def __supports_file_extension(self, extensions): + # type: (List[str]) -> bool + if self.__file_extension == "": + self.__LOGGER.warning( "No extension found! Will use first data match! This could " "result in strange or unusual data in your file! Considering " "using an extension in the future!" ) return True - elif self._file_extension in extensions: - self._logger.info( - "Found %s in %s!" % (self._file_extension, repr(extensions)) + elif self.__file_extension in extensions: + self.__LOGGER.debug( + "Found %s in %s!" % (self.__file_extension, repr(extensions)) ) return True else: - self._logger.info("Extension not supported!") + self.__LOGGER.info("Extension not supported!") return False + + def __log_found_plugin(self, plugin): + # type: (data_templates.TemplateDataPlugin) -> None + self.__LOGGER.info( + "Found '%s' to write '%s'" % ( + plugin.plugin_name, self.__file_name + ) + ) diff --git a/PyPWA/builtin_plugins/data/_plugin_finder.pyi b/PyPWA/builtin_plugins/data/_plugin_finder.pyi deleted file mode 100644 index df3f5382..00000000 --- a/PyPWA/builtin_plugins/data/_plugin_finder.pyi +++ /dev/null @@ -1,76 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import logging -import typing - -import numpy -from PyPWA.builtin_plugins.data import data_templates - - -class PluginSearch(object): - - _logger = logging.getLogger(__name__) - _found_plugins = typing.List[data_templates.TemplateDataPlugin] - - def __init__(self, user_plugin_dir: str): ... - - def _setup_plugin_storage(self, user_plugin_dir: str): ... - - def get_read_plugin(self, file_location: str) -> data_templates.TemplateDataPlugin: ... - - def get_write_plugin(self, file_location: str, data: numpy.ndarray) -> data_templates.TemplateDataPlugin: ... - - -class _FindReadPlugins(object): - - _logger = logging.getLogger(__name__) - _potential_plugins = typing.List[data_templates.TemplateDataPlugin] - - def __init__(self, potential_plugins: typing.List[data_templates.TemplateDataPlugin]): ... - - def get_plugin(self, file_location: str) -> data_templates.TemplateDataPlugin: ... - - def _search_plugin_list(self, file_location: str) -> data_templates.TemplateDataPlugin: ... - - def _plugin_can_read(self, plugin: data_templates.TemplateDataPlugin, file_location: str) -> bool: ... - - def _run_read_test(self, plugin: data_templates.TemplateDataPlugin, file_location: str): ... - - -class _FindWritePlugins(object): - - _data_is_gamp = False - _data_is_flat = False - _file_extension = "" - _logger = logging.getLogger(__name__) - _potential_plugins = typing.List[data_templates.TemplateDataPlugin] - - def __init__(self, potential_plugins: typing.List[data_templates.TemplateDataPlugin]): ... - - def get_plugin(self, file_location: str, data: numpy.ndarray) -> data_templates.TemplateDataPlugin: ... - - def _set_data_type(self, data: numpy.ndarray): ... - - def _set_data_extension(self, file_location: str): ... - - def _search_for_plugins(self) -> data_templates.TemplateDataPlugin: ... - - def _check_plugin(self, the_plugin: data_templates.TemplateDataPlugin) -> bool: ... - - def _supports_data_type(self, plugin: data_templates.TemplateDataPlugin) -> bool: ... - - def _supports_file_extension(self, extensions: typing.List[str]) -> bool: ... diff --git a/PyPWA/builtin_plugins/data/_setups.py b/PyPWA/builtin_plugins/data/_setups.py new file mode 100644 index 00000000..245ca4b1 --- /dev/null +++ b/PyPWA/builtin_plugins/data/_setups.py @@ -0,0 +1,71 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Holds both the setup plugins for this package. Since this package is both an +iterator and an parser, it has two plugin interfaces. +""" + +from PyPWA import AUTHOR, VERSION +from PyPWA.builtin_plugins.data import iterator +from PyPWA.builtin_plugins.data import memory +from PyPWA.core.configurator import option_tools +from PyPWA.core.configurator import options + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class SetupParser(options.Setup): + + def __init__(self, command_object): + # type: (option_tools.CommandOptions) -> None + self.__options_object = command_object + self.__parser = None + self.__setup_memory_parser() + + def __setup_memory_parser(self): + self.__parser = memory.Memory( + enable_cache=self.__options_object.enable_cache, + clear_cache=self.__options_object.clear_cache, + user_plugin_dir=self.__options_object.user_plugin + ) + + def return_interface(self): + # type: () -> memory.Memory + return self.__parser + + +class SetupIterator(options.Setup): + + def __init__(self, command_object): + # type: (option_tools.CommandOptions) -> None + self.__options_object = command_object + self.__iterator = None + self.__setup_iterator() + + def __setup_iterator(self): + self.__iterator = iterator.Iterator( + fail=self.__options_object.fail, + user_plugin=self.__options_object.user_plugin + ) + + def return_interface(self): + # type: () -> iterator.Iterator + return self.__iterator diff --git a/PyPWA/builtin_plugins/data/builtin/__init__.py b/PyPWA/builtin_plugins/data/builtin/__init__.py index e5939ec5..adf251e8 100644 --- a/PyPWA/builtin_plugins/data/builtin/__init__.py +++ b/PyPWA/builtin_plugins/data/builtin/__init__.py @@ -1,29 +1,27 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ """ -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION diff --git a/PyPWA/builtin_plugins/data/builtin/gamp/__init__.py b/PyPWA/builtin_plugins/data/builtin/gamp/__init__.py index af2dceb7..0f447805 100644 --- a/PyPWA/builtin_plugins/data/builtin/gamp/__init__.py +++ b/PyPWA/builtin_plugins/data/builtin/gamp/__init__.py @@ -1,23 +1,30 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data import data_templates -from PyPWA.builtin_plugins.data.builtin.gamp import g_read_tests from PyPWA.builtin_plugins.data.builtin.gamp import g_iterator from PyPWA.builtin_plugins.data.builtin.gamp import g_memory +from PyPWA.builtin_plugins.data.builtin.gamp import g_read_tests + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION class GampDataPlugin(data_templates.TemplateDataPlugin): diff --git a/PyPWA/builtin_plugins/data/builtin/gamp/g_iterator.py b/PyPWA/builtin_plugins/data/builtin/gamp/g_iterator.py index be05c96d..d22e6d31 100644 --- a/PyPWA/builtin_plugins/data/builtin/gamp/g_iterator.py +++ b/PyPWA/builtin_plugins/data/builtin/gamp/g_iterator.py @@ -1,18 +1,20 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ Gamp data reading and writing. @@ -27,19 +29,15 @@ import numpy -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core.templates import interface_templates +from PyPWA import AUTHOR, VERSION +from PyPWA.core.shared.interfaces import internals -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION -class GampReader(interface_templates.ReaderInterfaceTemplate): +class GampReader(internals.Reader): def __init__(self, file_location): """ @@ -50,9 +48,8 @@ def __init__(self, file_location): Args: file_location (str): Name of the GAMP file, can be any size. """ - super(GampReader, self).__init__(file_location) self._previous_event = None # type: numpy.ndarray - + self._the_file = file_location self._start_input() def _start_input(self): @@ -74,8 +71,7 @@ def reset(self): """ self._start_input() - @property - def next_event(self): + def next(self): """ Structures the read in event from the GAMP file into a deque then passes it to the calling function. @@ -96,10 +92,6 @@ def next_event(self): self._previous_event = event return self._previous_event - @property - def previous_event(self): - return self._previous_event - @staticmethod def _make_particle(string): """ @@ -130,7 +122,7 @@ def close(self): self._file.close() -class GampWriter(interface_templates.WriterInterfaceTemplate): +class GampWriter(internals.Writer): def __init__(self, file_location): """ @@ -141,7 +133,6 @@ def __init__(self, file_location): Args: file_location (str): Where to write the GAMP data. """ - super(GampWriter, self).__init__(file_location) self._file = open(file_location, "w") def write(self, data): diff --git a/PyPWA/builtin_plugins/data/builtin/gamp/g_memory.py b/PyPWA/builtin_plugins/data/builtin/gamp/g_memory.py index ebdf4fd1..ed105d74 100644 --- a/PyPWA/builtin_plugins/data/builtin/gamp/g_memory.py +++ b/PyPWA/builtin_plugins/data/builtin/gamp/g_memory.py @@ -1,18 +1,20 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ Gamp data reading and writing. @@ -27,16 +29,12 @@ import numpy -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data import data_templates from PyPWA.builtin_plugins.data.builtin.gamp import g_iterator -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION diff --git a/PyPWA/builtin_plugins/data/builtin/gamp/g_read_tests.py b/PyPWA/builtin_plugins/data/builtin/gamp/g_read_tests.py index 952d78e5..c545ffce 100644 --- a/PyPWA/builtin_plugins/data/builtin/gamp/g_read_tests.py +++ b/PyPWA/builtin_plugins/data/builtin/gamp/g_read_tests.py @@ -1,18 +1,20 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ Gamp data reading and writing. @@ -25,16 +27,12 @@ import io -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.builtin_plugins.data import exceptions +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data import data_templates +from PyPWA.builtin_plugins.data import exceptions -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION @@ -123,4 +121,3 @@ def quick_test(self, text_file): def full_test(self, text_file): self.quick_test(text_file) - diff --git a/PyPWA/builtin_plugins/data/builtin/kv/__init__.py b/PyPWA/builtin_plugins/data/builtin/kv/__init__.py index 1c829de6..6d65dbf3 100644 --- a/PyPWA/builtin_plugins/data/builtin/kv/__init__.py +++ b/PyPWA/builtin_plugins/data/builtin/kv/__init__.py @@ -1,18 +1,20 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ Handles EVIL to / from memory. @@ -33,18 +35,14 @@ attention to CSV/TSV in the SV object and forget that this ever existed. """ -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data import data_templates from PyPWA.builtin_plugins.data.builtin.kv import k_iterator from PyPWA.builtin_plugins.data.builtin.kv import k_memory from PyPWA.builtin_plugins.data.builtin.kv import k_read_tests -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION diff --git a/PyPWA/builtin_plugins/data/builtin/kv/k_iterator.py b/PyPWA/builtin_plugins/data/builtin/kv/k_iterator.py index 14b3cc7c..d4a97ad2 100644 --- a/PyPWA/builtin_plugins/data/builtin/kv/k_iterator.py +++ b/PyPWA/builtin_plugins/data/builtin/kv/k_iterator.py @@ -1,18 +1,20 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ Handles EVIL to / from memory. @@ -38,20 +40,16 @@ import numpy -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core.templates import interface_templates +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data.builtin.kv import k_read_tests +from PyPWA.core.shared.interfaces import internals -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION -class EVILReader(interface_templates.ReaderInterfaceTemplate): +class EVILReader(internals.Reader): def __init__(self, file_location): """ @@ -63,7 +61,7 @@ def __init__(self, file_location): self._logger = logging.getLogger(__name__) self._logger.addHandler(logging.NullHandler()) - super(EVILReader, self).__init__(file_location) + self._the_file = file_location self._previous_event = None self._file = False # type: io.TextIOBase self._parameters = False # type: [str] @@ -115,14 +113,7 @@ def _set_data_type(self): validator.quick_test(self._the_file) self._file_data_type = validator.evil_type - def reset(self): - """ - Wrapper for _start_input - """ - self._start_input() - - @property - def next_event(self): + def next(self): """ Reads in a single line and parses the line into a GenericEvent. @@ -139,10 +130,6 @@ def next_event(self): self._previous_event = values return self._previous_event - @property - def previous_event(self): - return self.previous_event - def __read(self): """ Reads a single line from the file and removes the spaces and @@ -216,7 +203,7 @@ def close(self): self._file.close() -class EVILWriter(interface_templates.WriterInterfaceTemplate): +class EVILWriter(internals.Writer): def __init__(self, file_location): """ @@ -227,7 +214,6 @@ def __init__(self, file_location): Args: file_location (str): Where to write the data. """ - super(EVILWriter, self).__init__(file_location) self._file = io.open(file_location, "w") def write(self, data): @@ -252,4 +238,3 @@ def close(self): Closes the file safely. """ self._file.close() - diff --git a/PyPWA/builtin_plugins/data/builtin/kv/k_memory.py b/PyPWA/builtin_plugins/data/builtin/kv/k_memory.py index b9e16356..7c73a621 100644 --- a/PyPWA/builtin_plugins/data/builtin/kv/k_memory.py +++ b/PyPWA/builtin_plugins/data/builtin/kv/k_memory.py @@ -1,18 +1,20 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ Handles EVIL to / from memory. @@ -38,16 +40,12 @@ import numpy -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data import data_templates from PyPWA.builtin_plugins.data.builtin.kv import k_read_tests -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION @@ -329,4 +327,3 @@ def write(self, file_location, data): self._logger.error(string) raise RuntimeError(string) writer.write(file_location, data) - diff --git a/PyPWA/builtin_plugins/data/builtin/kv/k_read_tests.py b/PyPWA/builtin_plugins/data/builtin/kv/k_read_tests.py index 169e5111..1c988f71 100644 --- a/PyPWA/builtin_plugins/data/builtin/kv/k_read_tests.py +++ b/PyPWA/builtin_plugins/data/builtin/kv/k_read_tests.py @@ -1,18 +1,20 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ Handles EVIL to / from memory. @@ -35,16 +37,12 @@ import io -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data import data_templates from PyPWA.builtin_plugins.data import exceptions -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION @@ -91,5 +89,3 @@ def evil_type(self): return self._evil_type except AttributeError: return False - - diff --git a/PyPWA/builtin_plugins/data/builtin/sv/__init__.py b/PyPWA/builtin_plugins/data/builtin/sv/__init__.py index 34bc01cf..25deaa77 100644 --- a/PyPWA/builtin_plugins/data/builtin/sv/__init__.py +++ b/PyPWA/builtin_plugins/data/builtin/sv/__init__.py @@ -1,24 +1,31 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data import data_templates from PyPWA.builtin_plugins.data.builtin.sv import s_iterator from PyPWA.builtin_plugins.data.builtin.sv import s_memory from PyPWA.builtin_plugins.data.builtin.sv import s_read_tests +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + class SvDataPlugin(data_templates.TemplateDataPlugin): diff --git a/PyPWA/builtin_plugins/data/builtin/sv/s_iterator.py b/PyPWA/builtin_plugins/data/builtin/sv/s_iterator.py index d224ac13..21afb332 100644 --- a/PyPWA/builtin_plugins/data/builtin/sv/s_iterator.py +++ b/PyPWA/builtin_plugins/data/builtin/sv/s_iterator.py @@ -1,162 +1,153 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . import csv import io import numpy -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core.templates import interface_templates - +from typing import Dict, List, Tuple +from PyPWA import AUTHOR, VERSION +from PyPWA.core.shared.interfaces import internals -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION -HEADER_SEARCH_BITS = 1024 +HEADER_SEARCH_BITS = 1024 -class SvReader(interface_templates.ReaderInterfaceTemplate): - _previous_event = None # type: collections.namedtuple - _reader = False # type: csv.DictReader - _file = False # type: io.TextIOBase - _types = False # type: list[tuple] - _elements = False # type: list[str] +class SvReader(internals.Reader): def __init__(self, file_location): - super(SvReader, self).__init__(file_location) - self._set_file_location(file_location) - self._start_input() - - def _set_file_location(self, file_location): - self._file_location = file_location - - def _start_input(self): - self._set_file() - dialect = self._get_dialect() - self._set_reader(dialect) - self._set_elements() - self._set_numpy_types() - - def _set_file(self): - self._file = io.open(self._file_location) - - def _get_dialect(self): + # type: (str) -> None + self.__file = io.open(file_location) + self.__previous_event = None # type: numpy.ndarray + self.__reader = False # type: csv.DictReader + self.__types = False # type: List[Tuple[str]] + self.__elements = False # type: List[str] + self.__start_input() + + def __start_input(self): + dialect = self.__get_dialect() + self.__set_reader(dialect) + self.__set_elements() + self.__set_numpy_types() + + def __get_dialect(self): + # type: () -> str dialect = csv.Sniffer().sniff( - self._file.read(HEADER_SEARCH_BITS), delimiters=[",", "\t"] + self.__file.read(HEADER_SEARCH_BITS), delimiters=[",", "\t"] ) - self._file.seek(0) + self.__file.seek(0) return dialect - def _set_reader(self, dialect): - self._reader = csv.reader(self._file, dialect) - - def _set_elements(self): - self._elements = next(self._reader) + def __set_reader(self, dialect): + # type: (str) -> None + self.__reader = csv.reader(self.__file, dialect) - def _set_numpy_types(self): - self._types = [] - for element in self._elements: - self._types.append((element, "f8")) + def __set_elements(self): + self.__elements = next(self.__reader) - def reset(self): - self.close() - self._start_input() + def __set_numpy_types(self): + self.__types = [] + for element in self.__elements: + self.__types.append((element, "f8")) def close(self): - self._file.close() + self.__file.close() - @property - def next_event(self): - non_parsed = list(next(self._reader)) - parsed = numpy.zeros(1, self._types) + def next(self): + # type: () -> numpy.ndarray + non_parsed = list(next(self.__reader)) + parsed = numpy.zeros(1, self.__types) - for index, element in enumerate(self._elements): + for index, element in enumerate(self.__elements): parsed[element][0] = non_parsed[index] - self._previous_event = parsed + self.__previous_event = parsed - return self.previous_event + return self.__previous_event - @property - def previous_event(self): - return self._previous_event - -class SvWriter(interface_templates.WriterInterfaceTemplate): - - _dialect = csv.Dialect - _writer = csv.DictWriter - _field_names = [str] +class SvWriter(internals.Writer): def __init__(self, file_location): - super(SvWriter, self).__init__(file_location) - self._file = open(file_location, "w") - self._set_dialect(file_location) - - def _set_dialect(self, file_location): - if self._is_tab(file_location): - self._dialect = csv.excel_tab + # type: (str) -> None + self.__file = open(file_location, "w") + self.__dialect = None # type: csv.Dialect + self.__writer = None # type: csv.DictWriter + self.__field_names = None # type: List[str] + self.__set_dialect(file_location) + + def __set_dialect(self, file_location): + # type: (str) -> None + if self.__is_tab(file_location): + self.__dialect = csv.excel_tab else: - self._dialect = csv.excel + self.__dialect = csv.excel - def _is_tab(self, file_location): - return self._get_extension(file_location) == ".tsv" + def __is_tab(self, file_location): + # type: (str) -> bool + return self.__get_extension(file_location) == ".tsv" @staticmethod - def _get_extension(file_location): + def __get_extension(file_location): + # type: (str) -> str return file_location.split(".")[-1] def write(self, data): - self._writer_setup(data) - converted_data = self._convert_to_dict(data) - self._write_row(converted_data) - - def _writer_setup(self, data): - if not self._writer: - self._set_field_names(data) - self._set_writer() - self._write_header() - - def _set_field_names(self, data): - self._field_names = list(data.dtype.names) - - def _set_writer(self): - self._writer = csv.DictWriter( - self._file, - fieldnames=self._field_names, - dialect=self._dialect + # type: (numpy.ndarray) -> None + self.__writer_setup(data) + converted_data = self.__convert_to_dict(data) + self.__write_row(converted_data) + + def __writer_setup(self, data): + # type: (numpy.ndarray) -> None + if not self.__writer: + self.__set_field_names(data) + self.__set_writer() + self.__write_header() + + def __set_field_names(self, data): + # type: (numpy.ndarray) -> None + self.__field_names = list(data.dtype.names) + + def __set_writer(self): + self.__writer = csv.DictWriter( + self.__file, + fieldnames=self.__field_names, + dialect=self.__dialect ) - def _write_header(self): - self._writer.writeheader() + def __write_header(self): + self.__writer.writeheader() - def _convert_to_dict(self, data): + def __convert_to_dict(self, data): + # type: (numpy.ndarray) -> Dict[str, str] dict_data = {} - for field_name in self._field_names: + for field_name in self.__field_names: dict_data[field_name] = repr(data[0][field_name]) return dict_data - def _write_row(self, dict_data): - self._writer.writerow(dict_data) + def __write_row(self, dict_data): + # type: (Dict[str, str]) -> None + self.__writer.writerow(dict_data) def close(self): - self._file.close() + self.__file.close() diff --git a/PyPWA/builtin_plugins/data/builtin/sv/s_memory.py b/PyPWA/builtin_plugins/data/builtin/sv/s_memory.py index b8be7056..07bbf93a 100644 --- a/PyPWA/builtin_plugins/data/builtin/sv/s_memory.py +++ b/PyPWA/builtin_plugins/data/builtin/sv/s_memory.py @@ -1,202 +1,227 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . -import sys import csv import io import logging import os +import sys +from typing import List, Tuple, Iterable, Dict import numpy -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data import data_templates -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION -HEADER_SEARCH_BITS = 1024 + +HEADER_SEARCH_BITS = 3072 class SvMemory(data_templates.TemplateMemory): def parse(self, file_location): + # type: (str) -> numpy.ndarray parser = _SvParser() return parser.return_read_data(file_location) def write(self, file_location, data): + # type: (str, numpy.ndarray) -> None writer = _SvMemoryWriter() writer.write_memory_to_disk(file_location, data) class _SvParser(object): - _logger = logging.getLogger(__name__) - _line_count = 0 - _dialect = None - _stream = None - _reader = None - _header = None + __LOGGER = logging.getLogger(__name__ + "._SvParser") def __init__(self): - self._logger.addHandler(logging.NullHandler()) + self.__line_count = 0 + self.__dialect = None # type: str + self.__stream = None # type: io.FileIO + self.__reader = None # type: csv.reader + self.__header = None # type: List[str] def return_read_data(self, file_location): - self._start_parsing(file_location) - return self._end_parsing() + # type: (str) -> numpy.ndarray + self.__start_parsing(file_location) + return self.__end_parsing() - def _start_parsing(self, file_location): - self._open_stream(file_location) - self._set_required_data() + def __start_parsing(self, file_location): + # type: (str) -> None + self.__open_stream(file_location) + self.__set_required_data() - def _open_stream(self, file_location): - self._stream = io.open(file_location, "r") + def __open_stream(self, file_location): + # type: (str) -> None + self.__stream = io.open(file_location, "r") - def _reset_stream(self): - self._stream.seek(0) + def __reset_stream(self): + self.__stream.seek(0) - def _close_stream(self): - self._stream.close() + def __close_stream(self): + self.__stream.close() - def _set_required_data(self): - self._set_line_number() - self._set_dialect() - self._set_reader() - self._set_header() + def __set_required_data(self): + self.__set_line_number() + self.__set_dialect() + self.__set_reader() + self.__set_header() - def _set_line_number(self): - for self._line_count, throw_away in enumerate(self._stream): + def __set_line_number(self): + for self.__line_count, throw_away in enumerate(self.__stream): pass - self._reset_stream() + self.__reset_stream() - def _set_dialect(self): - self._dialect = csv.Sniffer().sniff( - self._stream.read(HEADER_SEARCH_BITS), delimiters=[",", "\t"] + def __set_dialect(self): + self.__dialect = csv.Sniffer().sniff( + self.__stream.read(HEADER_SEARCH_BITS), delimiters=[",", "\t"] ) - self._reset_stream() + self.__reset_stream() - def _set_reader(self): - self._reader = csv.reader(self._stream, self._dialect) + def __set_reader(self): + self.__reader = csv.reader(self.__stream, self.__dialect) - def _set_header(self): - self._header = next(self._reader) + def __set_header(self): + self.__header = next(self.__reader) - def _end_parsing(self): - data = self._parse_data() - self._close_stream() + def __end_parsing(self): + # type: () -> numpy.ndarray + data = self.__parse_data() + self.__close_stream() return data - def _parse_data(self): - empty_array = self._setup_numpy_array() - return self._fill_array(empty_array) + def __parse_data(self): + # type: () -> numpy.ndarray + empty_array = self.__setup_numpy_array() + return self.__fill_array(empty_array) - def _setup_numpy_array(self): - types = self._build_numpy_types() - return self._make_empty_numpy_array(types) + def __setup_numpy_array(self): + # type: () -> numpy.ndarray + types = self.__build_numpy_types() + return self.__make_empty_numpy_array(types) - def _build_numpy_types(self): + def __build_numpy_types(self): + # type: () -> List[Tuple[str]] types = [] - for column in self._header: + for column in self.__header: types.append((column, "f8")) - self._logger.debug("Types: " + repr(types)) + self.__LOGGER.debug("Types: " + repr(types)) return types - def _make_empty_numpy_array(self, dtype): - return numpy.zeros(self._line_count, dtype) + def __make_empty_numpy_array(self, data_types): + # type: (List[Tuple[str]]) -> numpy.ndarray + return numpy.zeros(self.__line_count, data_types) - def _fill_array(self, empty_array): - for row_index, row_data in enumerate(self._reader): - self._fill_row(empty_array, row_index, row_data) + def __fill_array(self, empty_array): + # type: (numpy.ndarray) -> numpy.ndarray + for row_index, row_data in enumerate(self.__reader): + # this works because numpy arrays are passed around by reference + self.__fill_row(empty_array, row_index, row_data) return empty_array - def _fill_row(self, array, row_index, row_data): + def __fill_row(self, array, row_index, row_data): + # type: (numpy.ndarray, int, List[str]) -> None for column_index in range(len(row_data)): - array[self._header[column_index]][row_index] = \ + array[self.__header[column_index]][row_index] = \ row_data[column_index] class _SvMemoryWriter(object): - _dialect = "" - _column_names = None - _stream = None - _writer = None + def __init__(self): + self.__dialect = "" # type: str + self.__column_names = None # type: List[str] + self.__stream = None # type: io.FileIO + self.__writer = None # type: csv.DictWriter def write_memory_to_disk(self, file_location, data): - self._setup_initial_information(file_location, data) - self._setup_writer(file_location) - self._write_data(data) + # type: (str, numpy.ndarray) -> None + self.__setup_initial_information(file_location, data) + self.__setup_writer(file_location) + self.__write_data(data) - def _setup_initial_information(self, file_location, data): - self._process_dialect(file_location) - self._set_column_names(data) + def __setup_initial_information(self, file_location, data): + # type: (str, numpy.ndarray) -> None + self.__process_dialect(file_location) + self.__set_column_names(data) - def _process_dialect(self, file_location): - extension = self._get_extension(file_location) - self._set_dialect(extension) + def __process_dialect(self, file_location): + # type: (str) -> None + extension = self.__get_extension(file_location) + self.__set_dialect(extension) @staticmethod - def _get_extension(file_location): + def __get_extension(file_location): + # type: (str) -> str return os.path.splitext(file_location)[1] - def _set_dialect(self, extension): + def __set_dialect(self, extension): + # type: (str) -> None if extension == ".tsv": - self._dialect = csv.excel_tab + self.__dialect = csv.excel_tab else: - self._dialect = csv.excel + self.__dialect = csv.excel - def _set_column_names(self, data): - self._column_names = data.dtype.names + def __set_column_names(self, data): + # type: (numpy.ndarray) -> None + self.__column_names = data.dtype.names - def _setup_writer(self, file_location): - self._open_stream(file_location) - self._set_writer() - self._write_header() + def __setup_writer(self, file_location): + # type: (str) -> None + self.__open_stream(file_location) + self.__set_writer() + self.__write_header() - def _open_stream(self, file_location): + def __open_stream(self, file_location): + # type: (str) -> None if sys.version_info.major == 2: - self._stream = open(file_location, "w") + self.__stream = open(file_location, "w") else: - self._stream = io.open(file_location, "w") + self.__stream = io.open(file_location, "w") - def _set_writer(self): - self._writer = csv.DictWriter( - self._stream, fieldnames=self._column_names, dialect=self._dialect + def __set_writer(self): + self.__writer = csv.DictWriter( + self.__stream, fieldnames=self.__column_names, + dialect=self.__dialect ) - def _write_header(self): - self._writer.writeheader() + def __write_header(self): + self.__writer.writeheader() - def _write_data(self, data): - for index in self._iterator_over_columns(data): - new_dict = self._convert_row_to_dict(index, data) - self._writer.writerow(new_dict) + def __write_data(self, data): + # type: (numpy.ndarray) -> None + for index in self.__iterator_over_columns(data): + new_dict = self.__convert_row_to_dict(index, data) + self.__writer.writerow(new_dict) - def _iterator_over_columns(self, data): - length = len(data[self._column_names[0]]) + def __iterator_over_columns(self, data): + # type: (numpy.ndarray) -> Iterable + length = len(data[self.__column_names[0]]) return range(length) - def _convert_row_to_dict(self, row_index, data): + def __convert_row_to_dict(self, row_index, data): + # type: (int, numpy.ndarray) -> Dict[str, str] new_dict = {} - for column in self._column_names: + for column in self.__column_names: new_dict[column] = repr(data[column][row_index]) return new_dict diff --git a/PyPWA/builtin_plugins/data/builtin/sv/s_memory.pyi b/PyPWA/builtin_plugins/data/builtin/sv/s_memory.pyi deleted file mode 100644 index b6bc127f..00000000 --- a/PyPWA/builtin_plugins/data/builtin/sv/s_memory.pyi +++ /dev/null @@ -1,121 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import csv -import io -import logging -import typing - -import numpy -from PyPWA.builtin_plugins.data import data_templates - -__author__ = ... # type: typing.List[str] -__credits__ = ... # type: typing.List[str] -__maintainer__ = ... # type: typing.List[str] -__email__ = ... # type: str -__status__ = ... # type: str -__license__ = ... # type: str -__version__ = ... # type: str - -HEADER_SEARCH_BITS = ... # type: int - - -class SvMemory(data_templates.TemplateMemory): - - def parse(self, file_location: str) -> numpy.ndarray: ... - - def write(self, file_location: str, data: numpy.ndarray): ... - - -class _SvParser(object): - - _logger = logging.getLogger(__name__) - _line_count = ... # type: int - _dialect = ... # type: str - _stream = ... # type: io.FileIO - _reader = ... # type: csv.reader - _header = ... # type: typing.List[str] - - def __init__(self): ... - - def return_read_data(self, file_location: str) -> numpy.ndarray: ... - - def _start_parsing(self, file_location: str): ... - - def _open_stream(self, file_location: str): ... - - def _reset_stream(self): ... - - def _close_stream(self): ... - - def _set_line_number(self): ... - - def _set_required_data(self): ... - - def _set_dialect(self): ... - - def _set_reader(self): ... - - def _set_header(self): ... - - def _end_parsing(self) -> numpy.ndarray: ... - - def _parse_data(self): ... - - def _setup_numpy_array(self) -> numpy.ndarray: ... - - def _build_numpy_types(self) -> typing.List[typing.Tuple[str]]: ... - - def _make_empty_numpy_array(self, dtype: typing.List[typing.Tuple[str]]) -> numpy.ndarray: ... - - def _fill_array(self, empty_array: numpy.ndarray) -> numpy.ndarray: ... - - def _fill_row(self, array: numpy.ndarray, row_index: int, row_data: typing.List[numpy.float64]): ... - - -class _SvMemoryWriter(object): - - _dialect = ... # type: str - _column_names = ... # type: typing.List[str] - _stream = ... # type: io.FileIO - _writer = ... # type: csv.DictWriter - - def write_memory_to_disk(self, file_location: str, data: numpy.ndarray): ... - - def _setup_initial_information(self, file_location: str, data: numpy.ndarray): ... - - def _process_dialect(self, file_location: str): ... - - @staticmethod - def _get_extension(file_location: str) -> str: ... - - def _set_dialect(self, extension: str): ... - - def _set_column_names(self, data: numpy.ndarray): ... - - def _setup_writer(self, file_location: str): ... - - def _open_stream(self, file_location: str): ... - - def _set_writer(self): ... - - def _write_header(self): ... - - def _write_data(self, data: numpy.ndarray): ... - - def _iterator_over_columns(self, data: numpy.ndarray) -> range: ... - - def _convert_row_to_dict(self, row_index: int, data: numpy.ndarray) -> dict: ... diff --git a/PyPWA/builtin_plugins/data/builtin/sv/s_read_tests.py b/PyPWA/builtin_plugins/data/builtin/sv/s_read_tests.py index b2123d77..d85685cc 100644 --- a/PyPWA/builtin_plugins/data/builtin/sv/s_read_tests.py +++ b/PyPWA/builtin_plugins/data/builtin/sv/s_read_tests.py @@ -1,95 +1,98 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . import csv import io import logging -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data import data_templates from PyPWA.builtin_plugins.data import exceptions -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION -HEADER_SEARCH_BITS = 1024 + +HEADER_SEARCH_BITS = 3072 class SvDataTest(data_templates.ReadTest): - _stream = None # type: io.FileIO + def __init__(self): + self.__stream = None # type: io.FileIO def quick_test(self, file_location): - self._set_stream(file_location) - self._header_test() + # type: (str) -> None + self.__set_stream(file_location) + self.__header_test() def full_test(self, file_location): - self._set_stream(file_location) - self._header_test() + # type: (str) -> None + self.__set_stream(file_location) + self.__header_test() - def _set_stream(self, file_location): - self._stream = io.open(file_location, "r") + def __set_stream(self, file_location): + # type: (str) -> None + self.__stream = io.open(file_location, "r") - def _header_test(self): - header_test = _HeaderTest(self._stream) + def __header_test(self): + header_test = _HeaderTest(self.__stream) header_test.do_test() class _HeaderTest(object): - _logger = logging.getLogger(__name__) - _stream = None # type: io.FileIO - _sniffer = None # type: csv.Sniffer - _sample = None # type: str + __LOGGER = logging.getLogger(__name__ + "._HeaderTest") def __init__(self, stream): - self._logger.addHandler(logging.NullHandler()) - self._stream = stream + # type: (io.FileIO) -> None + self.__stream = stream + self.__sniffer = None # type: csv.Sniffer + self.__sample = None # type: str def do_test(self): - self._set_sniffer() - self._load_sample() - self._header_test() - self._reset_stream() + self.__set_sniffer() + self.__load_sample() + self.__header_test() + self.__reset_stream() - def _set_sniffer(self): - self._sniffer = csv.Sniffer() - self._sniffer.preferred = ["/t", ","] + def __set_sniffer(self): + self.__sniffer = csv.Sniffer() + self.__sniffer.preferred = ["/t", ","] - def _load_sample(self): - self._sample = self._stream.read(HEADER_SEARCH_BITS) + def __load_sample(self): + self.__sample = self.__stream.read(HEADER_SEARCH_BITS) - def _header_test(self): - if not self._has_a_header(): + def __header_test(self): + if not self.__has_a_header(): raise exceptions.IncompatibleData( "CSV Module failed to find the files header in " + str(HEADER_SEARCH_BITS) + " characters!" ) - def _has_a_header(self): + def __has_a_header(self): + # type: () -> bool try: - return self._sniffer.has_header(self._sample) + return self.__sniffer.has_header(self.__sample) except Exception as Error: - self._logger.error(Error) + self.__LOGGER.error(Error) return False - def _reset_stream(self): - self._stream.seek(0) + def __reset_stream(self): + self.__stream.seek(0) diff --git a/PyPWA/builtin_plugins/data/builtin/sv/s_read_tests.pyi b/PyPWA/builtin_plugins/data/builtin/sv/s_read_tests.pyi deleted file mode 100644 index 5c2037f1..00000000 --- a/PyPWA/builtin_plugins/data/builtin/sv/s_read_tests.pyi +++ /dev/null @@ -1,68 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import csv -import io -import logging -import typing - -from PyPWA.builtin_plugins.data import data_templates - -__author__ = ... # type: typing.List[str] -__credits__ = ... # type: typing.List[str] -__maintainer__ = ... # type: typing.List[str] -__email__ = ... # type: str -__status__ = ... # type: str -__license__ = ... # type: str -__version__ = ... # type: str - - -HEADER_SEARCH_BITS = ... # type: int - - -class SvDataTest(data_templates.ReadTest): - - _stream = ... # type: io.FileIO - - def quick_test(self, file_location: str): ... - - def full_test(self, file_location: str): ... - - def _set_stream(self, file_location: str): ... - - def _header_test(self): ... - - -class _HeaderTest(object): - - _logger = logging.getLogger(__name__) - _stream = ... # type: io.FileIO - _sniffer = ... # type: csv.Sniffer - _sample = ... # type: str - - def __init__(self, stream: io.FileIO): ... - - def do_test(self): ... - - def _set_sniffer(self): ... - - def _load_sample(self): ... - - def _header_test(self): ... - - def _has_a_header(self) -> bool: ... - - def _reset_stream(self): ... diff --git a/PyPWA/builtin_plugins/data/cache/__init__.py b/PyPWA/builtin_plugins/data/cache/__init__.py index 01b02096..c7677505 100644 --- a/PyPWA/builtin_plugins/data/cache/__init__.py +++ b/PyPWA/builtin_plugins/data/cache/__init__.py @@ -1,29 +1,27 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ Handles Caches for the data object """ -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION diff --git a/PyPWA/builtin_plugins/data/cache/_basic_info.py b/PyPWA/builtin_plugins/data/cache/_basic_info.py index 05e4d47a..49f1474b 100644 --- a/PyPWA/builtin_plugins/data/cache/_basic_info.py +++ b/PyPWA/builtin_plugins/data/cache/_basic_info.py @@ -1,91 +1,68 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ - +Finds the hash and cache location for the Cache Module. """ -import abc -import io import logging import os -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core import tools +from PyPWA import AUTHOR, VERSION +from PyPWA.core.shared import data_locator +from PyPWA.core.shared import generate_hash -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION -class BasicInfoInterface(object): - __metaclass__ = abc.ABCMeta - - @property - @abc.abstractmethod - def file_hash(self): - raise NotImplementedError - - @property - @abc.abstractmethod - def cache_location(self): - raise NotImplementedError - +class FindBasicInfo(object): -class FindBasicInfo(BasicInfoInterface): - _logger = logging.getLogger(__name__) - _hash_utility = tools.FileHashString() - _data_locator = tools.DataLocation() - _cache_location = "" - _found_hash = "" + __LOGGER = logging.getLogger(__name__ + ".FindBasicInfo") def __init__(self, original_file): - """ - Finds the hash and cache location for the Cache Module. - """ - self._setup_basic_info(original_file) - self._logger.addHandler(logging.NullHandler()) - - @property - def file_hash(self): - return self._found_hash - - @property - def cache_location(self): - return self._cache_location - - def _setup_basic_info(self, original_file): - self._set_cache_location(original_file) - self._set_file_hash(original_file) - - def _set_cache_location(self, original_file): - cache_location = self._get_cache_uri() - location = self._pair_filename_with_uri(original_file, cache_location) - self._cache_location = location + # type: (str) -> None + self.__cache_location = "" + self.__found_hash = "" + self.__setup_basic_info(original_file) + + def __setup_basic_info(self, original_file): + # type: (str) -> None + self.__set_cache_location(original_file) + self.__set_file_hash(original_file) + + def __set_cache_location(self, original_file): + # type: (str) -> None + cache_location = self.__get_cache_uri() + location = self.__pair_filename_with_uri( + original_file, cache_location + ) + self.__cache_location = location - def _get_cache_uri(self): - potential_cache_location = self._data_locator.get_cache_uri() - self._logger.debug("Found location is %s" % potential_cache_location) + def __get_cache_uri(self): + # type: () -> str + potential_cache_location = data_locator.get_cache_uri() + self.__LOGGER.debug("Found location is %s" % potential_cache_location) return potential_cache_location - def _pair_filename_with_uri(self, original_file, found_location): + def __pair_filename_with_uri(self, original_file, found_location): + # type: (str, str) -> str beginning_of_uri = "/" filename_extension = ".pickle" @@ -97,15 +74,26 @@ def _pair_filename_with_uri(self, original_file, found_location): filename_without_extension + filename_extension ) - self._logger.info("Cache Location set to %s" % final_location) + self.__LOGGER.debug("Cache Location set to '%s'" % final_location) return final_location - def _set_file_hash(self, original_file): - self._found_hash = self._file_hash(original_file) + def __set_file_hash(self, original_file): + # type: (str) -> None + self.__found_hash = self.__file_hash(original_file) + self.__LOGGER.debug( + "Found hash '%s' for '%s'" % ( + self.__found_hash, self.__cache_location + ) + ) + + @staticmethod + def __file_hash(original_file): + return generate_hash.get_sha512_hash(original_file) - self._logger.info("Found SHA512 hash for %s" % self._cache_location) - self._logger.debug("File Hash is set to %s" % self._found_hash) + @property + def file_hash(self): + return self.__found_hash - def _file_hash(self, original_file): - with io.open(original_file, "rb") as stream: - return self._hash_utility.get_sha512_hash(stream) + @property + def cache_location(self): + return self.__cache_location diff --git a/PyPWA/builtin_plugins/data/cache/_clear_cache.py b/PyPWA/builtin_plugins/data/cache/_clear_cache.py index a9818772..b1f362cb 100644 --- a/PyPWA/builtin_plugins/data/cache/_clear_cache.py +++ b/PyPWA/builtin_plugins/data/cache/_clear_cache.py @@ -1,18 +1,20 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ @@ -21,42 +23,36 @@ import logging import os -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data import exceptions from PyPWA.builtin_plugins.data.cache import _basic_info from PyPWA.builtin_plugins.data.cache import _template -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION class ClearCache(_template.ReadInterface): - _logger = logging.getLogger(__name__) - _info = _basic_info.FindBasicInfo + __LOGGER = logging.getLogger(__name__ + ".ClearCache") def __init__(self, basic_info): - self._logger.addHandler(logging.NullHandler()) - self._info = basic_info - self._attempt_to_remove_cache() + # type: (_basic_info.FindBasicInfo) -> None + self.__info = basic_info + self.__attempt_to_remove_cache() - @property def is_valid(self): return False def get_cache(self): raise exceptions.CacheError - def _attempt_to_remove_cache(self): + def __attempt_to_remove_cache(self): try: - self._remove_cache() + self.__remove_cache() except OSError: - self._logger.info("No cache to delete.") + self.__LOGGER.debug("No cache to delete.") - def _remove_cache(self): - os.remove(self._info.cache_location) \ No newline at end of file + def __remove_cache(self): + os.remove(self.__info.cache_location) diff --git a/PyPWA/builtin_plugins/data/cache/_no_cache.py b/PyPWA/builtin_plugins/data/cache/_no_cache.py index 2dbb3db1..b6bf36e0 100644 --- a/PyPWA/builtin_plugins/data/cache/_no_cache.py +++ b/PyPWA/builtin_plugins/data/cache/_no_cache.py @@ -1,48 +1,46 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ """ +from typing import Any -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data import exceptions from PyPWA.builtin_plugins.data.cache import _template -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION class NoWrite(_template.WriteInterface): def write_cache(self, data): + # type: (Any) -> None pass class NoRead(_template.ReadInterface): - @property def is_valid(self): return False def get_cache(self): raise exceptions.CacheError - diff --git a/PyPWA/builtin_plugins/data/cache/_standard_cache.py b/PyPWA/builtin_plugins/data/cache/_standard_cache.py index 55cd03cb..9a54ef0c 100644 --- a/PyPWA/builtin_plugins/data/cache/_standard_cache.py +++ b/PyPWA/builtin_plugins/data/cache/_standard_cache.py @@ -1,158 +1,127 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ +Standard Cache +-------------- +This simple just writes and reads the cache files without anything special +added to it. + +- ReadCache - Loads the cache from disk if it exists, will raise CacheError + if something is wrong with the cache. +- WriteCache - Writes the cache to disk. """ import io import logging import pickle +from typing import Any -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data import exceptions from PyPWA.builtin_plugins.data.cache import _basic_info from PyPWA.builtin_plugins.data.cache import _template -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION class ReadCache(_template.ReadInterface): - _info_object = _basic_info.FindBasicInfo - _packaged_data = {"hash": "", "data": object} - _logger = logging.getLogger(__name__) + __LOGGER = logging.getLogger(__name__ + ".ReadCache") def __init__(self, basic_info): - """ - Loads the cache from disk if it exists, will raise CacheError if - something is wrong with the cache. - """ - self._logger.addHandler(logging.NullHandler()) - self._info_object = basic_info - self._attempt_cache_load() - - @property - def is_valid(self): - return self._check_cache_is_valid() - - def get_cache(self): - if self.is_valid: - return self._packaged_data["data"] - else: - raise exceptions.CacheError - - def _attempt_cache_load(self): - found_data = self._graciously_load_cache() - self._set_data(found_data) - - def _graciously_load_cache(self): - self._logger.info( - "Attempting to load %s" % self._info_object.cache_location + # type: (_basic_info.FindBasicInfo) -> None + self.__info_object = basic_info + self.__packaged_data = {"hash": False, "data": object} + self.__graciously_load_cache() + + def __graciously_load_cache(self): + self.__LOGGER.debug( + "Attempting to load %s" % self.__info_object.cache_location ) try: - returned_data = self._load_data() - self._logger.info("Successfully loaded pickle cache!") + self.__load_data() + self.__LOGGER.debug("Successfully loaded pickle cache!") except (OSError, IOError): - returned_data = self._empty_raw_data - self._logger.info("No cache exists.") - except ( - pickle.PickleError, ValueError, IndexError, KeyError - ) as Error: - returned_data = self._empty_raw_data - self._logger.info( - "Pickle is from a different Python version or is damaged." - ) - self._logger.exception(Error) - return returned_data + self.__LOGGER.debug("No cache exists.") + except pickle.PickleError: + self.__LOGGER.debug("Pickle is from a different python version.") + except Exception as error: + self.__LOGGER.debug("Pickle is damaged.") + self.__LOGGER.debug(error, exc_info=True) - @property - def _empty_raw_data(self): - return {"hash": False, "data": object} + def __load_data(self): + with io.open(self.__info_object.cache_location, "rb") as stream: + self.__packaged_data = pickle.load(stream) - def _load_data(self): - with io.open(self._info_object.cache_location, "rb") as stream: - return pickle.load(stream) - - def _set_data(self, loaded_data): - self._packaged_data = loaded_data - - def _check_cache_is_valid(self): - if self._packaged_data["hash"] == self._info_object.file_hash: - return self._caches_match() - elif not self._packaged_data["hash"]: - return self._cache_hash_is_false() + def get_cache(self): + # type: () -> Any + if self.is_valid(): + return self.__packaged_data["data"] else: - return self._cache_hash_changed() - - def _caches_match(self): - self._logger.info("Cache Hashes match!") - return True - - def _cache_hash_is_false(self): - self._logger.debug("Cache load failed, hash is false.") - return False - - def _cache_hash_changed(self): - self._logger.warning("File hash has changed.") + raise exceptions.CacheError - self._logger.debug( - "%s != %s" % ( - self._packaged_data["hash"], - self._info_object.file_hash + def is_valid(self): + # type: () -> bool + if self.__packaged_data["hash"] == self.__info_object.file_hash: + self.__LOGGER.debug("Cache Hashes match!") + return True + elif not self.__packaged_data["hash"]: + self.__LOGGER.debug("Cache load failed, hash is false.") + return False + else: + self.__LOGGER.warning("File hash has changed.") + self.__LOGGER.debug( + "%s != %s" % ( + self.__packaged_data["hash"], + self.__info_object.file_hash + ) ) - ) - - return False + return False class WriteCache(_template.WriteInterface): - _packaged_data = {"hash": "", "data": object} - _logger = logging.getLogger(__name__) - _info_object = _basic_info.FindBasicInfo + __LOGGER = logging.getLogger(__name__ + ".WriteCache") def __init__(self, basic_info): - """ - Writes the cache to disk. - """ - self._logger.addHandler(logging.NullHandler()) - self._info_object = basic_info + # type: (_basic_info.FindBasicInfo) -> None + self.__info_object = basic_info + self.__packaged_data = {"hash": False, "data": object} def write_cache(self, data): - self._set_packaged_data(data) - self._write_cache_data() - - def _set_packaged_data(self, data): - self._packaged_data["hash"] = self._info_object.file_hash - self._packaged_data["data"] = data - - def _write_cache_data(self): - location = self._info_object.cache_location - - self._logger.info("Making cache for %s" % location) - + # type: (Any) -> None + self.__set_packaged_data(data) + self.__write_cache_data() + + def __set_packaged_data(self, data): + # type: (Any) -> None + self.__packaged_data["hash"] = self.__info_object.file_hash + self.__packaged_data["data"] = data + + def __write_cache_data(self): + location = self.__info_object.cache_location + self.__LOGGER.debug("Making cache for '%s'" % location) with io.open(location, "wb") as stream: pickle.dump( - self._packaged_data, stream, protocol=pickle.HIGHEST_PROTOCOL + self.__packaged_data, stream, protocol=pickle.HIGHEST_PROTOCOL ) diff --git a/PyPWA/builtin_plugins/data/cache/_template.py b/PyPWA/builtin_plugins/data/cache/_template.py index 43a83896..6b7e0e03 100644 --- a/PyPWA/builtin_plugins/data/cache/_template.py +++ b/PyPWA/builtin_plugins/data/cache/_template.py @@ -1,46 +1,49 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ +Interfaces for the cache objects defined in this package +-------------------------------------------------------- +- WriteInterface - Interface for all write objects +- ReadInterface - Interface for all read objects. """ -from PyPWA import VERSION, LICENSE, STATUS +from typing import Any + +from PyPWA import AUTHOR, VERSION -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION class WriteInterface(object): def write_cache(self, data): + # type: (Any) -> None raise NotImplementedError class ReadInterface(object): - @property def is_valid(self): raise NotImplementedError def get_cache(self): raise NotImplementedError - diff --git a/PyPWA/builtin_plugins/data/cache/builder.py b/PyPWA/builtin_plugins/data/cache/builder.py index 6f905ee1..79eddc56 100644 --- a/PyPWA/builtin_plugins/data/cache/builder.py +++ b/PyPWA/builtin_plugins/data/cache/builder.py @@ -1,128 +1,129 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ Memory Caching - +-------------- The objects in this file are dedicated to saving and writing chunks of memory to file for quick loading when the data is loaded into memory again. + +- _CacheInterface - A simple interface object to _WriteCache and _ReadCache + +- CacheBuilder - Builds the _CacheInterface using the other cache types + depending on the supplied booleans. """ import logging +from typing import Any -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data.cache import _basic_info from PyPWA.builtin_plugins.data.cache import _clear_cache from PyPWA.builtin_plugins.data.cache import _no_cache from PyPWA.builtin_plugins.data.cache import _standard_cache from PyPWA.builtin_plugins.data.cache import _template -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION class _CacheInterface(object): - _read_cache = _template.ReadInterface - _write_cache = _template.WriteInterface - def __init__(self, read_cache, write_cache): - """ - A simple interface object to _WriteCache and _ReadCache. - """ - self._read_cache = read_cache - self._write_cache = write_cache + # type: (_template.ReadInterface, _template.WriteInterface) -> None + self.__read_cache = read_cache + self.__write_cache = write_cache def write_cache(self, data): - self._write_cache.write_cache(data) + # type: (Any) -> None + self.__write_cache.write_cache(data) - @property def is_valid(self): - return self._read_cache.is_valid + return self.__read_cache.is_valid() def read_cache(self): """ - Raises: - cache.CacheError: If the hash has changed, is corrupt, or - doesn't exist, this error will be raised. + :raises cache.CacheError: If the hash has changed, or is corrupt. """ - return self._read_cache.get_cache() + return self.__read_cache.get_cache() class CacheBuilder(object): - _use_cache = True - _clear_cache = False - _info_object = _basic_info.FindBasicInfo - _selected_reader = _template.ReadInterface - _selected_writer = _template.WriteInterface - _logger = logging.getLogger(__name__) + + __LOGGER = logging.getLogger(__name__ + ".CacheBuilder") def __init__(self, use_cache=True, clear_cache=False): - self._logger.addHandler(logging.NullHandler()) - self._clear_cache = clear_cache - self._use_cache = use_cache + # type: (bool, bool) -> None + self.__clear_cache = clear_cache + self.__use_cache = use_cache + self.__info_object = None # type: _basic_info.FindBasicInfo + self.__selected_reader = None # type: _template.ReadInterface + self.__selected_writer = None # type: _template.WriteInterface def get_cache_interface(self, file_location): - self._set_info_object(file_location) - self._find_reader() - self._find_writer() - return self._make_interface() - - def _set_info_object(self, file_location): + # type: (str) -> _CacheInterface + self.__set_info_object(file_location) + self.__find_reader() + self.__find_writer() + return self.__make_interface() + + def __set_info_object(self, file_location): + # type: (str) -> None try: - self._info_object = _basic_info.FindBasicInfo(file_location) + self.__info_object = _basic_info.FindBasicInfo(file_location) except (OSError, IOError): - self._logger.warning("No original file found!") - self._enable_cache_fallback() - - def _enable_cache_fallback(self): - self._logger.debug("Cache set to fallback!") - self._use_cache = False - - def _find_reader(self): - if not self._use_cache: - self._logger.debug("No Read Cache selected.") - self._selected_reader = _no_cache.NoRead() - elif self._clear_cache: - self._logger.debug("Clear Cache selected.") - self._selected_reader = _clear_cache.ClearCache(self._info_object) + self.__LOGGER.warning("No original file found!") + self.__enable_cache_fallback() + + def __enable_cache_fallback(self): + self.__LOGGER.debug("Cache set to fallback!") + self.__use_cache = False + + def __find_reader(self): + if not self.__use_cache: + self.__LOGGER.debug("No Read Cache selected.") + self.__selected_reader = _no_cache.NoRead() + elif self.__clear_cache: + self.__LOGGER.debug("Clear Cache selected.") + self.__selected_reader = _clear_cache.ClearCache( + self.__info_object + ) else: - self._logger.debug("Read Cache selected.") - self._selected_reader = _standard_cache.ReadCache( - self._info_object + self.__LOGGER.debug("Read Cache selected.") + self.__selected_reader = _standard_cache.ReadCache( + self.__info_object ) - def _find_writer(self): - if not self._use_cache: - self._logger.debug("No Write Cache selected.") - self._selected_writer = _no_cache.NoWrite() + def __find_writer(self): + if not self.__use_cache: + self.__LOGGER.debug("No Write Cache selected.") + self.__selected_writer = _no_cache.NoWrite() else: - self._logger.debug("Write Cache selected.") - self._selected_writer = _standard_cache.WriteCache( - self._info_object + self.__LOGGER.debug("Write Cache selected.") + self.__selected_writer = _standard_cache.WriteCache( + self.__info_object ) - def _make_interface(self): + def __make_interface(self): + # type: () -> _CacheInterface return _CacheInterface( - self._selected_reader, - self._selected_writer + self.__selected_reader, + self.__selected_writer ) diff --git a/PyPWA/builtin_plugins/data/data_templates.py b/PyPWA/builtin_plugins/data/data_templates.py index 00f60a0c..038acb51 100644 --- a/PyPWA/builtin_plugins/data/data_templates.py +++ b/PyPWA/builtin_plugins/data/data_templates.py @@ -1,32 +1,35 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ -Holds the different implementation templates that are needed to interface +Holds the different implementation interfaces that are needed to interface data module. """ -from PyPWA import VERSION, LICENSE, STATUS +from typing import List + +import numpy + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.shared.interfaces import internals -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION @@ -34,44 +37,56 @@ class TemplateDataPlugin(object): @property def plugin_name(self): + # type: () -> str raise NotImplementedError() def get_plugin_memory_parser(self): + # type: () -> TemplateMemory raise NotImplementedError() def get_plugin_reader(self, file_location): + # type: (str) -> internals.Reader raise NotImplementedError() def get_plugin_writer(self, file_location): + # type: (str) -> internals.Writer raise NotImplementedError() def get_plugin_read_test(self): + # type: () -> ReadTest raise NotImplementedError() @property def plugin_supported_extensions(self): + # type: () -> List[str] raise NotImplementedError() @property def plugin_supports_flat_data(self): + # type: () -> bool raise NotImplementedError() @property def plugin_supports_gamp_data(self): + # type: () -> bool raise NotImplementedError() class TemplateMemory(object): + def parse(self, file_location): + # type: (str) -> numpy.ndarray raise NotImplementedError() def write(self, file_location, data): + # type: (str, numpy.ndarray) -> None raise NotImplementedError() class ReadTest(object): def quick_test(self, file_location): + # type: (str) -> None """ Raises: PyPWA.builtin_plugins.data.exceptions.IncompatibleData: Raised @@ -80,6 +95,7 @@ def quick_test(self, file_location): raise NotImplementedError() def full_test(self, file_location): + # type: (str) -> None """ Raises: PyPWA.builtin_plugins.data.exceptions.IncompatibleData: Raised diff --git a/PyPWA/builtin_plugins/data/data_templates.pyi b/PyPWA/builtin_plugins/data/data_templates.pyi deleted file mode 100644 index b78d7c4b..00000000 --- a/PyPWA/builtin_plugins/data/data_templates.pyi +++ /dev/null @@ -1,55 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import numpy -import typing -from PyPWA.core.templates import interface_templates - - -class TemplateDataPlugin(object): - - @property - def plugin_name(self) -> str: ... - - def get_plugin_memory_parser(self) -> TemplateMemory: ... - - def get_plugin_reader(self, file_location: str) -> interface_templates.ReaderInterfaceTemplate: ... - - def get_plugin_writer(self, file_location: str) -> interface_templates.WriterInterfaceTemplate: ... - - def get_plugin_read_test(self) -> ReadTest(): ... - - @property - def plugin_supported_extensions(self) -> typing.List[str]: ... - - @property - def plugin_supports_flat_data(self) -> bool: ... - - @property - def plugin_supports_gamp_data(self) -> bool: ... - - -class TemplateMemory(object): - def parse(self, file_location: str) -> numpy.ndarray: ... - - def write(self, file_location: str, data: numpy.ndarray): ... - - -class ReadTest(object): - - def quick_test(self, file_location: str): ... - - def full_test(self, file_location: str): ... diff --git a/PyPWA/builtin_plugins/data/exceptions.py b/PyPWA/builtin_plugins/data/exceptions.py index 690b13cc..b3ea75a3 100644 --- a/PyPWA/builtin_plugins/data/exceptions.py +++ b/PyPWA/builtin_plugins/data/exceptions.py @@ -1,31 +1,29 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ Stores the exceptions used by the parsing plugins for the data module. """ -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION diff --git a/PyPWA/builtin_plugins/data/iterator.py b/PyPWA/builtin_plugins/data/iterator.py index d1a2c984..954e0d93 100644 --- a/PyPWA/builtin_plugins/data/iterator.py +++ b/PyPWA/builtin_plugins/data/iterator.py @@ -1,70 +1,73 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Main object for iterating over data. +""" import logging +import numpy -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data import _plugin_finder from PyPWA.builtin_plugins.data import exceptions -from PyPWA.core.templates import plugin_templates +from PyPWA.core.shared.interfaces import plugins +from PyPWA.core.shared.interfaces import internals -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION -class Iterator(plugin_templates.DataReaderTemplate): - - _logger = logging.getLogger(__name__) - _fail = True - _plugin_fetcher = _plugin_finder.PluginSearch - - def __init__(self, fail=True, user_plugin="", **options): - self._logger.addHandler(logging.NullHandler()) +class Iterator(plugins.DataIterator): - self._fail = fail - self._plugin_fetcher = _plugin_finder.PluginSearch(user_plugin) + __LOGGER = logging.getLogger(__name__ + ".Iterator") - if options: - super(Iterator, self).__init__(options) + def __init__(self, fail=True, user_plugin=""): + # type: (bool, str) -> None + self.__fail = fail + self.__plugin_fetcher = _plugin_finder.PluginSearch(user_plugin) def return_reader(self, file_location): + # type: (str) -> internals.Reader try: - return self._get_reader_plugin(file_location) + return self.__get_reader_plugin(file_location) except exceptions.UnknownData as Error: - self._error_management(Error) + self.__error_management(Error) - def _get_reader_plugin(self, file_location): - plugin = self._plugin_fetcher.get_read_plugin(file_location) + def __get_reader_plugin(self, file_location): + # type: (str) -> internals.Reader + plugin = self.__plugin_fetcher.get_read_plugin(file_location) return plugin.get_plugin_reader(file_location) - def return_writer(self, file_location, data_shape): + def return_writer(self, file_location, data): + # type: (str, numpy.ndarray) -> internals.Writer try: - self._get_writer_plugin(file_location, data_shape) + return self.__get_writer_plugin(file_location, data) except exceptions.UnknownData as Error: - self._error_management(Error) + self.__error_management(Error) - def _get_writer_plugin(self, file_location, data): - plugin = self._plugin_fetcher.get_write_plugin(file_location, data) + def __get_writer_plugin(self, file_location, data): + # type: (str, numpy.ndarray) -> internals.Writer + plugin = self.__plugin_fetcher.get_write_plugin(file_location, data) return plugin.get_plugin_writer(file_location) - def _error_management(self, error): - if self._fail: + def __error_management(self, error): + # type: (Exception) -> None + if self.__fail: raise error diff --git a/PyPWA/builtin_plugins/data/memory.py b/PyPWA/builtin_plugins/data/memory.py index 595e1e66..aa7cfb90 100644 --- a/PyPWA/builtin_plugins/data/memory.py +++ b/PyPWA/builtin_plugins/data/memory.py @@ -1,115 +1,106 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Main object for Parsing Data +""" import logging -from PyPWA import VERSION, LICENSE, STATUS +import numpy + +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.data import _plugin_finder from PyPWA.builtin_plugins.data import exceptions -from PyPWA.core.templates import plugin_templates from PyPWA.builtin_plugins.data.cache import builder +from PyPWA.core.shared.interfaces import plugins +from PyPWA.builtin_plugins.data import data_templates -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION -class Memory(plugin_templates.DataParserTemplate): +class Memory(plugins.DataParser): - _enable_cache = True - _clear_cache = False - _user_plugin_dir = "" - _logger = logging.getLogger(__name__) - _plugin_search = _plugin_finder.PluginSearch - _cache_builder = builder.CacheBuilder - _cache_interface = builder._CacheInterface + __LOGGER = logging.getLogger(__name__ + ".Memory") def __init__( self, enable_cache=True, clear_cache=False, - user_plugin_dir="", **options + user_plugin_dir="" ): - self._logger.addHandler(logging.NullHandler()) - - self._enable_cache = enable_cache - self._clear_cache = clear_cache - self._user_plugin_dir = user_plugin_dir - - if options: - super(Memory, self).__init__(options=options) - - self._set_plugin_search() - - def _set_plugin_search(self): - self._plugin_search = _plugin_finder.PluginSearch( - self._user_plugin_dir - ) + # type: (bool, bool, str) -> None + self.__plugin_search = _plugin_finder.PluginSearch(user_plugin_dir) + self.__cache_builder = builder.CacheBuilder(enable_cache, clear_cache) + self.__cache_interface = None # type: builder._CacheInterface def parse(self, file_location): - self._set_cache_plugin() - self._set_cache_interface(file_location) - if self._cache_interface.is_valid: - self._logger.info("Found Cache, loading!") - return self._cache_interface.read_cache() + # type: (str) -> numpy.ndarray + self.__set_cache_interface(file_location) + if self.__cache_interface.is_valid(): + self.__LOGGER.info( + "Found Cache for '%s', loading!" % file_location + ) + return self.__cache_interface.read_cache() else: - self._logger.info("No cache found, loading file directly.") - return self._parse_with_cache(file_location) + self.__LOGGER.info("No cache found, loading file directly.") + return self.__parse_with_cache(file_location) - def _set_cache_plugin(self): - self._cache_builder = builder.CacheBuilder( - self._enable_cache, self._clear_cache - ) - - def _set_cache_interface(self, file_location): - self._cache_interface = self._cache_builder.get_cache_interface( + def __set_cache_interface(self, file_location): + # type: (str) -> None + self.__cache_interface = self.__cache_builder.get_cache_interface( file_location ) - def _parse_with_cache(self, file_location): - data = self._read_data(file_location) - self._cache_interface.write_cache(data) + def __parse_with_cache(self, file_location): + # type: (str) -> numpy.ndarray + data = self.__read_data(file_location) + self.__cache_interface.write_cache(data) return data - def _read_data(self, file_location): - plugin = self._load_read_plugin(file_location) + def __read_data(self, file_location): + # type: (str) -> numpy.ndarray + plugin = self.__load_read_plugin(file_location) returned_parser = plugin.get_plugin_memory_parser() return returned_parser.parse(file_location) - def _load_read_plugin(self, file_location): + def __load_read_plugin(self, file_location): + # type: (str) -> data_templates.TemplateDataPlugin try: - return self._plugin_search.get_read_plugin(file_location) + return self.__plugin_search.get_read_plugin(file_location) except exceptions.UnknownData: raise OSError def write(self, file_location, data): - self._write_data(file_location, data) - self._set_cache_plugin() - self._set_cache_interface(file_location) - self._cache_interface.write_cache(data) - - def _write_data(self, file_location, data): - plugin = self._load_write_plugin(file_location, data) + # type: (str, numpy.ndarray) -> None + self.__write_data(file_location, data) + self.__set_cache_interface(file_location) + self.__cache_interface.write_cache(data) + + def __write_data(self, file_location, data): + # type: (str, numpy.ndarray) -> None + plugin = self.__load_write_plugin(file_location, data) found_parser = plugin.get_plugin_memory_parser() found_parser.write(file_location, data) - def _load_write_plugin(self, file_location, data): + def __load_write_plugin(self, file_location, data): + # type: (str, numpy.ndarray) -> data_templates.TemplateDataPlugin try: - return self._plugin_search.get_write_plugin(file_location, data) + return self.__plugin_search.get_write_plugin(file_location, data) except exceptions.UnknownData: raise RuntimeError diff --git a/PyPWA/builtin_plugins/minuit/__init__.py b/PyPWA/builtin_plugins/minuit/__init__.py index b09feb66..6da32888 100644 --- a/PyPWA/builtin_plugins/minuit/__init__.py +++ b/PyPWA/builtin_plugins/minuit/__init__.py @@ -1,84 +1,76 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core.templates import option_templates -from PyPWA.builtin_plugins.minuit import minimization +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION +""" +Python Minimization with with Iminuit +------------------------------------- +This optimizer will try to find the nearest local minima in the function +provided using the settings that it was configured with. +To understand how to use the minimzer, read iminuit's documentation online. +""" -class MinuitOptions(option_templates.PluginsOptionsTemplate): - def _plugin_name(self): - return "Minuit" - def _plugin_interface(self): - return minimization.Minuit +from PyPWA import AUTHOR, VERSION +from PyPWA.builtin_plugins.minuit import _setup +from PyPWA.builtin_plugins.minuit import minimization +from PyPWA.core.configurator import options - def _plugin_type(self): - return self._minimization +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION - def _user_defined_function(self): - return None - def _default_options(self): - return { - "parameters": ["A1", "A2", "A3"], - "settings": {"A1": 1, "fix_A1": True}, - "strategy": 1, - "number of calls": 10000 - } +class MinuitOptions(options.Plugin): + plugin_name = "Minuit" + setup = _setup.MinuitSetup + provides = options.Types.OPTIMIZER + defined_function = None + module_comment = "Minuit is the tried and tested minimizer." - def _option_levels(self): - return { - "parameters": self._required, - "settings": self._required, - "strategy": self._optional, - "number of calls": self._advanced - } + default_options = { + "parameters": ["A1", "A2", "A3"], + "settings": {"A1": 1, "fix_A1": True}, + "strategy": 1, + "number of calls": 10000 + } - def _option_types(self): - return { - "parameters": list, - "settings": dict, - "strategy": int, - "number of calls": int - } + option_difficulties = { + "parameters": options.Levels.REQUIRED, + "settings": options.Levels.REQUIRED, + "strategy": options.Levels.OPTIONAL, + "number of calls": options.Levels.ADVANCED + } - def _module_comment(self): - return "Minuit is the tried and tested minimizer, developed " \ - "by ROOT" + option_types = { + "parameters": list, + "settings": dict, + "strategy": int, + "number of calls": int + } - def _option_comments(self): - return { - "parameters": - "The parameters used inside your settings and your " - "function", - "settings": - "The settings for iMinuit's fitting. See iMinuit " - "documentation", - "strategy": - "The strategy of Minuit. 0 for fast, 1 default, " - "2 for accurate", - "number of calls": - "The suggested max number of calls for " - } + option_comments = { + "parameters": + "The parameters used inside your settings and your function", + "settings": + "The settings for iMinuit's pyfit. See iMinuit documentation", + "strategy": + "The strategy of Minuit. 0 for fast, 1 default, 2 for accurate", + "number of calls": + "The suggested max number of calls for the fit." + } diff --git a/PyPWA/builtin_plugins/minuit/_save_data.py b/PyPWA/builtin_plugins/minuit/_save_data.py new file mode 100644 index 00000000..671702a6 --- /dev/null +++ b/PyPWA/builtin_plugins/minuit/_save_data.py @@ -0,0 +1,163 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Saves Data for iMinuit in a way the User can interact with it +------------------------------------------------------------- + +- _MakeTable - Makes the covariance table for the minimizer, also optionally + prints out the table. + +- _WriteData - takes all the essential data from the minimizer and saves to + the disk. + +- SaveData - the main object for saving data from iMinuit. +""" + +import logging + +import numpy +import tabulate + + +class _MakeTable(object): + + __logger = logging.getLogger(__name__ + "._MakeTable") + + __x = set() + __y = set() + __covariance = [] + + __fancy_table = None + __regular_table = None + + def make_tables(self, covariance_data): + self.__clear_variables() + self.__set_x_y_data(covariance_data) + self.__set_covariance_with_data(covariance_data) + self.__set_tables() + + def __clear_variables(self): + self.__x.clear() + self.__y.clear() + self.__covariance[:] = [] + + def __set_x_y_data(self, covariance_data): + for field in covariance_data: + self.__x.add(field[0]) + self.__y.add(field[1]) + + def __set_covariance_with_data(self, covariance_data): + for x in self.__x: + row = [x] + for y in self.__y: + row.append(covariance_data[(x, y)]) + self.__covariance.append(row) + + def __set_tables(self): + self.__fancy_table = tabulate.tabulate( + self.__covariance, self.__y, "fancy_grid", numalign="center" + ) + + self.__regular_table = tabulate.tabulate( + self.__covariance, self.__y, "grid", numalign="center" + ) + + def print_table(self): + print("Covariance: \n") + try: + print(self.__fancy_table) + except UnicodeEncodeError as system_error: + print(self.__regular_table) + self.__logger.info( + "Unicode tables are not supported, falling back to regular" + ) + self.__logger.debug(system_error, exc_info=True) + + @property + def table(self): + return self.__regular_table + + +class _WriteData(object): + + __save_location = None + __covariance_data = None + __final_value = None + __values = None + __table_data = None + + def __init__( + self, save_location, covariance_data, final_value, values, + table_data + ): + self.__save_location = save_location + self.__covariance_data = covariance_data + self.__final_value = final_value + self.__values = values + self.__table_data = table_data + + def write_data(self): + self.__save_text_data() + self.__save_numpy_data() + + def __save_text_data(self): + with open(self.__save_location + ".txt", "w") as stream: + stream.write("Covariance.\n") + stream.write(self.__table_data.table) + stream.write("\n") + stream.write("final value: " + str(self.__final_value)) + + def __save_numpy_data(self): + numpy.save( + self.__save_location + ".npy", { + "covariance": self.__covariance_data, + "fval": self.__final_value, + "values": self.__values + } + ) + + +class SaveData(object): + __logger = logging.getLogger(__name__ + "._SaveData") + __table = _MakeTable() + __write_data = None # type: _WriteData + + def save_data(self, save_location, covariance_data, final_value, values): + self.__load_table(covariance_data) + self.__print_table() + self.__set_write_data( + save_location, covariance_data, final_value, values + ) + self.__save_data_to_file() + + def __load_table(self, covariance_data): + self.__table.make_tables(covariance_data) + + def __print_table(self): + self.__table.print_table() + + def __set_write_data( + self, save_location, covariance_data, final_value, values + ): + self.__write_data = _WriteData( + save_location, covariance_data, final_value, values, self.__table + ) + + def __save_data_to_file(self): + self.__write_data.write_data() diff --git a/PyPWA/builtin_plugins/minuit/_setup.py b/PyPWA/builtin_plugins/minuit/_setup.py new file mode 100644 index 00000000..d7e47c41 --- /dev/null +++ b/PyPWA/builtin_plugins/minuit/_setup.py @@ -0,0 +1,50 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +The padding between config file and optimizer object. +""" + +from PyPWA import AUTHOR, VERSION +from PyPWA.builtin_plugins.minuit import minimization +from PyPWA.core.configurator import options + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class MinuitSetup(options.Setup): + + __command = None + __interface = None + + def __init__(self, command): + self.__command = command + self.__setup_interface() + + def __setup_interface(self): + self.__interface = minimization.Minuit( + parameters=self.__command.parameters, + settings=self.__command.settings, + strategy=self.__command.strategy, + number_of_calls=self.__command.number_of_calls + ) + + def return_interface(self): + return self.__interface diff --git a/PyPWA/builtin_plugins/minuit/minimization.py b/PyPWA/builtin_plugins/minuit/minimization.py index 37dc50bf..407e59a2 100644 --- a/PyPWA/builtin_plugins/minuit/minimization.py +++ b/PyPWA/builtin_plugins/minuit/minimization.py @@ -1,207 +1,132 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +A python a cython minimizer +-------------------------- +Attempts to find a minima, for information about how it works read Iminuit's +documentation online. + +- _ParserObject - Translates the received value inside run to something the + user can easily interact with. + +- Minuit - The main optimizer object. +""" import logging import iminuit import numpy -import tabulate -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core.templates import interface_templates -from PyPWA.core.templates import plugin_templates -__author__ = ["Mark Jones"] +from PyPWA import AUTHOR, VERSION +from PyPWA.builtin_plugins.minuit import _save_data +from PyPWA.core.shared.interfaces import internals +from PyPWA.core.shared.interfaces import plugins + __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION -class Minuit(plugin_templates.MinimizerTemplate): +class _ParserObject(internals.OptimizerOptionParser): - def __init__( - self, calc_function=False, parameters=False, settings=False, - fitting_type=False, strategy=1, number_of_calls=10000, - **options - ): - """ - Object based off of iminuit, provides an easy way to run - minimization - - Args: - calc_function (function): function that holds the - calculations. - parameters (list): List of the parameters - settings (dict): Dictionary of the settings for iminuit - strategy (int): iminuit's strategy - fitting_type (str): The type of fitting function, either - likelihood or chisquared. - number_of_calls (int): Max number of calls - options (dict): The settings dictionary built from the users - input and the plugin initializer. - """ - self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) - - self._final_value = 0 # type: numpy.float64 - self._covariance = 0 # type: tuple - self._values = 0 - self._set_up = 0 - - self._calc_function = calc_function + MULTIPLIER = -1 + + def __init__(self, parameters): self._parameters = parameters - self._settings = settings - self._strategy = strategy - self._number_of_calls = number_of_calls - if options: - super(Minuit, self).__init__(options) - def main_options(self, calc_function, fitting_type=False): - """ + def convert(self, *args): + parameters_with_values = {} + for parameter, arg in zip(self._parameters, args[0][0]): + parameters_with_values[parameter] = arg + + return parameters_with_values - Args: - calc_function: - fitting_type: - Returns: +class Minuit(plugins.Optimizer): - """ - self._calc_function = calc_function - self._error_def(fitting_type) + __logger = logging.getLogger(__name__ + ".Minuit") + __save_data = _save_data.SaveData() - def _check_params(self): - """ + __final_value = 0 # type: numpy.float64 + __covariance = 0 # type: tuple + __values = 0 + __set_up = 0 - Returns: + __calc_function = None + __parameters = None + __settings = None + __strategy = None + __number_of_calls = None + + def __init__( + self, parameters=False, settings=False, + strategy=1, number_of_calls=10000, + ): + self.__parameters = parameters + self.__settings = settings + self.__strategy = strategy + self.__number_of_calls = number_of_calls + + def main_options(self, calc_function, fitting_type=False): + self.__calc_function = calc_function + self.__error_def(fitting_type) - """ - if isinstance(self._parameters, bool): + def __check_params(self): + if isinstance(self.__parameters, bool): raise ValueError( "There are no supplied parameters! Please set " "'parameters' under 'Minuit' in your settings!" ) - self._logger.debug( - "Found parameters: {0}".format(repr(self._parameters)) + self.__logger.debug( + "Found parameters: {0}".format(repr(self.__parameters)) ) - def _error_def(self, fitting_type): - """ - - Args: - fitting_type: - - Returns: - - """ + def __error_def(self, fitting_type): if fitting_type == "chi-squared": self._set_up = 1 else: self._set_up = .5 def start(self): - """ - Method to call to start minimization process - """ - self._check_params() + self.__check_params() - self._logger.debug("Found settings: " + repr(self._settings)) + self.__logger.debug("Found settings: " + repr(self.__settings)) minimal = iminuit.Minuit( - self._calc_function, - forced_parameters=self._parameters, - **self._settings + self.__calc_function, + forced_parameters=self.__parameters, + **self.__settings ) - minimal.set_strategy(self._strategy) + minimal.set_strategy(self.__strategy) minimal.set_up(self._set_up) - minimal.migrad(ncall=self._number_of_calls) - self._final_value = minimal.fval - self._covariance = minimal.covariance - self._values = minimal.values - - def return_parser(self): - """ - - Returns: - interface_templates.MinimizerParserTemplate - """ - - class ParserObject(interface_templates.MinimizerParserTemplate): + minimal.migrad(ncall=self.__number_of_calls) - def __init__(self, parameters): - self._parameters = parameters + self.__final_value = minimal.fval + self.__covariance = minimal.covariance + self.__values = minimal.values - def convert(self, *args): - parameters_with_values = {} - for parameter, arg in zip(self._parameters, args[0][0]): - parameters_with_values[parameter] = arg - - return parameters_with_values - - return ParserObject(self._parameters) + def return_parser(self): + return _ParserObject(self.__parameters) def save_extra(self, save_name): - """ - - Args: - save_name: - - Returns: - - """ - if not isinstance(self._covariance, type(None)): - print("Covariance.\n") - the_x = [] - the_y = [] - for field in self._covariance: - the_x.append(field[0]) - the_y.append(field[1]) - - x_true = set(the_x) - y_true = set(the_y) - - covariance = [] - for x in x_true: - holding = [x] - for y in y_true: - holding.append(self._covariance[(x, y)]) - covariance.append(holding) - - table_fancy = tabulate.tabulate( - covariance, y_true, "fancy_grid", numalign="center" + if not isinstance(self.__covariance, type(None)): + self.__save_data.save_data( + save_name, self.__covariance, self.__final_value, + self.__values ) - - table = tabulate.tabulate( - covariance, y_true, "grid", numalign="center" - ) - - try: - print(table_fancy) - except UnicodeEncodeError: - print(table) - - with open(save_name + ".txt", "w") as stream: - stream.write("Covariance.\n") - stream.write(table) - stream.write("\n") - stream.write("fval: "+str(self._final_value)) - - numpy.save(save_name + ".npy", { - "covariance": self._covariance, - "fval": self._final_value, - "values": self._values - }) diff --git a/PyPWA/builtin_plugins/nestle/__init__.py b/PyPWA/builtin_plugins/nestle/__init__.py index 3d0c8a7f..8e5ff817 100644 --- a/PyPWA/builtin_plugins/nestle/__init__.py +++ b/PyPWA/builtin_plugins/nestle/__init__.py @@ -1,140 +1,125 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.builtin_plugins.nestle import nested -from PyPWA.core.templates import option_templates +""" +The nestle maximizer +-------------------- +This is a complex maximizer that takes a random array of n dimensions and +passes it through the prior to generate point data, then moves the live +points depending on the results of the returned value. To know what each +option does, check the actual documentation for nestle on ReadTheDocs.io or +the documentation inside nestle. -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION +- _graph_data - Doesn't graph the data, but saves the data needed to + generate a graph to file. +- _save_results - Where the table for the results are created and the data + is saved to disk -class NestleOptions(option_templates.PluginsOptionsTemplate): - def _plugin_name(self): - return "Nestle" +- _setup - Provides the interface between the plugin and the configurator. - def _plugin_interface(self): - return nested.NestledSampling +- nested - Where the actual optimization process takes place. +""" - def _plugin_type(self): - return self._minimization - def _user_defined_function(self): - return None +from PyPWA import AUTHOR, VERSION +from PyPWA.builtin_plugins.nestle import _setup +from PyPWA.core.configurator import options + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION - def _default_options(self): - return { - "prior location": "/location/to/prior.py", - "prior name": "prior_function", - "ndim": 1, - "npoints": 100, - "method": "single", - "update interval": None, - "npdim": None, - "maxiter": None, - "maxcall": None, - "dlogz": None, - "decline_factor": None - } - def _option_levels(self): - return { - "prior location": self._required, - "prior name": self._required, - "ndim": self._required, - "npoints": self._optional, - "method": self._optional, - "update interval": self._advanced, - "npdim": self._advanced, - "maxiter": self._advanced, - "maxcall": self._advanced, - "dlogz": self._advanced, - "decline_factor": self._advanced - } +class NestleOptions(options.Plugin): + plugin_name = "Nestle" + setup = _setup.NestleSetup + provides = options.Types.OPTIMIZER + defined_function = _setup.NestlePriorFunction + module_comment = "Nestle, a python based multinest implementation." - def _option_types(self): - return { - "prior location": str, - "prior name": str, - "ndim": int, - "npoints": int, - "method": ["classic", "single", "multi"], - "update interval": int, - "npdim": int, - "maxiter": int, - "maxcall": int, - "dlogz": float, - "decline_factor": float - } + default_options = { + "prior location": "/location/to/prior.py", + "prior name": "prior_function", + "ndim": 1, + "npoints": 100, + "method": "single", + "update interval": None, + "npdim": None, + "maxiter": None, + "maxcall": None, + "dlogz": None, + "decline_factor": None + } + option_difficulties = { + "prior location": options.Levels.REQUIRED, + "prior name": options.Levels.REQUIRED, + "folder location": options.Levels.OPTIONAL, + "ndim": options.Levels.REQUIRED, + "npoints": options.Levels.OPTIONAL, + "method": options.Levels.OPTIONAL, + "update interval": options.Levels.ADVANCED, + "npdim": options.Levels.ADVANCED, + "maxiter": options.Levels.ADVANCED, + "maxcall": options.Levels.ADVANCED, + "dlogz": options.Levels.ADVANCED, + "decline_factor": options.Levels.ADVANCED + } - def _module_comment(self): - return "Nestle, a python based multinest implementation." + option_types = { + "prior location": str, + "prior name": str, + "ndim": int, + "npoints": int, + "method": ["classic", "single", "multi"], + "update interval": int, + "npdim": int, + "maxiter": int, + "maxcall": int, + "dlogz": float, + "decline_factor": float + } - def _option_comments(self): - return { - "prior location": - "The path of the file containing the prior.", - "prior name": - "The name of the prior function.", - "ndim": - "Number of parameters returned by prior and accepted by " - "loglikelihood.", - "npoints": - "Number of active points. Larger numbers result in a more " - "finely sampled posterior (more accurate evidence), " - "but also a larger number of iterations required to " - "converge.", - "method": - "Method to select new points. Options are classic, " - "single-ellipsoidal (single), and multi-ellipsoidal (multi)", - "update interval": - "Only update the new point selector every " - "``update_interval``-th likelihood call. Update intervals " - "larger than 1 can be more efficient when the likelihood " - "function is very fast, particularly when using the " - "multi-ellipsoid method.", - "npdim": - "Number of parameters accepted by prior. This might differ " - "from *ndim* in the case where a parameter of loglikelihood " - "is dependent upon multiple independently distributed " - "parameters, some of which may be nuisance parameters.", - "maxiter": - "Maximum number of iterations. Iteration may stop earlier " - "if termination condition is reached.", - "maxcall": - "Maximum number of likelihood evaluations. Iteration may " - "stop earlier if termination condition is reached.", - "dlogz" : - "If supplied, iteration will stop when the estimated " - "contribution of the remaining prior volume to the total " - "evidence falls below this threshold. Explicitly, " - "the stopping criterion is " - "``log(z + z_est) - log(z) < dlogz`` where *z* is the " - "current evidence from all saved samples, and *z_est* is " - "the estimated contribution from the remaining volume. This " - "option and decline_factor are mutually exclusive.", - "decline_factor": - "If supplied, iteration will stop when the weight (" - "likelihood times prior volume) of newly saved samples has " - "been declining for ``decline_factor * nsamples`` " - "consecutive samples. A value of 1.0 seems to work pretty " - "well. This option and dlogz are mutually exclusive." - } + option_comments = { + "prior location": + "The path of the file containing the prior.", + "prior name": + "The name of the prior function.", + "ndim": + "Number of parameters returned by prior.", + "npoints": + "Number of active points.", + "method": + "Method to select new points.", + "update interval": + "Only update the new point selector every " + "``update_interval``-th likelihood call.", + "npdim": + "Number of parameters accepted by prior.", + "maxiter": + "Maximum number of iterations.", + "maxcall": + "Maximum number of likelihood evaluations.", + "dlogz": + "If supplied, iteration will stop when the estimated " + "contribution of the remaining prior volume to the total " + "evidence falls below this threshold.", + "decline_factor": + "If supplied, iteration will stop when the weight of newly " + "saved samples has been declining for x consecutive samples." + } diff --git a/PyPWA/builtin_plugins/nestle/_graph_data.py b/PyPWA/builtin_plugins/nestle/_graph_data.py new file mode 100644 index 00000000..9e7f6256 --- /dev/null +++ b/PyPWA/builtin_plugins/nestle/_graph_data.py @@ -0,0 +1,152 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Save graph data for the program. +-------------------------------- +Saves the data needed to graph the ongoing fit for nestle. + +- _Handler - Abstract object for saving data to disc. + +- _EllipsoidHandler - Saves the data for the ellipsoids. + +- _PointsHandler - Saves the information needed for the live points. + +- SaveData - Creates and clears the directory for saving the data, then saves + the live point data at each call of the likelihood. +""" + +import os +import shutil + +import numpy + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class _Handler(object): + + __data = None # type: numpy.ndarray + + def __init__(self, data): + self.__process_data(data) + + def __process_data(self, data): + list_of_points = self._find_points(data) + array_of_points = self.__convert_list_to_numpy(list_of_points) + self.__data = array_of_points + + @staticmethod + def _find_points(data): + raise NotImplementedError + + @staticmethod + def __convert_list_to_numpy(list_of_points): + return numpy.array(list_of_points) + + def save_data(self, file_location): + numpy.save(file_location, self.__data) + + +class _EllipsoidHandler(_Handler): + + @staticmethod + def _find_points(ellipsoids): + list_of_centers = [[],[]] + for ellipsoid in ellipsoids: + center = ellipsoid.ctr + list_of_centers[0].append(center[0]) + list_of_centers[1].append(center[1]) + return list_of_centers + + +class _PointsHandler(_Handler): + + @staticmethod + def _find_points(points): + xs_and_ys = [[],[]] + for point in points: + xs_and_ys[0].append(point[0]) + xs_and_ys[1].append(point[1]) + return xs_and_ys + + +class SaveData(object): + + __DATA_FOLDER = "saved_data" + + __basic_data = None # type: List[double] + __root_save_name = None # type: str + + def __init__(self, folder_name): + self.__create_empty_basic_data() + self.__handle_directories() + + def __set_folder_name(self, folder): + self.__DATA_FOLDER = folder + + def __create_empty_basic_data(self): + self.__basic_data = [] + + def __handle_directories(self): + if os.path.isdir(self.__DATA_FOLDER): + self.__clear_directory() + self.__create_directory() + + def __clear_directory(self): + shutil.rmtree(self.__DATA_FOLDER) + + def __create_directory(self): + os.mkdir(self.__DATA_FOLDER) + + def process_callback(self, info): + self.__set_root_save_name(info["it"]) + self.__process_ellipsoids(info["sampler"].ells) + self.__process_active_points(info["active_u"]) + self.__append_basic_data(info["logz"]) + + def __set_root_save_name(self, iteration): + self.__root_save_name = self.__DATA_FOLDER + "/" + self.__root_save_name += str(iteration) + "_" + + def __process_ellipsoids(self, ells): + handler = _EllipsoidHandler(ells) + save_location = self.__root_save_name + "ellipsoids.npy" + handler.save_data(save_location) + + def __process_active_points(self, points): + handler = _PointsHandler(points) + save_location = self.__root_save_name + "points.npy" + handler.save_data(save_location) + + def __append_basic_data(self, logz): + self.__basic_data.append(logz) + + def save_final_data(self): + final_data = self.__converted_basic_data() + self.__write_data(final_data) + + def __converted_basic_data(self): + return numpy.array(self.__basic_data) + + def __write_data(self, data): + numpy.save(self.__DATA_FOLDER + "/logz.npy", data) diff --git a/PyPWA/builtin_plugins/nestle/_save_results.py b/PyPWA/builtin_plugins/nestle/_save_results.py new file mode 100644 index 00000000..201824b1 --- /dev/null +++ b/PyPWA/builtin_plugins/nestle/_save_results.py @@ -0,0 +1,168 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Saves Data for Nestle in a way the User can interact with it +------------------------------------------------------------ + +- _MakeTable - Makes the covariance table for the minimizer, also optionally + prints out the tables. + +- _SaveData - takes all the essential data from the minimizer and saves to + the disk. + +- SaveData - the main object for saving data from iMinuit. +""" + +from __future__ import print_function + +import numpy +import nestle +import tabulate + + +class _MakeTable(object): + + __fancy_mean_table = None + __fancy_cov_table = None + __regular_mean_table = None + __regular_cov_table = None + + __covariance = None + __means = None + __index_list = list() + __mean_list = list() + __covariance_list = list() + + def make_tables(self, results): + self.__clear_variables() + self.__load_mean_and_covariance(results) + self.__set_index_list() + self.__create_mean_list() + self.__create_covariance_list() + self.__create_mean_tables() + self.__create_covariance_tables() + + def __clear_variables(self): + self.__covariance_list[:] = [] + self.__mean_list[:] = [] + self.__index_list[:] = [] + + def __load_mean_and_covariance(self, results): + self.__means, self.__covariance = nestle.mean_and_cov( + results.samples, results.weights + ) + + def __set_index_list(self): + self.__index_list = list(range(len(self.__covariance))) + + def __create_mean_list(self): + for index, mean in enumerate(self.__means): + row = [index, mean] + self.__mean_list.append(row) + + def __create_covariance_list(self): + for x in self.__index_list: + row = [x] + for y in self.__index_list: + row.append(self.__covariance[x, y]) + self.__covariance_list.append(row) + + def __create_mean_tables(self): + self.__fancy_mean_table = tabulate.tabulate( + self.__mean_list, ["Mean"], "fancy_grid", numalign="center" + ) + + self.__regular_mean_table = tabulate.tabulate( + self.__mean_list, ["Mean"], "grid", numalign="center" + ) + + def __create_covariance_tables(self): + self.__fancy_cov_table = tabulate.tabulate( + self.__covariance_list, self.__index_list, "fancy_grid", + numalign="center" + ) + + self.__regular_cov_table = tabulate.tabulate( + self.__covariance_list, self.__index_list, "grid", + numalign="center" + ) + + def print_tables(self): + try: + print(self.__fancy_mean_table) + print("Covariance: ") + print(self.__fancy_cov_table) + except UnicodeEncodeError: + print(self.__regular_mean_table) + print("Covariance: ") + print(self.__regular_cov_table) + + @property + def cov_table(self): + return self.__regular_cov_table + + @property + def mean_table(self): + return self.__regular_mean_table + + +class _SaveData(object): + + @classmethod + def save_data(cls, save_name, results, table): + cls.__save_text_data(save_name, results, table) + cls.__save_cov_data(save_name, results) + + @staticmethod + def __save_text_data(save_name, results, table): + with open(save_name + ".txt", "w") as stream: + stream.write(results.summary()) + stream.write("\n\n") + stream.write(table.mean_table) + stream.write("\n\n") + stream.write(table.cov_table) + + @staticmethod + def __save_cov_data(save_name, results): + mean, cov = nestle.mean_and_cov(results.samples, results.weights) + numpy.save(save_name + ".npy", {"mean": mean, "cov": cov}) + + +class SaveData(object): + + __tables = _MakeTable() + + def save_data(self, save_location, results): + self.__print_summery(results) + self.__make_tables(results) + self.__print_tables() + self.__save_data(save_location, results) + + @staticmethod + def __print_summery(results): + print(results.summary(), end="\n\n") + + def __make_tables(self, results): + self.__tables.make_tables(results) + + def __print_tables(self): + self.__tables.print_tables() + + def __save_data(self, save_location, results): + _SaveData.save_data(save_location, results, self.__tables) diff --git a/PyPWA/builtin_plugins/nestle/_setup.py b/PyPWA/builtin_plugins/nestle/_setup.py new file mode 100644 index 00000000..f058cfe6 --- /dev/null +++ b/PyPWA/builtin_plugins/nestle/_setup.py @@ -0,0 +1,84 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Takes the options from OptionsObject and parses those options into +NestedSampling. Also contains the reference function for Nestle's Prior. +""" + +import logging +from typing import Callable + +import numpy + +from PyPWA import AUTHOR, VERSION +from PyPWA.builtin_plugins.nestle import nested +from PyPWA.core.configurator import option_tools +from PyPWA.core.configurator import options + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class NestleSetup(options.Setup): + + __LOGGER = logging.getLogger(__name__ + ".NestleSetup") + + def __init__(self, options_object): + # type: (option_tools.CommandOptions) -> None + self.__options = options_object + self.__loader = nested.LoadPrior() + + self.__prior = None # type: Callable[[numpy.ndarray], numpy.ndarray] + self.__minimizer = None # type: nested.NestledSampling + + self.__load_prior() + self.__set_minimizer() + + def __load_prior(self): + self.__loader.load_prior( + self.__options.prior_location, self.__options.prior_name + ) + self.__prior = self.__loader.prior + + def __set_minimizer(self): + self.__minimizer = nested.NestledSampling( + self.__prior, self.__options.ndim, self.__options.npoints, + self.__options.method, self.__options.update_interval, + self.__options.npdim, self.__options.maxiter, + self.__options.maxcall, self.__options.dlogz, + self.__options.decline_factor + ) + + def return_interface(self): + # type: () -> nested.NestledSampling + return self.__minimizer + + +class NestlePriorFunction(options.FileBuilder): + imports = set() + functions = [ + """ +def prior(x): + # type: Callable[[numpy.ndarray], numpy.ndarray] + # For information about how to use nestle's prior function, please read + # nestle's documentation at: http://kylebarbary.com/nestle/index.html + return x + """ + ] diff --git a/PyPWA/builtin_plugins/nestle/nested.py b/PyPWA/builtin_plugins/nestle/nested.py index 5fae3e93..0552962f 100644 --- a/PyPWA/builtin_plugins/nestle/nested.py +++ b/PyPWA/builtin_plugins/nestle/nested.py @@ -1,119 +1,146 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Multinest maximization +---------------------- +A very accurate but slow optimizer that will try to find the maximas inside +your parameter space for provided function. + +- _NestleParserObject - Removes any extra information from the prior before + its passed to the kernels. + +- NestedSampling - The actual optimizer object. + +- LoadPrior - Loads the prior for the optimizer. +""" import logging +import typing import nestle -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core import plugin_loader -from PyPWA.core.templates import interface_templates -from PyPWA.core.templates import plugin_templates +from PyPWA import AUTHOR, VERSION +from PyPWA.builtin_plugins.nestle import _graph_data +from PyPWA.builtin_plugins.nestle import _save_results +from PyPWA.core.shared import plugin_loader +from PyPWA.core.shared.interfaces import internals +from PyPWA.core.shared.interfaces import plugins -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION -class _NestleParserObject(interface_templates.MinimizerParserTemplate): +class _NestleParserObject(internals.OptimizerOptionParser): def convert(self, *args): - return args[0][0] - + return args[0][0][0] -class NestledSampling(plugin_templates.MinimizerTemplate): - _logger = logging.getLogger(__name__) +class NestledSampling(plugins.Optimizer): - _loaded_function = None # type: typing.Any + __logger = logging.getLogger(__name__) + __callback_object = None # type: _graph_data.SaveData + __results = None # type: nestle.Result - _calc_function = None # type: typing.Any - _prior_location = None # type: str - _prior_name = None # type: str - _ndim = None # type: int - _npoints = None # type: int - _method = None # type: str - _update_interval = None # type: int - _npdim = None # type: int - _maxiter = None # type: int - _maxcall = None # type: int - _dlogz = None # type: float - _decline_factor = None # type: float + __calc_function = None # type: typing.Any + __prior = None # type: typing.Any + __npdim = None # type: int + __ndim = None # type: int + __npoints = None # type: int + __method = None # type: str + __update_interval = None # type: int + __maxiter = None # type: int + __maxcall = None # type: int + __dlogz = None # type: float + __decline_factor = None # type: float + __folder_location = False # type: str + __save_data = _save_results.SaveData() def __init__( - self, calc_function=False, prior_location=None, - prior_name=None, ndim=None, npoints=None, method=None, + self, prior, ndim, npoints=100, method="single", update_interval=None, npdim=None, maxiter=None, maxcall=None, - dlogz=None, decline_factor=None, **options + dlogz=None, decline_factor=None, folder_location=False ): - self._logger.addHandler(logging.NullHandler()) - - self._calc_function = calc_function - self._prior_location = prior_location - self._prior_name = prior_name - self._ndim = ndim - self._npoints = npoints - self._method = method - self._update_interval = update_interval - self._npdim = npdim - self._maxiter = maxiter - self._maxcall = maxcall - self._dlogz = dlogz - self._decline_factor = decline_factor - - if options: - super(NestledSampling, self).__init__(options) + self.__prior = prior + self.__ndim = ndim + self.__npoints = npoints + self.__method = method + self.__update_interval = update_interval + self.__npdim = npdim + self.__maxiter = maxiter + self.__maxcall = maxcall + self.__dlogz = dlogz + self.__decline_factor = decline_factor + self.__folder_location = folder_location def main_options(self, calc_function, fitting_type=False): - self._calc_function = calc_function + self.__calc_function = calc_function def start(self): - self._load_prior() - self._start_sampling() - - def _load_prior(self): - loader = plugin_loader.SingleFunctionLoader( - self._prior_location - ) - self._loaded_function = loader.fetch_function( - self._prior_name, True - ) - - def _start_sampling(self): - nestle.sample( - loglikelihood=self._calc_function, - prior_transform=self._loaded_function, - ndim=self._ndim, - npoints=self._npoints, - method=self._method, - update_interval=self._update_interval, - npdim=self._npdim, - maxiter=self._maxiter, - maxcall=self._maxcall, - dlogz=self._dlogz, - decline_factor=self._decline_factor + self.__start_sampling() + + def __setup_callback(self): + if self.__folder_location: + self.__logger.info("Writing nestle's data to disk.") + callback = _graph_data.SaveData(self.__folder_location) + self.__callback_object = callback.process_callback + + def __start_sampling(self): + self.__results = nestle.sample( + loglikelihood=self.__calc_function, + prior_transform=self.__prior, + ndim=self.__ndim, + npoints=self.__npoints, + method=self.__method, + update_interval=self.__update_interval, + npdim=self.__npdim, + maxiter=self.__maxiter, + maxcall=self.__maxcall, + dlogz=self.__dlogz, + decline_factor=self.__decline_factor, + callback=self.__callback_object ) def return_parser(self): return _NestleParserObject() def save_extra(self, save_name): - pass # We are still learning how nestle works.. + self.__save_data.save_data(save_name, self.__results) + + +class LoadPrior(object): + + __logger = logging.getLogger("_LoadPrior." + __name__) + __plugin_storage = plugin_loader.PluginLoader() + __found_prior = None # type: typing.Any + + def load_prior(self, prior_location, prior_name): + self.__add_prior_location(prior_location) + self.__set_prior(prior_name) + + def __add_prior_location(self, location): + self.__plugin_storage.add_plugin_location(location) + + def __set_prior(self, name): + self.__found_prior = self.__plugin_storage.get_by_name(name) + @property + def prior(self): + return self.__found_prior diff --git a/PyPWA/builtin_plugins/process/__init__.py b/PyPWA/builtin_plugins/process/__init__.py index 36ec190b..591970b5 100644 --- a/PyPWA/builtin_plugins/process/__init__.py +++ b/PyPWA/builtin_plugins/process/__init__.py @@ -1,18 +1,20 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ This is the builtin plugin for Multiprocessing, it works by taking the @@ -29,59 +31,36 @@ import multiprocessing -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core.templates import option_templates +from PyPWA import AUTHOR, VERSION +from PyPWA.builtin_plugins.process import _setup from PyPWA.builtin_plugins.process import foreman +from PyPWA.core.configurator import options -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION -class Processing(option_templates.PluginsOptionsTemplate): - - def _plugin_name(self): - return "Builtin Multiprocessing" - - def _plugin_interface(self): - return foreman.CalculationForeman - - def _plugin_type(self): - return self._kernel_processing - - def _user_defined_function(self): - return None +class Processing(options.Plugin): - def _default_options(self): - return { - "number of processes": multiprocessing.cpu_count() - } + plugin_name = "Builtin Multiprocessing" + setup = _setup.ProcessSetup + provides = options.Types.KERNEL_PROCESSING + defined_function = None + module_comment = "Builtin SMP Plugin, should be 'good enough'" - def _option_levels(self): - return { - "number of processes": self._optional - } + default_options = { + "number of processes": multiprocessing.cpu_count() * 2 + } - def _option_types(self): - return { - "number of processes": int - } + option_levels = { + "number of processes": options.Levels.OPTIONAL + } - def _module_comment(self): - return "This is the builtin processing plugin, you can replace " \ - "this with your own, or use one of the other options " \ - "that we have." + option_types = { + "number of processes": int + } - def _option_comments(self): - return { - "number of processes": - "This is the max number of processes to have running at " - "any time in the program, the hard max will always be 2 " - "* the number of CPUs in your computer so that we don't " - "resource lock your computer. Will work on any Intel or " - "AMD processor, PowerPCs might have difficulty here." - } + option_comments = { + "number of processes": "Number of processes to use for calculation." + } diff --git a/PyPWA/builtin_plugins/process/_communication.py b/PyPWA/builtin_plugins/process/_communication.py index b566c038..a07479f0 100644 --- a/PyPWA/builtin_plugins/process/_communication.py +++ b/PyPWA/builtin_plugins/process/_communication.py @@ -1,18 +1,20 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ This is an internal file that handles the communication between the main @@ -23,14 +25,10 @@ import multiprocessing -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION diff --git a/PyPWA/builtin_plugins/process/_processing.py b/PyPWA/builtin_plugins/process/_processing.py index 8371ea4e..975cbabb 100644 --- a/PyPWA/builtin_plugins/process/_processing.py +++ b/PyPWA/builtin_plugins/process/_processing.py @@ -1,43 +1,46 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ The processes and their factories are defined here. The current supported methods are Duplex for worker processes and Simplex for offload processes. """ +import logging import multiprocessing -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.process._communication import CommunicationFactory +from PyPWA.core.shared import initial_logging -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION class _DuplexProcess(multiprocessing.Process): daemon = True # This is set to true so that if the main process # dies the child processes will die as well. + __logging_level = None + __logging_file = None + __logger = None - def __init__(self, index, kernel, communicator): + def __init__(self, index, kernel, communicator, level, file): """ Main object for duplex processes. These processes are worker processes and as such will continue to run indefinitely until @@ -53,8 +56,10 @@ def __init__(self, index, kernel, communicator): children and vice versa. """ super(_DuplexProcess, self).__init__() + self.__logging_level = level + self.__logging_file = file self._kernel = kernel - self._kernel.processor_id = index + self._kernel.PROCESS_ID = index self._communicator = communicator def run(self): @@ -65,21 +70,40 @@ def run(self): Returns: 0: When the process is closed cleanly. """ + self.__setup_logger() + self.__set_logger() + self.__logger.debug( + "Starting logging in proc index %d" % self._kernel.PROCESS_ID + ) self._kernel.setup() while True: value = self._communicator.receive() - if value == "DIE": + if isinstance(value, str) and value == "DIE": + self.__logger.debug( + "Shutting down %d" % self._kernel.PROCESS_ID + ) break else: self._communicator.send(self._kernel.process(value)) return 0 + def __setup_logger(self): + initial_logging.InternalLogger.configure_root_logger( + self.__logging_level, self.__logging_file + ) + + def __set_logger(self): + self.__logger = logging.getLogger(__name__ + "._DuplexProcess") + class _SimplexProcess(multiprocessing.Process): daemon = True # Set to true so that if the main process dies, # the children will die as well. + __logging_level = None + __logging_file = None + __logger = None - def __init__(self, index, single_kernel, communicator): + def __init__(self, index, single_kernel, communicator, level, file): """ The simplex process is the simple offload process, anything passed to here will be ran immediately then send to the result @@ -94,8 +118,10 @@ def __init__(self, index, single_kernel, communicator): processed. """ super(_SimplexProcess, self).__init__() + self.__logging_level = level + self.__logging_file = file self._kernel = single_kernel - self._kernel.processor_id = index + self._kernel.PROCESS_ID = index self._communicator = communicator def run(self): @@ -107,10 +133,17 @@ def run(self): Returns: 0: On success. """ + self.__set_logger() self._kernel.setup() + self.__logger.debug( + "Starting logging in proc index %d" % self._kernel.PROCESS_ID + ) self._communicator.send(self._kernel.process()) return 0 + def __set_logger(self): + self.__logger = logging.getLogger(__name__ + "._SimplexProcess") + class CalculationFactory(object): @@ -138,7 +171,9 @@ def simplex_build(process_kernels): for index, internals in enumerate(zip(process_kernels, sends)): processes.append(_SimplexProcess( - index, internals[0], internals[1] + index, internals[0], internals[1], + initial_logging.InternalLogger.get_level(), + initial_logging.InternalLogger.get_filename() )) return [processes, receives] @@ -162,7 +197,9 @@ def duplex_build(process_kernels): for index, internals in enumerate(zip(process_kernels, process_com)): processes.append(_DuplexProcess( - index, internals[0], internals[1] + index, internals[0], internals[1], + initial_logging.InternalLogger.get_level(), + initial_logging.InternalLogger.get_filename() )) return [processes, main_com] diff --git a/PyPWA/builtin_plugins/process/_setup.py b/PyPWA/builtin_plugins/process/_setup.py new file mode 100644 index 00000000..787db7e3 --- /dev/null +++ b/PyPWA/builtin_plugins/process/_setup.py @@ -0,0 +1,43 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from PyPWA import AUTHOR, VERSION +from PyPWA.builtin_plugins.process import foreman +from PyPWA.core.configurator import options + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class ProcessSetup(options.Setup): + + __command = None + __interface = None + + def __init__(self, command): + self.__command = command + self.__setup_interface() + + def __setup_interface(self): + self.__interface = foreman.CalculationForeman( + number_of_processes=self.__command.number_of_processes + ) + + def return_interface(self): + return self.__interface diff --git a/PyPWA/builtin_plugins/process/foreman.py b/PyPWA/builtin_plugins/process/foreman.py index 08409639..90e7261c 100644 --- a/PyPWA/builtin_plugins/process/foreman.py +++ b/PyPWA/builtin_plugins/process/foreman.py @@ -1,18 +1,20 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ This is the main file for the process plugin. This plugin contains all @@ -26,22 +28,19 @@ import multiprocessing import numpy -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core.templates import interface_templates -from PyPWA.core.templates import plugin_templates + +from PyPWA import AUTHOR, VERSION from PyPWA.builtin_plugins.process import _communication from PyPWA.builtin_plugins.process import _processing +from PyPWA.core.shared.interfaces import internals +from PyPWA.core.shared.interfaces import plugins -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION -class _ProcessInterface(interface_templates.InterfaceTemplate): +class _ProcessInterface(internals.ProcessInterface): def __init__(self, interface_kernel, process_com, processes, duplex): """ @@ -59,7 +58,6 @@ def __init__(self, interface_kernel, process_com, processes, duplex): processing processes. """ self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) self._com = process_com self._interface_kernel = interface_kernel @@ -135,7 +133,7 @@ def is_alive(self): return self._processes[0].is_alive() -class CalculationForeman(plugin_templates.KernelProcessingTemplate): +class CalculationForeman(plugins.KernelProcessing): def __init__( self, number_of_processes=multiprocessing.cpu_count() * 2, @@ -158,7 +156,6 @@ def __init__( self._interface_template = False self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) self._number_of_processes = number_of_processes @@ -188,7 +185,7 @@ def main_options(self, data, process_template, interface_template): process_template, process_data ) - self._duplex = interface_template.is_duplex + self._duplex = interface_template.IS_DUPLEX self._interface_template = interface_template self._interface = self._build() diff --git a/PyPWA/core/__init__.py b/PyPWA/core/__init__.py index e5939ec5..d5da0230 100644 --- a/PyPWA/core/__init__.py +++ b/PyPWA/core/__init__.py @@ -1,29 +1,37 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ +All core logic is located here. +-------------------------------------------- +- shared - shared is where the universal interfaces and libs are located, + the plugin loader, the core interfaces that define how plugins should + operate, logging, hash generation, and data location api are all located + here. + +- configurator - This is the package that takes all the plugin's data and + converts it to YML format, then on run takes that YML file and converts it + to executing code. """ -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION diff --git a/PyPWA/core/configurator/__init__.py b/PyPWA/core/configurator/__init__.py index 248b4f38..44c07185 100644 --- a/PyPWA/core/configurator/__init__.py +++ b/PyPWA/core/configurator/__init__.py @@ -1,32 +1,79 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ -This Module is the main module for all of PyPWA. This module takes a -configuration file, processes it, then contacts the main module that is -requested to determine what information is needed to be loaded and how it -needs to be structured to be able to function in the desired way. +A Yml based configuration initializer for PyPWA. +------------------------------------------------ +This initializer takes a configuration file and uses it to initialize the +requested objects, to start the program. It also can take all the available +plugins and render those into a template configuration file. + +- create_config - That package that contains all the code needed to create + a configuration file from the available plugins, also contains the logic + for the questions and input handled for the --WriteConfig + +- execute - This takes a already made configuration file and then renders + it into requested objects that then becomes the program. + +- option_tools - the various little objects needed to parse and pass + information between the plugins. + +- options - The interfaces needed to create a plugin that can interact with + the configurator. + +- start - Argument loading, logging, and initial setup for the configurator. + +- storage - The Storage singleton that is the core to all managing and + interacting with plugins. """ -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import options -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION + + +class ConfiguratorOptions(options.Plugin): + + plugin_name = "Global Options" + default_options = { + "plugin directory": "none", + "logging": "error" + } + + option_difficulties = { + "plugin directory": options.Levels.ADVANCED, + "logging": options.Levels.OPTIONAL + } + + option_types = { + "plugin directory": str, + "logging": [ + "debug", "info", "warning", + "error", "critical", "fatal" + ] + } + + option_comments = { + "plugin directory": "Directory for any plugins you may have.", + "logging": "How much logging to enable, overridden by -v" + } + + module_comment = "These settings effect runtime settings for the program." diff --git a/PyPWA/core/configurator/_storage.py b/PyPWA/core/configurator/_storage.py deleted file mode 100644 index 6ef11a5a..00000000 --- a/PyPWA/core/configurator/_storage.py +++ /dev/null @@ -1,240 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" - -""" - -import logging - -import PyPWA.builtin_plugins -import PyPWA.shell -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core import plugin_loader -from PyPWA.core.templates import option_templates - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class PluginStorage(object): - - def __init__(self, extra_locations=None): - """ - - Args: - extra_locations: - """ - plugins = [PyPWA.builtin_plugins, PyPWA.shell] - - if isinstance(extra_locations, str): - plugins.append(extra_locations) - elif isinstance(extra_locations, list): - for plugin in extra_locations: - plugins.append(plugin) - - options_loader = plugin_loader.PluginLoading( - option_templates.PluginsOptionsTemplate - ) - - shell_loader = plugin_loader.PluginLoading( - option_templates.MainOptionsTemplate - ) - - self._plugins = options_loader.fetch_plugin(plugins) - self._shell = shell_loader.fetch_plugin(plugins) - - templates = {} - for plugin in self._plugins: - the_plugin = plugin() - templates[the_plugin.request_metadata("name")] = \ - the_plugin.request_options("template") - - for main in self._shell: - the_main = main() - templates[the_main.request_metadata("id")] = \ - the_main.request_options("template") - - self._templates = templates - - def request_main_by_id(self, the_id): - """ - - Args: - the_id (str): - - Returns: - - """ - for main in self._shell: - the_main = main() - if the_main.request_metadata("id") == the_id: - return the_main - return False - - def request_plugin_by_name(self, name): - for plugin in self._plugins: - the_plugin = plugin() - if the_plugin.request_metadata("name") == name: - return the_plugin - return False - - @property - def templates_config(self): - return self._templates - - -class MetadataStorage(object): - - def __init__(self): - """ - - """ - self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) - self._minimization = [] - self._kernel_processing = [] - self._data_reader = [] - self._data_parser = [] - - def add_plugins(self, plugins): - """ - - Args: - plugins: - - Returns: - - """ - for plugin in plugins: - self._plugin_filter(plugin) - - def _plugin_filter(self, plugin): - """ - - Args: - plugin: - - Returns: - - """ - try: - temp_object = plugin() - plugin_type = temp_object.request_metadata("provides") - - if plugin_type == "data reader": - self._data_reader.append(plugin) - elif plugin_type == "data parser": - self._data_parser.append(plugin) - elif plugin_type == "minimization": - self._minimization.append(plugin) - elif plugin_type == "kernel processing": - self._kernel_processing.append(plugin) - - except Exception as Error: - self._logger.error(Error) - - def search_plugin(self, plugin_name, plugin_type): - """ - - Args: - plugin_name: - plugin_type: - - Returns: - - """ - if plugin_type is "data reader": - return self._plugin_name_search( - plugin_name, self._data_reader - ) - - elif plugin_type is "data parser": - return self._plugin_name_search( - plugin_name, self._data_parser - ) - - elif plugin_type is "minimization": - return self._plugin_name_search( - plugin_name, self._minimization - ) - - elif plugin_type is "kernel processing": - return self._plugin_name_search( - plugin_name, self._kernel_processing - ) - - @staticmethod - def _plugin_name_search(plugin_name, plugins): - """ - - Args: - plugin_name: - plugins: - - Returns: - - """ - for plugin in plugins: - loaded_plugin = plugin() - name = loaded_plugin.request_metadata("name") - if name == plugin_name: - return plugin - else: - raise ImportError( - "Failed to find plugin {0}".format(plugin_name) - ) - - @property - def minimization(self): - """ - - Returns: - - """ - return self._minimization - - @property - def kernel_processing(self): - """ - - Returns: - - """ - return self._kernel_processing - - @property - def data_reader(self): - """ - - Returns: - - """ - return self._data_reader - - @property - def data_parser(self): - """ - - Returns: - - """ - return self._data_parser diff --git a/PyPWA/core/configurator/_tools.py b/PyPWA/core/configurator/_tools.py deleted file mode 100644 index 94e4f62f..00000000 --- a/PyPWA/core/configurator/_tools.py +++ /dev/null @@ -1,232 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" - -""" - -import logging - -import fuzzywuzzy.process -import numpy -from PyPWA import VERSION, LICENSE, STATUS - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -FUZZY_STRING_CONFIDENCE_LEVEL = 75 # percent from 0 to 100 - - -class SettingsAid(object): - - _failed = "failed to find" - - def __init__(self): - """ - Object that corrects the settings of the dictionaries rendered - in from the user. - """ - self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) - - def correct_settings(self, value, correct): - """ - Corrects the settings of the dictionary using a template - dictionary. - - Args: - value (dict): Users dictionary. - correct (dict): Template dictionary - - Returns: - dict: The corrected dictionary. - """ - key_correct_dictionary = self._correct_keys(value, correct) - return self._correct_all(key_correct_dictionary, correct) - - def _correct_all(self, dictionary, template_dictionary): - """ - Corrects all settings types. - - Args: - dictionary (dict): The users dictionary. - template_dictionary (dict): The Template dictionary. - - Returns: - dict: The corrected dictionary. - """ - corrected_dictionary = {} - for key in dictionary.keys(): - template_value = template_dictionary[key] - current_value = dictionary[key] - - if template_value == int: - corrected_dictionary[key] = self._correct_integers( - current_value - ) - - elif template_value == float: - corrected_dictionary[key] = self._correct_floats( - current_value - ) - - elif template_value == bool: - corrected_dictionary[key] = self._correct_boolean_values( - current_value - ) - - elif template_value == str: - corrected_dictionary[key] = str(current_value) - - elif template_value == list: - corrected_dictionary[key] = list(current_value) - - elif template_value == set: - corrected_dictionary[key] = set(current_value) - - elif isinstance(template_value, list): - corrected_dictionary[key] = self._correct_from_list( - current_value, template_value - ) - - elif isinstance(template_value, dict): - corrected_dictionary[key] = self.correct_settings( - current_value, template_value - ) - - else: - self._logger.debug( - "Key {0} is not correctable by settings " - "aid.".format(key) - ) - - corrected_dictionary[key] = current_value - - return corrected_dictionary - - def _correct_keys(self, dictionary, template_dictionary): - """ - Simple method that corrects only the keys in the dictionary. - - Args: - dictionary (dict): The users dictionary - template_dictionary (dict): The correct template dictionary. - - Returns: - dict: The dictionary with the corrected keys. - """ - key_correct_dict = {} - correct_keys = list(template_dictionary.keys()) - - for key in dictionary.keys(): - potential_key = fuzzywuzzy.process.extractOne( - key, correct_keys - ) - - if potential_key[1] >= FUZZY_STRING_CONFIDENCE_LEVEL: - key_correct_dict[potential_key[0]] = dictionary[key] - - else: - self._logger.warning( - "Unknown key {0}, value is being " - "removed!".format(key) - ) - - return key_correct_dict - - def _correct_from_list(self, string, value_list): - """ - Corrects a string using predefined strings inside a list. - - Args: - string (str): The users string - value_list (list): The potential values. - - Returns: - str: The corrected values. - """ - value = fuzzywuzzy.process.extractOne(string, value_list) - - if value[1] >= FUZZY_STRING_CONFIDENCE_LEVEL: - return value[0] - else: - return self._failed - - def _correct_boolean_values(self, value): - """ - Takes boolean values and translates them to Python Booleans. - - Args: - value (str): The users supplied value. - - Returns: - bool: The correct boolean. - """ - try: - exact = int(value) - if exact: - return True - else: - return False - except ValueError: - pass - - value = fuzzywuzzy.process.extractOne(value, ["true", "false"]) - if value[1] >= FUZZY_STRING_CONFIDENCE_LEVEL: - if value[0] == "true": - return True - elif value[0] == "false": - return False - else: - return self._failed - else: - return self._failed - - def _correct_integers(self, value): - """ - Corrects integers read in to actual integers. - - Args: - value (str): The string of the number. - - Returns: - int: The correct value. - """ - try: - return int(value) - except ValueError: - return self._failed - - def _correct_floats(self, value): - """ - Corrects the floats to numpy.float64s. - - Args: - value (str): The users float. - - Returns: - numpy.float64: The corrected value. - """ - try: - return numpy.float64(value) - except ValueError: - return self._failed diff --git a/PyPWA/core/configurator/config_loader.py b/PyPWA/core/configurator/config_loader.py deleted file mode 100644 index 7547cff2..00000000 --- a/PyPWA/core/configurator/config_loader.py +++ /dev/null @@ -1,479 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" - -""" - -import io -import logging -import os -import sys - -import PyPWA.builtin_plugins -import PyPWA.shell -import fuzzywuzzy.process -import ruamel.yaml -import ruamel.yaml.comments -import ruamel.yaml.parser -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core import plugin_loader -from PyPWA.core.configurator import _storage -from PyPWA.core.templates import option_templates - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class ConfigParser(object): - - def __init__(self): - """ - - """ - self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) - - def read_config(self, configuration): - """ - Parses the configuration that the user specified. - - Args: - configuration (str): The name of the configuration file. - - Returns: - dict: The configuration of the program. - """ - # Using the word 'unclean' is hip, right? - return self._parse_config(configuration) - - def _parse_config(self, configuration): - """ - Reads in the configuration file into memory then returns the - unfiltered dictionary. - If there is a syntax error it will catch the error then raise - a cleaned version of the error to not flood the user with - unneeded information. - The full exception will be passed to the logger if the user - wants to see the full error, should only show if they have - verboseness enabled. - - Args: - configuration (str): The name of the configuration file. - - Returns: - dict: The unfiltered dictionary of the configuration. - - Raises: - SyntaxError: If there is a typo or other similar error in the - configuration file. - """ - with open(configuration, "r") as stream: - try: - return ruamel.yaml.load( - stream, ruamel.yaml.RoundTripLoader - ) - except ruamel.yaml.parser.ParserError as UserError: - self._logger.exception(UserError) - raise SyntaxError(str(UserError)) - - -class SimpleConfigBuilder(object): - - def __init__(self): - """ - - """ - self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) - - self._plugin_handler = plugin_loader.PluginLoading( - option_templates.PluginsOptionsTemplate - ) - - self._input_manager = SimpleInputObject() - self._settings = ruamel.yaml.comments.CommentedMap() - - self._storage = None # type: _storage.MetadataStorage - self._plugin_directory = None # type: str - self._save_location = None # type: str - self._level = None # type: str - self._plugins = None # type: list - - def build_configuration( - self, plugin_name, main_plugin, - provided_options=None, save_location=False - ): - """ - - Args: - plugin_name: - main_plugin: - provided_options: - save_location: - - Returns: - - """ - self._determine_plugin_level() - self._determine_plugin_directory() - self._build_storage() - self._make_plugin_list(main_plugin) - self._build_configuration() - self._add_main_to_configuration(main_plugin) - self._correct_options(main_plugin, plugin_name, provided_options) - self._set_save_location(save_location) - self._write_final_config() - - def _determine_plugin_level(self): - """ - - Returns: - - """ - possible_levels = ["required", "optional", "advanced"] - - question = "\nHow much control would you like to have over the " \ - "configuration? \nrequired\noptional (default, " \ - "recommended)\nadvanced\n\n[optional]: " - - self._level = self._input_manager.input( - question, possible_levels, "optional" - ) - - def _determine_plugin_directory(self): - """ - - Returns: - - """ - question = "\nWould you like to use your own plugins? If YES " \ - "then please enter the location, if NO then just " \ - "press ENTER.\n[None]: " - - if self._level == "advanced": - self._plugin_directory = self._input_manager.input( - question, default_answer="None", is_dir=True - ) - else: - self._plugin_directory = None - - def _build_storage(self): - """ - - Returns: - - """ - plugins = self._plugin_handler.fetch_plugin( - [PyPWA.builtin_plugins, self._plugin_directory] - ) - - self._storage = _storage.MetadataStorage() - self._storage.add_plugins(plugins) - - def _make_plugin_list(self, main_plugin): - """ - - Args: - main_plugin: - - Returns: - - """ - list_maker = PluginList() - self._plugins = list_maker.parse_plugins( - main_plugin, self._storage - ) - - def _build_configuration(self): - """ - - Returns: - - """ - configuration = ruamel.yaml.comments.CommentedMap() - for plugin in self._plugins: - configuration.update(plugin.request_options(self._level)) - self._settings = configuration - - def _add_main_to_configuration(self, main_plugin): - """ - - Args: - main_plugin: - - Returns: - - """ - self._settings.update(main_plugin.request_options(self._level)) - - def _correct_options( - self, main_plugin, main_name, provided_options - ): - """ - - Args: - main_plugin: - main_name: - provided_options: - - Returns: - - """ - shell_id = main_plugin.request_metadata("id") - - if provided_options: - for option in provided_options: - try: - self._settings[shell_id].pop(option) - except KeyError: - raise AttributeError( - "There is no option '{0}'!".format(option) - ) - - self._settings[main_name] = self._settings[shell_id] - self._settings.pop(shell_id) - - def _set_save_location(self, save_location=False): - """ - - Args: - save_location: - - Returns: - - """ - question = "\nWhat would you like to name the configuration " \ - "file?\nFile Name?: " - - if save_location: - self._save_location = save_location - else: - self._save_location = self._input_manager.input(question) - - def _write_final_config(self): - """ - - Returns: - - """ - with open(self._save_location, "w") as stream: - stream.write( - ruamel.yaml.dump( - self._settings, Dumper=ruamel.yaml.RoundTripDumper - ) - ) - - -class PluginList(object): - - def __init__(self): - """ - - """ - self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) - - self._input_manager = SimpleInputObject() - - def parse_plugins(self, main_plugin, storage): - """ - - Args: - main_plugin: - storage: - - Returns: - - """ - plugins = [] - if main_plugin.requires("data parser"): - plugins.append(self._process_plugins( - "data parser", "Data Parsing", storage, - storage.data_parser - )) - - if main_plugin.requires("data reader"): - plugins.append(self._process_plugins( - "data reader", "Data Iterator", storage, - storage.data_reader - )) - - if main_plugin.requires("kernel processing"): - plugins.append(self._process_plugins( - "kernel processing", "Kernel Processor", storage, - storage.kernel_processing - )) - - if main_plugin.requires("minimization"): - plugins.append(self._process_plugins( - "minimization", "Minimizer", storage, - storage.minimization - )) - - return plugins - - def _process_plugins( - self, plugin_type, plugin_type_name, storage, plugin_list - ): - """ - - Args: - plugin_type: - plugin_type_name: - storage: - plugin_list: - - Returns: - - """ - if len(plugin_list) == 1: - empty_plugin = plugin_list[0] - else: - name = self._ask_plugin( - plugin_list, plugin_type_name - ) - - empty_plugin = storage.search_plugin(name, plugin_type) - - return empty_plugin() - - def _ask_plugin(self, plugin_list, plugin_type): - """ - - Args: - plugin_list: - plugin_type: - - Returns: - - """ - names = [] - for plugin in plugin_list: - the_plugin = plugin() - names.append(the_plugin.request_metadata("name")) - - string = "Which would plugin would you " \ - "like to use for {0}?".format(plugin_type) - - for name in names: - string += "\n{0}".format(name) - - string += "\nPlugin?: " - - return self._input_manager.input(string, possible_answers=names) - - -class SimpleInputObject(object): - - def __init__(self, auto_correct_percentage=75): - """ - - Args: - auto_correct_percentage: - """ - self._auto_correction_percentage = auto_correct_percentage - - def input( - self, string, possible_answers=False, - default_answer=False, is_dir=False - ): - """ - - Args: - string (str): - possible_answers (list): - default_answer (str): - is_dir (bool): - - Returns: - - """ - final_answer = False - - while not final_answer: - answer = self.__input(string) - - if answer is "" and default_answer: - final_answer = default_answer - continue - - else: - if possible_answers: - corrected_answer = fuzzywuzzy.process.extractOne( - answer, possible_answers - ) - - if corrected_answer[1] > \ - self._auto_correction_percentage: - answer = corrected_answer[0] - if is_dir: - if not os.path.isdir(answer): - continue - if self._is_correct(answer): - final_answer = answer - - if final_answer == "None": - final_answer = None - return final_answer - - def _is_correct(self, answer): - final_answer = False - string = """\ -It looks like you selected '{0}', is this correct? -[Y]es/No: """ - - while not final_answer: - is_correct = self.__input(string.format(answer)) - - value = fuzzywuzzy.process.extractOne( - is_correct.lower(), ["yes", "no"] - ) - - if is_correct == "": - final_answer = "yes" - break - - if value[1] > self._auto_correction_percentage: - if value[0] == "yes": - final_answer = "yes" - else: - final_answer = "no" - - if final_answer == "yes": - return True - elif final_answer == "no": - return False - - @staticmethod - def __input(string): - """ - - Args: - string: - - Returns: - - """ - if sys.version_info.major == 2: - return raw_input(string) - else: - return input(string) diff --git a/PyPWA/core/configurator/configurator.py b/PyPWA/core/configurator/configurator.py deleted file mode 100644 index 254e63b8..00000000 --- a/PyPWA/core/configurator/configurator.py +++ /dev/null @@ -1,280 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -This file is the main file for all of PyPWA. This file takes a -configuration file, processes it, then contacts the main module that is -requested to determine what information is needed to be loaded and how it -needs to be structured to be able to function in the users desired way. -""" - -import logging - -import PyPWA.builtin_plugins -import PyPWA.shell -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core import plugin_loader -from PyPWA.core.configurator import _storage -from PyPWA.core.configurator import _tools -from PyPWA.core.configurator import config_loader -from PyPWA.core.templates import configurator_templates -from PyPWA.core.templates import option_templates - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class Configurator(configurator_templates.ShellCoreTemplate): - - def __init__(self): - """ - - """ - self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) - - self._config_parser = config_loader.ConfigParser() - self._settings_aid = _tools.SettingsAid() - - def make_config(self, function_settings, application_settings): - """ - - Args: - function_settings: - application_settings: - - Returns: - - """ - main_plugin = None - plugin_name = function_settings["main name"] - plugin_id = function_settings["main"] - settings = None - - self._logger.debug("Searching for ID: {0}".format(plugin_id)) - self._logger.debug("Searching for name: {0}".format(plugin_name)) - - try: - settings = function_settings["main options"] - except KeyError: - pass - - loader = plugin_loader.PluginLoading( - option_templates.MainOptionsTemplate - ) - - plugin_list = loader.fetch_plugin([PyPWA.shell]) - - for plugin in plugin_list: - temp_object = plugin() - if temp_object.request_metadata("id") == plugin_id: - main_plugin = temp_object - break - - if not main_plugin: - raise RuntimeError( - "There was no main plugin found for id '{0}'!".format( - plugin_id - ) - ) - - config_maker = config_loader.SimpleConfigBuilder() - - config_maker.build_configuration( - plugin_name, main_plugin, settings, - application_settings.configuration - ) - - def run(self, function_settings, configuration_location): - """ - - Args: - function_settings (dict): - configuration_location: - - Returns: - - """ - extra_plugins = False - - parsed_config = self._config_parser.read_config( - configuration_location - ) - - try: - for key in list(function_settings["main options"].keys()): - parsed_config[function_settings["main name"]][key] = \ - function_settings["main options"][key] - except KeyError: - pass - - parsed_config[function_settings["main"]] = \ - parsed_config[function_settings["main name"]] - - parsed_config.pop(function_settings["main name"]) - - try: - extra_plugins = \ - parsed_config["Global Options"]["plugin directory"] - except KeyError: - pass - - storage = _storage.PluginStorage(extra_plugins) - plugins_template = storage.templates_config - - complete_templates = \ - self._add_configuration_settings(plugins_template) - - correct_settings = self._settings_aid.correct_settings( - parsed_config, complete_templates - ) - - launcher = ShellLauncher(storage, correct_settings) - launcher.start() - - @staticmethod - def _add_configuration_settings(templates): - """ - - Args: - templates: - - Returns: - - """ - special_sauce = ConfiguratorOptions() - templates[special_sauce.request_metadata("name")] = \ - special_sauce.request_options("template") - return templates - - -class ShellLauncher(object): - - def __init__(self, plugin_storage, settings): - """ - - Args: - plugin_storage (PluginStorage): - settings (dict): - """ - self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) - - self._plugin_storage = plugin_storage - self._settings = settings - - def start(self): - """ - - Returns: - - """ - the_ids = list(self._settings.keys()) - main = None # type: option_templates.MainOptionsTemplate - plugins = [] - initialized_plugins = {} - - for the_id in the_ids: - temp = self._plugin_storage.request_plugin_by_name(the_id) - if temp: - plugins.append(temp) - - for the_id in the_ids: - temp = self._plugin_storage.request_main_by_id(the_id) - if temp: - self._logger.debug("Found: " + repr(temp)) - main = temp - - for plugin in plugins: - name = plugin.request_metadata("name") - the_type = plugin.request_metadata("provides") - interface = plugin.request_metadata("interface") - initialized = interface(**self._settings[name]) - initialized_plugins[the_type] = initialized - - main_settings = self._settings[main.request_metadata("id")] - - for key in list(initialized_plugins.keys()): - main_settings[key] = initialized_plugins[key] - - self._logger.debug("Found settings: " + repr(main_settings)) - - shell = main.request_metadata("object") - initialized_shell = shell(**main_settings) - initialized_shell.start() - - -class ConfiguratorOptions(option_templates.PluginsOptionsTemplate): - - def _plugin_name(self): - return "Global Options" - - def _plugin_interface(self): - return False - - def _plugin_type(self): - return False - - def _user_defined_function(self): - return None - - def _default_options(self): - return { - "plugin directory": "none", - "logging": [ - "debug", "info", "warning", - "error", "critical", "fatal" - ] - } - - def _option_levels(self): - return { - "plugin directory": self._advanced, - "logging": self._optional - } - - def _option_types(self): - return { - "plugin directory": str, - "logging": [ - "debug", "info", "warning", - "error", "critical", "fatal" - ] - } - - def _option_comments(self): - return { - "plugin directory": - "This is the option that you would add your own plugins " - "to the system. Supported plugins are Data parsing and " - "writing, minimization, and even new programs " - "capitalizing on the internal frameworking of " - "the program.", - "logging": - "This sets the logging level of the program, supported " - "options are debug, info, warning, error, critical, and " - "fatal. This setting will be overwritten by the command " - "prompt if the user specifies -v" - } - - def _module_comment(self): - return "This is the global loaders settings. These settings " \ - "are the options that will be set for the entire program." diff --git a/PyPWA/core/configurator/create_config/__init__.py b/PyPWA/core/configurator/create_config/__init__.py new file mode 100644 index 00000000..72c37e6a --- /dev/null +++ b/PyPWA/core/configurator/create_config/__init__.py @@ -0,0 +1,50 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Creates the initial configuration template for users to modify. +--------------------------------------------------------------- + +- _builder - Builds the actual configuration for the program. + +- _function_builder - Defines how the example function file is built and + written to file. + +- _input_loop - Provides a simple object to extend for defining questions. + +- _level_processing - takes a plugin and a requested level and returns + the needed options for the selected difficulty. + +- _metadata - Objects that interact directly with the plugins and shells, + determines which plugins to load. + +- _override - Overrides options and keys in the created + template configuration. + +- _questions - Stores questions that the user can be asked. + +- _writer - Each of the potential configuration writers are defined here. + +- create - The main object for create_config. +""" + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION diff --git a/PyPWA/core/configurator/create_config/_builder.py b/PyPWA/core/configurator/create_config/_builder.py new file mode 100644 index 00000000..b688d1af --- /dev/null +++ b/PyPWA/core/configurator/create_config/_builder.py @@ -0,0 +1,117 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Creates the configuration +------------------------- + +- _GlobalOptions - Setups the global options if any are required. +- BuildConfig - The main object that builds the configuration. +""" + +from typing import Any, Dict + +import ruamel.yaml.comments + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import options +from PyPWA.core.configurator.create_config import _level_processing +from PyPWA.core.configurator.create_config import _metadata +from PyPWA.core.configurator.create_config import _override +from PyPWA.core.configurator.create_config import _questions + +__credits__ = ["Mark Jones", "Ryan Wright"] +__author__ = AUTHOR +__version__ = VERSION + + +class _GlobalOptions(object): + + def __init__(self): + self.__global_options = {"Global Options": {"plugin directory": ""}} + + def build_options(self, plugin_dir): + # type: (_questions.GetPluginDirectory) -> None + if plugin_dir.get_plugin_directory(): + self.__set_plugin_dir(plugin_dir) + else: + self.__global_options = None + + def __set_plugin_dir(self, plugin_dir): + # type: (_questions.GetPluginDirectory) -> None + self.__global_options["Global Options"]["plugin directory"] = \ + plugin_dir.get_plugin_directory() + + @property + def global_options(self): + # type: () -> Dict[str, Any] + return self.__global_options + + +class BuildConfig(object): + + def __init__( + self, + plugin_dir, # type: _questions.GetPluginDirectory + plugin_list, # type: _metadata.GetPluginList + level # type: options.Levels + ): + # type: (...) -> None + self.__global = _GlobalOptions() + self.__configuration = ruamel.yaml.comments.CommentedMap() + self.__level_fetch = _level_processing.ProcessOptions() + self.__overrider = _override.Override() + self.__plugin_dir = plugin_dir + self.__plugin_list = plugin_list + self.__level = level + + def build(self, overrides): + # type: (Dict[str, Any]) -> None + self.__create_configuration() + self.__overrider.execute(self.__configuration, overrides) + + def __create_configuration(self): + self.__update_shell() + self.__update_plugins() + + def __update_global_options(self): + self.__global.build_options(self.__plugin_dir) + if self.__global.global_options: + self.__configuration.update(self.__global.global_options) + + def __update_shell(self): + self.__configuration.update( + self.__get_plugin_options(self.__plugin_list.shell) + ) + + def __update_plugins(self): + for plugin in self.__plugin_list.plugins: + self.__configuration.update( + self.__get_plugin_options(plugin) + ) + + def __get_plugin_options(self, plugin): + # type: (options.Base) -> Dict[str, Any] + return self.__level_fetch.processed_options( + plugin, self.__level.get_plugin_level() + ) + + @property + def configuration(self): + # type: () -> Dict[str, Any] + return self.__overrider.processed_configuration diff --git a/PyPWA/core/configurator/create_config/_function_builder.py b/PyPWA/core/configurator/create_config/_function_builder.py new file mode 100644 index 00000000..586152d7 --- /dev/null +++ b/PyPWA/core/configurator/create_config/_function_builder.py @@ -0,0 +1,184 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Writer for Example Functions +---------------------------- + +- _GetFunctionLocation - Takes the configuration file location then derives + a function file location using the same name. + +- _FunctionStorage - a simple object used for passing around data about the + imports and functions. + +- _BuildStorage - Takes the plugin list and uses it to populate the + _FunctionStorage object. + +- _FileBuilder - takes all the storage object and uses it to build the actual + text file that is to be written to disk. + +- _FileWriter - A simple object that takes the file and function location and + writes the rendered functions to disk. + +- FunctionHandler - The main object to interact with to generate a functions + file. +""" + +import os + +from typing import List + +from PyPWA.core.configurator import options +from PyPWA.core.configurator.create_config import _metadata +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class _GetFunctionLocation(object): + + def __init__(self): + self.__function_location = None # type: str + + def process_location(self, configuration_location): + # type: (str) -> None + self.__function_location = "" + file_name = os.path.splitext(configuration_location)[0] + self.__function_location += file_name + ".py" + + @property + def function_location(self): + # type: () -> str + return self.__function_location + + +class _FunctionStorage(object): + + def __init__(self): + self.imports = set() + self.functions = [] + + +class _BuildStorage(object): + + def __init__(self): + self.__storage = _FunctionStorage() + self.__plugin_list = None + + def process_plugin_list(self, plugin_list): + # type: (_metadata.GetPluginList) -> None + self.__plugin_list = plugin_list + self.__process_main() + self.__process_plugins() + + def __process_main(self): + if self.__plugin_list.shell.defined_function: + self.__process_function(self.__plugin_list.shell) + + def __process_plugins(self): + for plugin in self.__plugin_list.plugins: + if plugin.defined_function: + self.__process_function(plugin) + + def __process_function(self, plugin): + # type: (options.Plugin) -> None + self.__add_imports(plugin.defined_function.imports) + self.__add_function(plugin.defined_function.functions) + + def __add_imports(self, imports): + # type: (List[str]) -> None + for the_import in imports: + self.__storage.imports.add(the_import) + + def __add_function(self, functions): + # type: (List[str]) -> None + for the_function in functions: + self.__storage.functions.append(the_function) + + @property + def storage(self): + # type: () -> _FunctionStorage + return self.__storage + + +class _FileBuilder(object): + + def __init__(self): + self.__imports = None # type: List[str] + self.__functions = None # type: List[str] + self.__file = None # type: str + + def build(self, storage): + # type: (_FunctionStorage) -> None + self.__file = "" + self.__process_imports(storage) + self.__process_functions(storage) + self.__render_imports() + self.__render_functions() + + def __process_imports(self, storage): + # type: (_FunctionStorage) -> None + self.__imports = sorted(storage.imports) + + def __process_functions(self, storage): + # type: (_FunctionStorage) -> None + self.__functions = sorted(storage.functions) + + def __render_imports(self): + for the_import in self.__imports: + self.__file += "import %s\n" % the_import + + def __render_functions(self): + for the_function in self.__functions: + self.__file += "\n" + the_function + self.__file += "\n" + + @property + def functions_file(self): + # type: () -> str + return self.__file + + +class _FileWriter(object): + + @staticmethod + def write_file(file_location, file_data): + # type: (str, str) -> None + with open(file_location, "w") as stream: + stream.write(file_data) + + +class FunctionHandler(object): + + def __init__(self): + self.__file_location = _GetFunctionLocation() + self.__builder = _FileBuilder() + self.__writer = _FileWriter() + self.__storage = _BuildStorage() + + def output_functions(self, plugin_list, configuration_location): + # type: (_metadata.GetPluginList, str) -> None + self.__file_location.process_location(configuration_location) + self.__storage.process_plugin_list(plugin_list) + self.__builder.build(self.__storage.storage) + self.__writer.write_file( + self.__file_location.function_location, + self.__builder.functions_file + ) diff --git a/PyPWA/core/configurator/create_config/_input_loop.py b/PyPWA/core/configurator/create_config/_input_loop.py new file mode 100644 index 00000000..c5501aa7 --- /dev/null +++ b/PyPWA/core/configurator/create_config/_input_loop.py @@ -0,0 +1,208 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Handles all real input for Create Config +---------------------------------------- + +- _Input - Handles differences between Python 2 and 3 + +- _IsCorrectLoop - A simple loop that asks the user if about their input + is fuzzing wasn't good enough. + +- QuestionLoop - The main question loop, handles all input. +""" + +import logging +import sys +from typing import List, Tuple + +import fuzzywuzzy.process + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class _Input(object): + + __VERSION = sys.version_info.major + + @classmethod + def input(cls, string): + # type: (str) -> str + if cls.__VERSION == 2: + return cls.__python_2(string) + else: + return cls.__python_new(string) + + @staticmethod + def __python_2(string): + # type: (str) -> str + return raw_input(string) + + @staticmethod + def __python_new(string): + # type: (str) -> str + return input(string) + + +class _IsCorrectLoop(object): + + __LOGGER = logging.getLogger(__name__ + "._IsCorrectLoop") + __AUTO_CORRECT_PERCENTAGE = 90 + + def __init__(self): + self.__input_data = None # type: str + self.__processed_answer = None # type: Tuple[str, int] + + def ask(self, value): + # type: (str) -> bool + self.__question_loop(value) + return self.__process_final_answer() + + def __question_loop(self, value): + # type: (str) -> None + while True: + self.__get_answer(value) + + if self.__input_data == "": + self.__assume_answer_is_correct() + break + + self.__fuzz_value() + if self.__answer_is_valid(): + break + + def __get_answer(self, value): + # type: (str) -> None + input_data = _Input.input( + "It looks like you selected '%s', is this correct?\n" + "[Y]es/No: " % value + ) + self.__input_data = input_data.lower() + + def __assume_answer_is_correct(self): + self.__processed_answer = ["yes", 100] + + def __fuzz_value(self): + choices = ["yes", "no"] + + self.__processed_answer = fuzzywuzzy.process.extractOne( + self.__input_data, choices + ) + + def __answer_is_valid(self): + # type: () -> bool + if self.__processed_answer[1] > self.__AUTO_CORRECT_PERCENTAGE: + return True + else: + return False + + def __process_final_answer(self): + # type: () -> bool + if self.__processed_answer[0] == "yes": + return True + elif self.__processed_answer[0] == "no": + return False + + +class QuestionLoop(object): + + __LOGGER = logging.getLogger(__name__ + ".QuestionLoop") + + def __init__(self): + self.__is_correct = _IsCorrectLoop() + self.__users_input = None # type: str + self.__processed_value = None # type: Tuple[str, int] + + self._auto_correction_percentage = 75 + self._question = None # type: str + self._possible_answers = False # type: List[str] + self._default_answer = False # type: str + + def _question_loop(self): + self.__log_initial_data() + + while True: + self.__get_input(self._question) + + if self.__users_input is "": + if self._default_answer: + self.__set_processed_value_to_default_answer() + break + continue + + else: + if self._possible_answers: + self.__process_input_using_known_values() + + if self.__answer_is_valid(): + break + else: + self.__set_processed_value_to_user_input() + break + + def __log_initial_data(self): + self.__LOGGER.debug("Question: %s" % self._question) + + if self._possible_answers: + self.__LOGGER.debug( + "Potential Answers: %s" % self._possible_answers + ) + else: + self.__LOGGER.debug("No potential answers provided") + + if self._default_answer: + self.__LOGGER.debug("Default Answer: %s" % self._default_answer) + else: + self.__LOGGER.debug("No default answer set.") + + def __get_input(self, string): + # type: (str) -> None + self.__users_input = _Input.input(string) + + def __set_processed_value_to_default_answer(self): + self.__processed_value = [self._default_answer, 100] + self.__LOGGER.info("Using default answer: %s" % self._default_answer) + + def __process_input_using_known_values(self): + self.__processed_value = fuzzywuzzy.process.extractOne( + self.__users_input, self._possible_answers + ) + + def __answer_is_valid(self): + # type: () -> bool + if self.__processed_value[1] > self._auto_correction_percentage: + if self.__processed_value[1] < 95: + return self.__is_correct.ask(self.__processed_value[0]) + else: + return True + else: + return False + + def __set_processed_value_to_user_input(self): + self.__processed_value = [self.__users_input, 100] + self.__LOGGER.info("Setting answer to %s" % self.__users_input) + + @property + def _answer(self): + # type: () -> str + return self.__processed_value[0] diff --git a/PyPWA/core/configurator/create_config/_level_processing.py b/PyPWA/core/configurator/create_config/_level_processing.py new file mode 100644 index 00000000..f98b2158 --- /dev/null +++ b/PyPWA/core/configurator/create_config/_level_processing.py @@ -0,0 +1,137 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Difficulty Processing for Configuration Creation +------------------------------------------------ +These objects take the plugin's metadata and produces a template configuration +that can be used for output. + +- _FullOptions - Renders the entire template configuration for ProcessOptions + +- ProcessOptions - Takes the metadata from a plugin and the selected + difficulty, then parses that into a usable ruamel.yaml object that can be + loaded into a template configuration file. +""" + +import logging +from typing import List + +from ruamel.yaml import comments + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import options + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class _FullOptions(object): + + __LOGGER = logging.getLogger(__name__ + ".FullOptions") + + def __init__(self, options_object): + # type: (options.Base) -> None + self.__options = options_object + self.__built_options = None # type: comments.CommentedMap + self.__build_options() + + def __build_options(self): + self.__set_header_into_built_options() + self.__set_content_into_built_options() + self.__LOGGER.info( + "Built the options for %s" % self.__options.plugin_name + ) + + def __set_header_into_built_options(self): + header = comments.CommentedMap() + header.yaml_add_eol_comment( + self.__options.module_comment, self.__options.plugin_name + ) + self.__built_options = header + + def __set_content_into_built_options(self): + content = comments.CommentedMap() + populated_content = self.__add_default_options(content) + commented_content = self.__add_option_comments(populated_content) + self.__built_options[self.__options.plugin_name] = commented_content + + def __add_default_options(self, content): + # type: (comments.CommentedMap) -> comments.CommentedMap + for option, value in self.__options.default_options.items(): + content[option] = value + return content + + def __add_option_comments(self, content): + # type: (comments.CommentedMap) -> comments.CommentedMap + for option, comment in self.__options.option_comments.items(): + content.yaml_add_eol_comment(comment, option) + return content + + @property + def plugin_options(self): + # type: () -> comments.CommentedMap + return self.__built_options + + @property + def name(self): + # type: () -> str + return self.__options.plugin_name + + @property + def difficulties(self): + # type: () -> List[options.Types] + return self.__options.option_difficulties.items() + + +class ProcessOptions(object): + + def __init__(self): + self.__rejection_list = None # type: list + self.__full_options = None # type: _FullOptions + self.__processed_options = None # type: comments.CommentedMap + + def processed_options(self, options_object, requested_difficulty): + # type: (options.Base, options.Levels) -> comments.CommentedMap + self.__full_options = _FullOptions(options_object) + self.__processed_options = self.__full_options.plugin_options + self.__set_difficulty_rejection_list(requested_difficulty) + self.__remove_difficulties() + return self.__processed_options + + def __set_difficulty_rejection_list(self, requested_difficulty): + # type: (options.Levels) -> None + if requested_difficulty == options.Levels.REQUIRED: + self.__rejection_list = [ + options.Levels.OPTIONAL, + options.Levels.ADVANCED + ] + elif requested_difficulty == options.Levels.OPTIONAL: + self.__rejection_list = [options.Levels.ADVANCED] + elif requested_difficulty == options.Levels.ADVANCED: + self.__rejection_list = [] + else: + raise ValueError( + "Unknown difficulty: %s" % repr(requested_difficulty) + ) + + def __remove_difficulties(self): + for option, difficulty in self.__full_options.difficulties: + if difficulty in self.__rejection_list: + self.__processed_options[self.__full_options.name].pop(option) diff --git a/PyPWA/core/configurator/create_config/_metadata.py b/PyPWA/core/configurator/create_config/_metadata.py new file mode 100644 index 00000000..729bba15 --- /dev/null +++ b/PyPWA/core/configurator/create_config/_metadata.py @@ -0,0 +1,138 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Handles direct interaction with plugins +--------------------------------------- + +- MetadataStorage - Interacts directly with the plugins. +- GetPluginList - Stores the dependency plugins for the configuration. +""" + +import logging + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import options +from PyPWA.core.configurator import storage +from PyPWA.core.configurator.create_config import _questions +from typing import Any, Dict, Union, List + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + +__STORAGE_TYPE = Dict[Union[str, options.Types], Any] + + +class MetadataStorage(storage.Storage): + + __LOGGER = logging.getLogger(__name__) + + def __init__(self): + super(MetadataStorage, self).__init__() + self.__actual_storage = None # type: __STORAGE_TYPE + self._update_extra() + + def _update_extra(self): + self.__actual_storage = {} + for plugin in self._get_plugins(): + self.__add_type(plugin) + self.__append_plugin(plugin) + + def __add_type(self, plugin): + # type: (options.Plugin) -> None + if plugin.provides not in self.__actual_storage: + self.__actual_storage[plugin.provides] = [] + + def __append_plugin(self, plugin): + # type: (options.Plugin) -> None + self.__actual_storage[plugin.provides].append(plugin) + + def search_plugin(self, plugin_name, plugin_type): + # type: (str, options.Types) -> options.Plugin + if plugin_type in self.__actual_storage: + return self.__plugin_name_search(plugin_name, plugin_type) + else: + self.__cant_find_plugin(plugin_name) + + def __plugin_name_search(self, plugin_name, plugin_type): + # type: (str, options.Types) -> options.Plugin + for plugin in self.__actual_storage[plugin_type]: + if plugin.plugin_name == plugin_name: + return plugin + self.__cant_find_plugin(plugin_name) + + @staticmethod + def __cant_find_plugin(plugin_name): + # type: (str) -> None + error = "Failed to find plugin {0}".format(plugin_name) + raise ValueError(error) + + def request_plugins_by_type(self, plugin_type): + # type: (options.Types) -> List[options.Plugin] + if plugin_type in self.__actual_storage: + return self.__actual_storage[plugin_type] + else: + raise ValueError("Unknown plugin type: %s!" % plugin_type) + + def request_main_plugin_by_name(self, name): + # type: (str) -> options.Plugin + for plugin in self._get_shells(): + if plugin.plugin_name == name: + return plugin + raise ValueError("Unknown shell name '%s'" % name) + + +class GetPluginList(object): + + __LOGGER = logging.getLogger(__name__) + + def __init__(self): + self.__ask_for_plugin = _questions.GetSpecificPlugin() + self.__storage = MetadataStorage() + self.__plugin_list = [] # type: List[options.Plugin] + self.__main_plugin = None # type: options.Main + + def parse_plugins(self, main_plugin): + # type: (options.Main) -> None + for plugin_type in options.Types: + if plugin_type in main_plugin.required_plugins: + self.__plugin_list.append(self.__process_plugins(plugin_type)) + self.__main_plugin = main_plugin + + def __process_plugins(self, plugin_type): + # type: (options.Types) -> options.Plugin + plugin_list = self.__storage.request_plugins_by_type(plugin_type) + if len(plugin_list) == 1: + return plugin_list[0] + else: + self.__ask_for_plugin.ask_for_plugin(plugin_list, plugin_type) + name = self.__ask_for_plugin.get_specific_plugin() + + the_chosen_one = self.__storage.search_plugin(name, plugin_type) + return the_chosen_one + + @property + def plugins(self): + # type: () -> List[options.Plugin] + return self.__plugin_list + + @property + def shell(self): # needed so that BuildConfig can know the shell plugin + # type: () -> options.Main + return self.__main_plugin diff --git a/PyPWA/core/configurator/create_config/_override.py b/PyPWA/core/configurator/create_config/_override.py new file mode 100644 index 00000000..6cbe0494 --- /dev/null +++ b/PyPWA/core/configurator/create_config/_override.py @@ -0,0 +1,159 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Handles all setting overrides +----------------------------- + +- _ExternalizeName - Swaps the internal name for the shell plugin for the + external name + +- RemovePredefinedOptions - Takes any options that are defined in the entries + and removes them from the configuration. + +- Override - The main override object. +""" + +import logging +from typing import Any, Dict + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class _ExternalizeName(object): + + __LOGGER = logging.getLogger(__name__ + "._ExternalizeName") + + def __init__(self): + self.__configuration = None # type: Dict[str, Any] + self.__internal_name = None # type: str + self.__external_name = None # type: str + + def override(self, configuration, override): + # type: (Dict[str, Any], Dict[str, Any]) -> None + self.__set_configuration(configuration) + self.__find_names(override) + self.__externalize_shell_name() + self.__remove_old_name() + + def __set_configuration(self, configuration): + # type: (Dict[str, Any]) -> None + self.__configuration = None + self.__configuration = configuration + + def __find_names(self, override): + # type: (Dict[str, Any]) -> None + self.__internal_name = override["main"] + self.__external_name = override["main name"] + + def __externalize_shell_name(self): + self.__LOGGER.debug("Converting '%s'to '%s'" % ( + self.__internal_name, self.__external_name + )) + shell_options = self.__configuration[self.__internal_name] + self.__configuration[self.__external_name] = shell_options + + def __remove_old_name(self): + self.__configuration.pop(self.__internal_name) + + @property + def configuration(self): + # type: () -> Dict[str, Any] + return self.__configuration + + +class _RemovePredefinedOptions(object): + + __LOGGER = logging.getLogger(__name__ + "._RemovePredefinedOptions") + + def __init__(self): + self.__configuration = None # type: Dict[str, Any] + self.__predefined_options = None # type: Dict[str, Any] + self.__name = None # type: str + + def override(self, configuration, override): + # type: (Dict[str, Any], Dict[str, Any]) -> None + self.__set_configuration(configuration) + self.__setup_override(override) + self.__process_options() + + def __set_configuration(self, configuration): + # type: (Dict[str, Any]) -> None + self.__configuration = configuration + + def __setup_override(self, override): + # type: (Dict[str, Any]) -> None + if "main options" in override: + self.__LOGGER.debug("Removing override options.") + self.__predefined_options = override["main options"] + self.__name = override["main name"] + else: + self.__predefined_options = None + self.__LOGGER.debug("No options to override.") + + def __process_options(self): + if self.__predefined_options: + self.__pop_unneeded_options() + + def __pop_unneeded_options(self): + for option in self.__predefined_options: + self.__LOGGER.debug("Removing option '%s'" % option) + self.__configuration[self.__name].pop(option) + + @property + def configuration(self): + # type: () -> Dict[str, Any] + return self.__configuration + + +class Override(object): + + def __init__(self): + self.__externalize = _ExternalizeName() + self.__predefined_options = _RemovePredefinedOptions() + self.__override = None # type: Dict[str, Any] + self.__configuration = None # type: Dict[str, Any] + + def execute(self, configuration, override): + # type: (Dict[str, Any], Dict[str, Any]) -> None + self.__override = override + self.__configuration = configuration + self.__start_processing() + + def __start_processing(self): + self.__externalize_shell_name() + self.__remove_predefined_options() + + def __externalize_shell_name(self): + self.__externalize.override(self.__configuration, self.__override) + self.__configuration = self.__externalize.configuration + + def __remove_predefined_options(self): + self.__predefined_options.override( + self.__configuration, self.__override + ) + self.__configuration = self.__predefined_options.configuration + + @property + def processed_configuration(self): + # type: () -> Dict[str, Any] + return self.__configuration diff --git a/PyPWA/core/configurator/create_config/_questions.py b/PyPWA/core/configurator/create_config/_questions.py new file mode 100644 index 00000000..86376097 --- /dev/null +++ b/PyPWA/core/configurator/create_config/_questions.py @@ -0,0 +1,159 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +All questions that can be asked, ever. +-------------------------------------- + +- GetPluginLevel - Asks the user for the preferred difficulty. + +- GetPluginDirectory - Asks the user if they have any extra plugins they would + like to add. + +- GetSaveLocation - Asks the user for a save file location if one hasn't + already been provided. + +- GetSpecificPlugin - Asks the user to select a plugin when there are multiple + plugins that can fill the same dependency. +""" + +from typing import List +from typing import Optional as Opt + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import option_tools +from PyPWA.core.configurator import options +from PyPWA.core.configurator.create_config import _input_loop + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class GetPluginLevel(_input_loop.QuestionLoop): + + def __init__(self): + super(GetPluginLevel, self).__init__() + self._default_answer = "optional" + self._possible_answers = ["required", "optional", "advanced"] + self._question = """ +How much control would you like to have over the configuration? +required +optional (default, recommended) +advanced + +[optional]: """ + + def ask_for_plugin_level(self): + self._question_loop() + + def get_plugin_level(self): + # type: () -> options.Levels + if self._answer is "required": + return options.Levels.REQUIRED + elif self._answer is "optional": + return options.Levels.OPTIONAL + elif self._answer is "advanced": + return options.Levels.ADVANCED + else: + raise ValueError("Unknown answer '%s'" % self._answer) + + +class GetPluginDirectory(_input_loop.QuestionLoop): + + def __init__(self): + super(GetPluginDirectory, self).__init__() + self._default_answer = "None" + self._question = """ +Would you like to use your own plugins? If so enter the path to your plugins +[None]: """ + + def ask_for_plugin_directory(self): + self._question_loop() + + def get_plugin_directory(self): + # type: () -> Opt[str] + if self._answer is "None": + return None + else: + return self._answer + + +class GetSaveLocation(_input_loop.QuestionLoop): + + def __init__(self): + super(GetSaveLocation, self).__init__() + self.__override = None + self._question = """ +What would you like to name the configuration file? +File Name?: """ + + def ask_for_save_location(self): + self._question_loop() + + def override_save_location(self, save_location): + # type: (str) -> None + self.__override = save_location + + def get_save_location(self): + # type: () -> str + if self.__override: + return self.__override + else: + return self._answer + + +class GetSpecificPlugin(_input_loop.QuestionLoop): + + def __init__(self): + super(GetSpecificPlugin, self).__init__() + self.__name_conversion = option_tools.PluginNameConversion() + + def ask_for_plugin(self, plugin_list, plugin_type): + # type: (List[options.Plugin], options.Types) -> None + self.__set_possible_answers(plugin_list) + self.__create_question(plugin_type) + self._question_loop() + + def __set_possible_answers(self, plugin_list): + # type: (List[options.Plugin]) -> None + self._possible_answers = [] + for plugin in plugin_list: + self._possible_answers.append(plugin.plugin_name) + + def __create_question(self, plugin_type): + # type: (options.Types) -> None + self._question = self.__make_base_string(plugin_type) + self._question += self.__make_name_list_string() + self._question += "\nPlugin?: " + + def __make_base_string(self, plugin_type): + # type: (options.Types) -> str + clean_type = self.__name_conversion.internal_to_external(plugin_type) + return "Which plugin would you like to use for '%s'?" % clean_type + + def __make_name_list_string(self): + # type: () -> None + name_string = "" + for name in self._possible_answers: + name_string += "\n%s" % name + return name_string + + def get_specific_plugin(self): + # type: () -> str + return self._answer diff --git a/PyPWA/core/configurator/create_config/_writer.py b/PyPWA/core/configurator/create_config/_writer.py new file mode 100644 index 00000000..64dc293d --- /dev/null +++ b/PyPWA/core/configurator/create_config/_writer.py @@ -0,0 +1,87 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Simple writers to export configurations. +---------------------------------------- + +- _YmlWriter - Exports configurations using ruamel.yaml, this is default, and + is the only way to get comments. + +- _JsonWriter - Exports configurations using json for masochists who prefer + it, does not support comments. + +- Write - Simple wrapping main object around the two defined writers. +""" + +import json +import os +from typing import Any, Dict + +import ruamel.yaml + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class _YmlWriter(object): + + @staticmethod + def write(settings, location): + # type: (Dict[str, Any], str) -> None + with open(location, "w") as stream: + stream.write( + ruamel.yaml.dump( + settings, + Dumper=ruamel.yaml.RoundTripDumper + ) + ) + + +class _JsonWriter(object): + + @staticmethod + def write(settings, location): + # type: (Dict[str, Any], str) -> None + with open(location, "w") as stream: + stream.write(json.dumps(settings, indent=4)) + + +class Write(object): + + def __init__(self): + self.__json = _JsonWriter() + self.__yml = _YmlWriter() + + def write(self, settings, location): + # type: (Dict[str, Any], str) -> None + if self.__is_json(location): + self.__json.write(settings, location) + else: + self.__yml.write(settings, location) + + @staticmethod + def __is_json(location): + # type: (str) -> bool + if os.path.splitext(location)[1] == ".json": + return True + else: + return False diff --git a/PyPWA/core/configurator/create_config/create.py b/PyPWA/core/configurator/create_config/create.py new file mode 100644 index 00000000..6e900947 --- /dev/null +++ b/PyPWA/core/configurator/create_config/create.py @@ -0,0 +1,99 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Creates the template configuration file when --WriteConfig is passed +""" + +from typing import Any, Dict + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator.create_config import _builder +from PyPWA.core.configurator.create_config import _function_builder +from PyPWA.core.configurator.create_config import _metadata +from PyPWA.core.configurator.create_config import _questions +from PyPWA.core.configurator.create_config import _writer + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class StartConfig(object): + + def __init__(self): + self.__writer = _writer.Write() + self.__functions = _function_builder.FunctionHandler() + self.__storage = _metadata.MetadataStorage() + self.__plugin_dir = _questions.GetPluginDirectory() + self.__level = _questions.GetPluginLevel() + self.__save_location = _questions.GetSaveLocation() + self.__plugin_list = _metadata.GetPluginList() + self.__configuration = _builder.BuildConfig( + self.__plugin_dir, self.__plugin_list, self.__level + ) + self.__main_plugin = None + + def make_config(self, function_settings, config_location): + # type: (Dict[str, Any], str) -> None + self.__fetch_main_plugin(function_settings) + self.__get_plugin_directories() + self.__set_level() + self.__set_plugin_list() + self.__create_configuration(function_settings) + self.__set_save_location(config_location) + self.__save_configuration() + self.__save_functions() + + def __fetch_main_plugin(self, function_settings): + # type: (Dict[str, Any]) -> None + self.__main_plugin = self.__storage.request_main_plugin_by_name( + function_settings["main"] + ) + + def __get_plugin_directories(self): + self.__plugin_dir.ask_for_plugin_directory() + self.__storage.add_location(self.__plugin_dir.get_plugin_directory()) + + def __set_level(self): + self.__level.ask_for_plugin_level() + + def __set_plugin_list(self): + self.__plugin_list.parse_plugins(self.__main_plugin) + + def __create_configuration(self, function_settings): + # type: (Dict[str, Any]) -> None + self.__configuration.build(function_settings) + + def __set_save_location(self, save_location): + # type: (str) -> None + if save_location: + self.__save_location.override_save_location(save_location) + else: + self.__save_location.ask_for_save_location() + + def __save_configuration(self): + self.__writer.write( + self.__configuration.configuration, + self.__save_location.get_save_location() + ) + + def __save_functions(self): + self.__functions.output_functions( + self.__plugin_list, self.__save_location.get_save_location() + ) diff --git a/PyPWA/core/configurator/execute/__init__.py b/PyPWA/core/configurator/execute/__init__.py new file mode 100644 index 00000000..4a893589 --- /dev/null +++ b/PyPWA/core/configurator/execute/__init__.py @@ -0,0 +1,48 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Where the program starts. +------------------------- +This module takes the written configuration file along with some information +from the entry point and tries to use that attempt to load the plugins and +start the program. + +- _correct_configuration - Corrects the parsed configuration file using the + rendered template dict from all the known plugins. + +- _plugin_data - Contains the logic pertaining to loading the plugins listed + in the user's config file and initializing it with the users settings + +- _reader - Loads the different types of supported configuration files. + +- _settings - Processes the overrides,appends the plugin directory to the + plugin search path, then corrects the received values + using _correct_configuration. + +- _storage_data - contains the objects that operate directly with the loaded + plugins. + +- start - Where the main source of execution occurs for the program. +""" + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION diff --git a/PyPWA/core/configurator/execute/_correct_configuration.py b/PyPWA/core/configurator/execute/_correct_configuration.py new file mode 100644 index 00000000..1f40fea6 --- /dev/null +++ b/PyPWA/core/configurator/execute/_correct_configuration.py @@ -0,0 +1,262 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Attempts to correct the received settings if possible. +------------------------------------------------------ + +- _CorrectKeys - Iterates through all keys and sub-dictionaries of a + dictionary and then tries to correct the key names if possible. + +- _CorrectValues - Attempts to correct the value of each key inside the + dictionary if possible. + +- SettingsAid - Takes the template dictionary and the received dictionary + and attempts to correct all of the values. +""" + +import logging +from typing import Any, Dict, List, Union, Tuple + +import fuzzywuzzy.process +import numpy + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator.execute import _storage_data + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +FUZZY_STRING_CONFIDENCE_LEVEL = 75 + + +class _CorrectKeys(object): + + __LOGGER = logging.getLogger(__name__ + "._CorrectKeys") + + def __init__(self, template, depth=0): + # type: (Dict[str, Any], int) -> None + self.__depth = depth + self.__template = template + self.__LOGGER.debug("Received template: %s" % template) + self.__initial_settings = None # type: Dict[str, Any] + self.__corrected_keys = None # type: Dict[str, Any] + self.__set_keys() + + def __set_keys(self): + self.__keys = list(self.__template.keys()) + + def correct_keys(self, dictionary): + # type: (Dict[str, Any]) -> Dict[str, Any] + self.__empty_corrected() + self.__set_initial_settings(dictionary) + self.__loop_over_keys() + return self.__corrected_keys + + def __empty_corrected(self): + self.__corrected_keys = {} + + def __set_initial_settings(self, settings): + # type: (Dict[str, Any]) -> None + self.__initial_settings = settings + + def __loop_over_keys(self): + for key in self.__initial_settings.keys(): + found = self.__get_potential_key(key) + if found: + self.__set_corrected_key(found, key) + else: + self.__handle_key_error(key) + self.__check_for_dictionary(found) + + def __get_potential_key(self, key): + # type: (str) -> str + found_key = self.__fuzz_key(key) + if found_key[1] >= FUZZY_STRING_CONFIDENCE_LEVEL: + return found_key[0] + + def __fuzz_key(self, key): + # type: (str) -> Tuple(str, int) + found_key = fuzzywuzzy.process.extractOne(key, self.__keys) + return found_key + + def __set_corrected_key(self, found, key): + # type: (str, str) -> None + self.__corrected_keys[found] = self.__initial_settings[key] + + def __check_for_dictionary(self, found): + # type: (str) -> None + if isinstance(self.__template[found], dict): + self.__LOGGER.debug( + "Correcting internal dictionary: %s" % self.__template[found] + ) + self.__correct_nested_dictionary(found) + + def __correct_nested_dictionary(self, found): + # type: (str) -> None + correction = _CorrectKeys(self.__template[found], self.__depth + 1) + corrected = correction.correct_keys(self.__corrected_keys[found]) + self.__corrected_keys[found] = corrected + + def __handle_key_error(self, key): + # type: (str) -> None + if self.__depth: + raise ValueError( + "Root level key error! Unknown Plugin '%s'!" % key + ) + else: + self.__LOGGER.warning( + "Unknown key '%s', value is being removed!" % key + ) + + +class _CorrectValues(object): + + __LOGGER = logging.getLogger(__name__ + "._CorrectValues") + __FAILED = "failed to find" + + def correct_all(self, dictionary, template_dictionary): + # type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any] + corrected_dictionary = {} + for key in dictionary.keys(): + template_value = template_dictionary[key] + current_value = dictionary[key] + + if isinstance(current_value, type(None)): + corrected_dictionary[key] = None + + elif template_value == int: + corrected_dictionary[key] = self.__correct_integers( + current_value + ) + + elif template_value == float: + corrected_dictionary[key] = self.__correct_floats( + current_value + ) + + elif template_value == bool: + corrected_dictionary[key] = self.__correct_boolean_values( + current_value + ) + + elif template_value == str: + corrected_dictionary[key] = str(current_value) + + elif template_value == list: + corrected_dictionary[key] = list(current_value) + + elif template_value == set: + corrected_dictionary[key] = set(current_value) + + elif isinstance(template_value, list): + corrected_dictionary[key] = self.__correct_from_list( + current_value, template_value + ) + + elif isinstance(template_value, dict): + corrected_dictionary[key] = self.correct_all( + current_value, template_value + ) + + else: + self.__LOGGER.debug( + "Key '%s' is not correctable by settings aid because " + "its expected value is not known." % key + ) + + corrected_dictionary[key] = current_value + + return corrected_dictionary + + def __correct_from_list(self, string, value_list): + # type: (str, List[str]) -> str + value = fuzzywuzzy.process.extractOne(string, value_list) + + if value[1] >= FUZZY_STRING_CONFIDENCE_LEVEL: + return value[0] + else: + return self.__FAILED + + def __correct_boolean_values(self, value): + # type: (Any) -> Union[bool, str] + try: + exact = int(value) + if exact: + return True + else: + return False + except ValueError: + pass + + value = fuzzywuzzy.process.extractOne(value, ["true", "false"]) + if value[1] >= FUZZY_STRING_CONFIDENCE_LEVEL: + if value[0] == "true": + return True + elif value[0] == "false": + return False + else: + return self.__FAILED + else: + return self.__FAILED + + def __correct_integers(self, value): + # type: (Any) -> Union[int, str] + try: + return int(value) + except ValueError: + return self.__FAILED + + def __correct_floats(self, value): + # type: (Any) -> Union[numpy.float64, str] + try: + return numpy.float64(value) + except ValueError: + return self.__FAILED + + +class SettingsAid(object): + + __LOGGER = logging.getLogger(__name__ + ".SettingsAid") + + def __init__(self): + self.__template = _storage_data.Templates() + self.__key_corrector = _CorrectKeys(self.__template.get_templates()) + self.__correct_values = _CorrectValues() + self.__settings = None + + def correct_settings(self, value): + # type: (Dict[str, Any]) -> None + self.__set_settings(value) + self.__correct_keys() + self.__correct_all() + return self.__settings + + def __set_settings(self, values): + # type: (Dict[str, Any]) -> None + self.__settings = values + + def __correct_keys(self): + self.__settings = self.__key_corrector.correct_keys(self.__settings) + + def __correct_all(self): + self.__settings = self.__correct_values.correct_all( + self.__settings, self.__template.get_templates() + ) diff --git a/PyPWA/core/configurator/execute/_plugin_data.py b/PyPWA/core/configurator/execute/_plugin_data.py new file mode 100644 index 00000000..1c6b8252 --- /dev/null +++ b/PyPWA/core/configurator/execute/_plugin_data.py @@ -0,0 +1,231 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Plugin Setup +------------ +This source file is file that initializes the plugins for use in the main +program. + +- _RequestedPlugins - Takes the ids from the settings and uses it to grab the + metadata for all the plugins listed in the configuration file, plugins + are loaded into loaded_plugin_metadata and the main is loaded + into loaded_main_metadata. + +- _InitializePlugin - Takes the settings and metadata for a plugin and uses + it to load and extract the actual executed plugin. + +- _SetupPlugins - Contains the main loop needed to initialize all the plugins, + loads the plugins into a dictionary where the key is the plugin type, and + exposes that dictionary through loaded_plugins. + +- _SetupMain - Takes all of the objects and uses them to load the plugin data + into the settings for the main, then initializes the main and exposes that + through main_program. + +- SetupProgram - Takes the settings object and uses that to initialize all of + the plugins. Exposes execute to begin the main program. +""" + +import logging +from typing import Any, Dict, List +from typing import Optional as Opt + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import option_tools +from PyPWA.core.configurator import options as opts +from PyPWA.core.configurator.execute import _settings +from PyPWA.core.configurator.execute import _storage_data +from PyPWA.core.shared.interfaces import plugins + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class _RequestedPlugins(object): + + __LOGGER = logging.getLogger(__name__ + "._RequestedPlugins") + + def __init__(self, the_ids): + # type: (List[str]) -> None + self.__storage = _storage_data.ModulePicking() + self.__the_ids = the_ids + self.__plugins = [] + self.__main = None # type: opts.Main + self.__find_metadata() + + def __find_metadata(self): + for the_id in self.__the_ids: + self.__LOGGER.debug("Scanning plugins for '%s'" % the_id) + self.__check_metadata(the_id) + + def __check_metadata(self, the_id): + # type: (str) -> None + potential_main, potential_plugin = self.__get_potential(the_id) + self.__process_potential(potential_main, potential_plugin, the_id) + + def __get_potential(self, the_id): + # type: (str) -> List[Opt[opts.Main], Opt[opts.Plugin]] + potential_main = self.__storage.request_main_by_id(the_id) + potential_plugin = self.__storage.request_plugin_by_name(the_id) + + return [potential_main, potential_plugin] + + def __process_potential(self, potential_main, potential_plugin, the_id): + # type: (Opt[opts.Main], Opt[opts.Plugin], str) -> None + if potential_main: + self.__LOGGER.debug( + "Found that '%s' is the main" % potential_main.plugin_name + ) + self.__main = potential_main + elif potential_plugin: + self.__LOGGER.debug( + "Found that '%s' is a plugin" % potential_plugin.plugin_name + ) + self.__plugins.append(potential_plugin) + else: + raise ValueError("Unknown plugin %s" % the_id) + + @property + def loaded_plugin_metadata(self): + # type: () -> List[opts.Plugin] + return self.__plugins + + @property + def loaded_main_metadata(self): + # type: () -> opts.Main + return self.__main + + +class _InitializePlugin(object): + + __LOGGER = logging.getLogger(__name__ + "._InitializePlugin") + + @classmethod + def initialize(cls, metadata, settings): + # type: (opts.Base, Dict[str, Any]) -> Any + cls.__LOGGER.debug("Initializing '%s'" % metadata.plugin_name) + command = cls.__get_command_object(metadata, settings) + return cls.__get_interface(metadata, command) + + @staticmethod + def __get_command_object(metadata, settings): + # type: (opts.Base, Dict[str, Any]) -> option_tools.CommandOptions + default = metadata.default_options + loaded_settings = settings[metadata.plugin_name] + return option_tools.CommandOptions(default, loaded_settings) + + @staticmethod + def __get_interface(metadata, command): + # type: (opts.Base, option_tools.CommandOptions) -> Any + setup = metadata.setup(command) + return setup.return_interface() + + +class _SetupPlugins(object): + + __LOGGER = logging.getLogger(__name__ + "_SetupPlugins") + + def __init__(self, settings, loaded_modules): + # type: (Dict[str, Any], _RequestedPlugins) -> None + self.__settings = settings + self.__selected_modules = loaded_modules + self.__plugins = {} + self.__setup_plugins() + + def __setup_plugins(self): + self.__LOGGER.info("Initializing plugins.") + for metadata in self.__selected_modules.loaded_plugin_metadata: + self.__LOGGER.debug("Plugin Type: '%s'" % repr(metadata)) + self.__process_plugin(metadata) + + def __process_plugin(self, metadata): + # type: (opts.Plugin) -> None + plugin = _InitializePlugin.initialize(metadata, self.__settings) + self.__plugins[metadata.provides.name] = plugin + + @property + def loaded_plugins(self): + # type: () -> Dict[str, opts.Plugin] + return self.__plugins + + +class _SetupMain(object): + + __LOGGER = logging.getLogger(__name__ + "_SetupMain") + + def __init__(self, settings, loaded_modules, loaded_plugins): + # type: (Dict[str, Any], _RequestedPlugins, _SetupPlugins) -> None + self.__settings = settings + self.__selected_modules = loaded_modules + self.__plugins = loaded_plugins + self.__name = loaded_modules.loaded_main_metadata.plugin_name + self.__main = None # type: plugins.Main + self.__setup_main() + + def __setup_main(self): + self.__add_plugins_to_settings() + self.__main = _InitializePlugin.initialize( + self.__selected_modules.loaded_main_metadata, self.__settings + ) + + def __add_plugins_to_settings(self): + for key, value in self.__plugins.loaded_plugins.items(): + self.__LOGGER.debug("Adding '%s' to main's settings" % key) + self.__settings[self.__name][key] = value + + @property + def main_program(self): + # type: () -> plugins.Main + return self.__main + + +class SetupProgram(object): + + def __init__(self, settings_setup): + # type: (_settings.Setup) -> None + self.__settings_setup = settings_setup # type: _settings.Setup + self.__selected_plugins = None # type: _RequestedPlugins + self.__plugins = None # type: _SetupPlugins + self.__main = None # type: _SetupMain + + def setup(self): + self.__determine_plugins() + self.__load_plugins() + self.__load_main() + + def __determine_plugins(self): + self.__selected_plugins = _RequestedPlugins( + self.__settings_setup.plugin_ids + ) + + def __load_plugins(self): + self.__plugins = _SetupPlugins( + self.__settings_setup.loaded_settings, self.__selected_plugins + ) + + def __load_main(self): + self.__main = _SetupMain( + self.__settings_setup.loaded_settings, + self.__selected_plugins, self.__plugins + ) + + def execute(self): + program = self.__main.main_program + program.start() diff --git a/PyPWA/core/configurator/execute/_reader.py b/PyPWA/core/configurator/execute/_reader.py new file mode 100644 index 00000000..0e2ce782 --- /dev/null +++ b/PyPWA/core/configurator/execute/_reader.py @@ -0,0 +1,109 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Loads in the users configuration files. +--------------------------------------- +- _ReadData - Abstract class used to define the config parsers +- _ReadYml - Loads the Yaml configuration files. +- _ReadJson - Loads the Json configuration files. +- ConfigurationLoader - Main object to call for loading configuration, + defaults to Yml unless files extension is json. +""" + +import json +import logging +import os +import io + +from typing import Any, Dict + +import ruamel.yaml + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class _ReadData(object): + + __LOGGER = logging.getLogger(__name__ + "._ReadData") + + def read(self, configuration): + # type: (str) -> Dict[str, Any] + with io.open(configuration, "r") as stream: + data = self._process_stream(stream) + self.__LOGGER.info("Parsed %s" % configuration) + return data + + def _process_stream(self, stream): + # type: (io.TextIOWrapper) -> Dict[str, Any] + raise NotImplementedError + + def _process_error(self, user_error): + # type: (Exception) -> None + self.__LOGGER.exception(user_error) + raise SyntaxError(str(user_error)) + + +class _ReadYml(_ReadData): + + def _process_stream(self, stream): + # type: (io.TextIOWrapper) -> Dict[str, Any] + try: + return self.__load_configuration(stream) + except ruamel.yaml.parser.ParserError as UserError: + self._process_error(UserError) + + @staticmethod + def __load_configuration(stream): + # type: (io.TextIOWrapper) -> Dict[str, Any] + return ruamel.yaml.load(stream, ruamel.yaml.RoundTripLoader) + + +class _ReadJson(_ReadData): + + def _process_stream(self, stream): + # type: (io.TextIOWrapper) -> Dict[str, Any] + try: + return self._load_configuration(stream) + except json.JSONDecodeError as UserError: + self._process_error(UserError) + + @staticmethod + def _load_configuration(stream): + # type: (io.TextIOWrapper) -> Dict[str, Any] + return json.loads(stream) + + +class ConfigurationLoader(object): + + __LOGGER = logging.getLogger(__name__ + ".ConfigurationLoader") + + def __init__(self): + self.__json = _ReadJson() + self.__yml = _ReadYml() + + def read_config(self, configuration): + # type: (str) -> Dict[str, Any] + if os.path.splitext(configuration)[1] is json: + return self.__json.read(configuration) + else: + return self.__yml.read(configuration) diff --git a/PyPWA/core/configurator/execute/_settings.py b/PyPWA/core/configurator/execute/_settings.py new file mode 100644 index 00000000..647d8ffe --- /dev/null +++ b/PyPWA/core/configurator/execute/_settings.py @@ -0,0 +1,165 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +The main file for handing configuration parsing. +------------------------------------------------ +This file contains a collection of objects that load and process the +configuration file into a usable dictionary that can be used to setup the +plugins. This configuration file also goes through a sort of spell check to +ensure that all the keys and values are of the right type for the plugin that +is going to be rendering it. + +.. seealso:: + _correct_configuration.py for the logic regarding setting value + correction. + +- _InternalizeSettings - Takes the settings loaded from the configuration, + and replaces select keys in the configuration with keys from the settings + override in the entry function. Useful so that you can have multiple names + for the same main module. + +- _SetupPluginDir - Static Object that pulls the plugin directory from the + configuration and adds the path to the storage objects plugin search path. + +- Setup - Takes the configuration and override information then parses that + information into a usable configuration dictionary. +""" + +import logging +from typing import Any, Dict, List + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import storage +from PyPWA.core.configurator.execute import _correct_configuration +from PyPWA.core.configurator.execute import _reader + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class _InternalizeSettings(object): + + __LOGGER = logging.getLogger(__name__ + "._InternalizeSettings") + + def __init__(self): + self.__settings = None + self.__overrides = None + + def processed_settings(self, settings, settings_overrides): + # type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any] + self.__settings = settings + self.__overrides = settings_overrides + self.__process() + return self.__settings + + def __process(self): + self.__override_settings() + self.__convert_name() + + def __override_settings(self): + if "main options" in self.__overrides: + self.__process_overrides() + else: + self.__LOGGER.debug("Failed to find main options") + + def __process_overrides(self): + for key in self.__overrides["main options"]: + self.__settings[self.__overrides["main name"]][key] = \ + self.__overrides["main options"][key] + + def __convert_name(self): + self.__settings[self.__overrides["main"]] = \ + self.__settings[self.__overrides["main name"]] + + self.__settings.pop(self.__overrides["main name"]) + + +class _SetupPluginDir(object): + + __LOGGER = logging.getLogger(__name__ + "._SetupPluginDir") + + def __init__(self): + self.__loader = storage.Storage() + + def add_locations_from_settings(self, settings): + # type: (Dict[str, Any]) -> None + try: + location = self.__get_location_from_settings(settings) + self.__add_found_location(location) + except KeyError: + self.__LOGGER.info("No extra plugin directories found.") + + @staticmethod + def __get_location_from_settings(settings): + # type: (Dict[str, Dict[str, str]]) -> str + return settings["Global Options"]["plugin directory"] + + def __add_found_location(self, location): + # type: (str) -> None + self.__loader.add_location(location) + self.__LOGGER.info("Found extra plugin locations %s" % repr(location)) + + +class Setup(object): + + def __init__(self): + self.__settings = None + + def load_settings(self, settings_overrides, configuration_location): + # type: (Dict[str, Any], str) -> None + config = self.__load_config(configuration_location) + internal = self.__internalize_settings(config, settings_overrides) + self.__process_plugin_path(internal) + self.__correct_settings(internal) + + @staticmethod + def __load_config(configuration_location): + # type: (str) -> Dict[str, Any] + loader = _reader.ConfigurationLoader() + return loader.read_config(configuration_location) + + @staticmethod + def __internalize_settings(configuration, settings_overrides): + # type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any] + internalize = _InternalizeSettings() + return internalize.processed_settings( + configuration, settings_overrides + ) + + @staticmethod + def __process_plugin_path(settings): + # type: (Dict[str, Any]) -> None + plugin_dir = _SetupPluginDir() + plugin_dir.add_locations_from_settings(settings) + + def __correct_settings(self, settings): + # type: (Dict[str, Any]) -> None + corrector = _correct_configuration.SettingsAid() + self.__settings = corrector.correct_settings(settings) + + @property + def loaded_settings(self): + # type: () -> Dict[str, Any] + return self.__settings + + @property + def plugin_ids(self): + # type: () -> List[str] + return list(self.__settings.keys()) diff --git a/PyPWA/core/configurator/execute/_storage_data.py b/PyPWA/core/configurator/execute/_storage_data.py new file mode 100644 index 00000000..03ca9011 --- /dev/null +++ b/PyPWA/core/configurator/execute/_storage_data.py @@ -0,0 +1,87 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Execute Tools, general libs needed to build the program. +-------------------------------------------------------- +- ModulePicking - This loads all the plugins, then parses their templates + into one massive template dictionary. + +- Templates - Allows the program to fetch plugins and mains by their + name so that the names inside the configuration file can match up to their + respected plugin. +""" + +import logging + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import storage +from PyPWA.core.configurator import options + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class ModulePicking(storage.Storage): + + def __init__(self): + super(ModulePicking, self).__init__() + + def request_main_by_id(self, the_id): + # type: (str) -> options.Main + for main in self._get_shells(): + if main.plugin_name == the_id: + return main + + def request_plugin_by_name(self, name): + # type: (str) -> options.Plugin + for plugin in self._get_plugins(): + if plugin.plugin_name == name: + return plugin + + +class Templates(storage.Storage): + + __LOGGER = logging.getLogger(__name__ + ".Templates") + + def __init__(self): + super(Templates, self).__init__() + self.__templates = None # type: dict + self._update_extra() + + def _update_extra(self): + self.__templates = {} + self.__process_options() + self.__process_main() + + def __process_options(self): + for plugin in self._get_plugins(): + self.__add_module(plugin) + + def __process_main(self): + for main in self._get_shells(): + self.__add_module(main) + + def __add_module(self, main): + # type: (options.Main) -> None + self.__templates[main.plugin_name] = main.option_types + + def get_templates(self): + self._check_for_updates() + return self.__templates diff --git a/PyPWA/core/configurator/execute/start.py b/PyPWA/core/configurator/execute/start.py new file mode 100644 index 00000000..dd9b6c37 --- /dev/null +++ b/PyPWA/core/configurator/execute/start.py @@ -0,0 +1,61 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Where the program really starts. +-------------------------------- +This is a shell object to connect the two major halves of execute together, +_settings that loads the settings into something usable, and _plugins that +takes those settings to package together a little runnable program. +""" + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator.execute import _plugin_data +from PyPWA.core.configurator.execute import _settings + +from typing import Dict + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class Execute(object): + + def __init__(self): + self.__settings = _settings.Setup() + self.__executor = None # type: _plugin_data.SetupProgram + + def run(self, function_settings, configuration_location): + # type: (Dict[str, str], str) -> None + self.__set_settings(function_settings, configuration_location) + self.__set_executor() + self.__execute() + + def __set_settings(self, function_settings, configuration_location): + # type: (Dict[str, str], str) -> None + self.__settings.load_settings( + function_settings, configuration_location + ) + + def __set_executor(self): + self.__executor = _plugin_data.SetupProgram(self.__settings) + + def __execute(self): + self.__executor.setup() + self.__executor.execute() diff --git a/PyPWA/core/configurator/option_tools.py b/PyPWA/core/configurator/option_tools.py new file mode 100644 index 00000000..6d1cd253 --- /dev/null +++ b/PyPWA/core/configurator/option_tools.py @@ -0,0 +1,97 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +A collection of tools needed to help with options metadata. +----------------------------------------------------------- +The tools here are all simple enough to exist on their own, but all serve +the purpose of helping with options metadata. + +- CommandOptions - The object that is loaded wih values from the + configuration file that is then passed to the plugins setup. + +- PluginsNamesConversion - Since the plugins are defined using an + enumeration, this object takes an enumeration and returns its readable + name, or takes a readable name and returns the enumeration. +""" + +import logging +import re +from typing import Any, Dict + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import options + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class CommandOptions(object): + + __LOGGER = logging.getLogger(__name__ + ".CommandOptions") + + def __init__(self, default_options, loaded_options): + # type: (Dict[str, Any], Dict[str, Any]) -> None + self.__options = [] + self.__set_variables(default_options) + self.__set_variables(loaded_options) + + def __set_variables(self, plugin_options): + # type: (Dict[str, Any]) -> None + for key in list(plugin_options.keys()): + name = self.__find_variable_name(key) + setattr(self, name, plugin_options[key]) + self.__options.append(name) + + def __find_variable_name(self, key): + # type: (str) -> str + underscored_name = key.replace(" ", "_") + lowercase_name = underscored_name.lower() + filtered_name = re.sub(r'[^a-z0-9_]', '', lowercase_name) + self.__LOGGER.debug("Converted {0} to {1}".format(key, filtered_name)) + return filtered_name + + def __getattr__(self, item): + # type: (str) -> None + raise AttributeError( + "No option named '%s', only '%s' have been defined." % + (item, repr(self.__options)) + ) + + +class PluginNameConversion(object): + __NAMES = [ + # Internal name, External Name + [options.Types.DATA_PARSER, "Data Parsing"], + [options.Types.DATA_READER, "Data Iterator"], + [options.Types.KERNEL_PROCESSING, "Kernel Processor"], + [options.Types.OPTIMIZER, "Optimizer"] + ] + + def internal_to_external(self, plugin_type): + # type: (options.Types) -> str + for internal_name, external_name in self.__NAMES: + if internal_name == plugin_type: + return external_name + + def external_to_internal(self, plugin_type): + # type: (str) -> options.Types + for internal_name, external_name in self.__NAMES: + if external_name == plugin_type: + return internal_name diff --git a/PyPWA/core/configurator/options.py b/PyPWA/core/configurator/options.py new file mode 100644 index 00000000..f9a3208d --- /dev/null +++ b/PyPWA/core/configurator/options.py @@ -0,0 +1,125 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Required objects to define a plugin. +------------------------------------ +Here we have all the objects and interfaces that are necessary to define a +plugin to be used with the configurator plugin. + +- Types - Enumeration of the supported plugin types. + - KERNEL_PROCESSING - A plugin that takes a kernel of code with data + then distributes that code and data across nodes. + - OPTIMIZER - Minimizer or Maximizer. + - DATA_READER - this is a plugin that will iterate over events instead of + parsing all the data into the memory. + - DATA_PARSER - this should interact with all data being stored inside the + memory. + - SKIP - Shouldn't be loaded, skipped, used for debug. + +- Levels - Enumeration of the difficulty and necessity of an option. + - Required - An option that has to be given to the plugin, and can not be + calculated in any way from the program. + - Optional - An option that doesn't require a deep understanding of the + plugin in order to utilize, but isn't required to be provided if it can + be calculated otherwise. + - Advanced - An option that can be calculated or determined internally, + and required a deep understanding of the plugin. + +- Setup - This is the object that would be nested inside your root plugin + module. This should take a configuration CommandOptions, and use it to + setup the plugin to be used throughout the program. + .. see also: + PyPWA.core.configuration.option_tools.CommandOptions + +- Base - This is the base object for all plugins and mains, though you + shouldn't use this unless you know what you are doing. Instead you should + use Plugin or Main. + +- Plugin - The interface to define the metadata for Plugins. + +- Main - The interface to define the metadata for mains, this is essentially + the beginning of a program. + +- FileBuilder - This is the object that needs to be extended and filled out + if your plugin needs a function to be defined for it to be usable. +""" + +import enum + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class Types(enum.Enum): + KERNEL_PROCESSING = 1 + OPTIMIZER = 2 + DATA_READER = 3 + DATA_PARSER = 4 + SKIP = 5 + + +class Levels(enum.Enum): + REQUIRED = 1 + OPTIONAL = 2 + ADVANCED = 3 + + +class Setup(object): + + def return_interface(self): + """ + This should return the initialized plugin or main using the + CommandOptions that would be received via the __init__ + + :return: The initialized plugin or main. + """ + raise NotImplementedError + + +class Base(object): + plugin_name = "BASE" + # the options coupled with their default values + default_options = {} + # The options and their Levels. + option_difficulties = {} + # the option and their types. See official documentation. + option_types = {} + module_comment = "BASE" + # A short comment about each option. + option_comments = {} + # The defined functions if needed. + defined_function = None + # The setup object + setup = Setup # type: Setup + + +class Plugin(Base): + provides = Types.SKIP # type: Types + + +class Main(Base): + required_plugins = [] # type: [Types] + + +class FileBuilder(object): + imports = set() + functions = [] diff --git a/PyPWA/core/configurator/start.py b/PyPWA/core/configurator/start.py new file mode 100644 index 00000000..f362ca6d --- /dev/null +++ b/PyPWA/core/configurator/start.py @@ -0,0 +1,227 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Where everything begins. +------------------------ +This is the starting objects for the configurator. This handles initial +output, argument parsing, logging, and the finally depending on the +arguments will start building the configuration, or it will execute the +program. + +- _Arguments - A simple object that parses the arguments for the program, + then exposes those inputs through the properties. + +- StartProgram - This is the object that takes the information from the + entry point along with the data from the _Arguments to determine where + which half of the configuration utility should be started. +""" + +import argparse +import logging +import sys +from typing import Dict + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator.create_config import create +from PyPWA.core.configurator.execute import start +from PyPWA.core.shared import initial_logging + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class _Arguments(object): + + def __init__(self): + self.__parser = None # type: argparse.ArgumentParser + self.__arguments = None # type: argparse.Namespace() + + def parse_arguments(self, description): + # type: (str) -> None + self.__set_arguments(description) + self.__parse_arguments() + self.__quit_if_no_args() + + def __set_arguments(self, description): + # type: (str) -> None + self.__set_parser(description) + self.__add_configurator_argument() + self.__add_write_config_argument() + self.__add_verbose_argument() + self.__add_log_file_argument() + self.__add_version_argument() + + def __set_parser(self, description): + # type: (str) -> None + self.__parser = argparse.ArgumentParser(description=description) + + def __add_configurator_argument(self): + self.__parser.add_argument( + "configuration", type=str, default="", nargs="?" + ) + + def __add_write_config_argument(self): + self.__parser.add_argument( + "--WriteConfig", "-wc", action="store_true", + help="Write an example configuration to the current working " + "directory" + ) + + def __add_verbose_argument(self): + self.__parser.add_argument( + "-v", action="count", default=0, + help="Adds logging, defaults to errors, then setups up on " + "from there. -v will include warning, -vv will show " + "warnings and info, and -vvv will show info, warnings, " + "debugging." + ) + + def __add_log_file_argument(self): + self.__parser.add_argument( + "--log-file", "-l", type=str, default="", nargs="?" + ) + + def __add_version_argument(self): + self.__parser.add_argument( + "--Version", "-V", action="version", + version="%(prog)s (version " + __version__ + ")" + ) + + def __parse_arguments(self): + self.__arguments = self.__parser.parse_args() + + def __quit_if_no_args(self): + if not self.write_config and self.configuration_location == "": + self.__parser.print_help() + sys.exit() + + @property + def write_config(self): + # type: () -> bool + return self.__arguments.WriteConfig + + @property + def configuration_location(self): + # type: () -> str + return self.__arguments.configuration + + @property + def verbose(self): + # type: () -> int + return self.__arguments.v + + @property + def log_file(self): + # type: () -> str + return self.__arguments.log_file + + +class StartProgram(object): + + def __init__(self): + self.__execute = start.Execute() + self.__create_config = create.StartConfig() + self.__arguments = _Arguments() + self.__configuration = None # type: dict + + def start(self, configuration): + # type: (Dict[str, str]) -> None + self.__set_configuration(configuration) + self.__process_extras() + self.__load_arguments() + self.__begin_output() + self.__setup_logger() + self.__process_arguments() + + def __set_configuration(self, configuration): + # type: (Dict[str, str]) -> None + self.__configuration = configuration + + def __process_extras(self): + if self.__configuration["extras"]: + print( + "[ERROR] Caught something unaccounted for, " + "this should be reported, caught: " + "{}".format(self.__configuration["extras"][0]) + ) + + def __load_arguments(self): + self.__arguments.parse_arguments(self.__configuration["description"]) + + def __begin_output(self): + sys.stdout.write("\x1b[2J\x1b[H") # Clears the screen + sys.stdout.write(self.__opening_art()) + + @staticmethod + def __opening_art(): + # type: () -> str + return """\ +######### ######### ## ## ### +## ## ## ## ## ## ## ## +## ## ## ## ## ## ## ## +######### ######### ## ## ## ## ## +## ## ## ## ## #### ## ## ##### ## +## ## ## ## #### #### ## ## +## ## ## ## ## ## ## ## + ## + ## $$$$$$$$ $ $ $$$$$ $$ $$ + ### $$$ $$ $$ $ $$ $$ + $$$$$$$ $$$$$$$ $$$$$$ $$ $$ + $$$ $$ $$ $ $$ $$ + $$$$$$$$ $ $ $$$$$ $$$$$$ $$$$$$ + +Built in Jefferson Lab. +""" + + def __setup_logger(self): + if self.__arguments.verbose == 1: + initial_logging.InternalLogger.configure_root_logger( + logging.WARNING, self.__arguments.log_file + ) + elif self.__arguments.verbose == 2: + initial_logging.InternalLogger.configure_root_logger( + logging.INFO, self.__arguments.log_file + ) + elif self.__arguments.verbose >= 3: + initial_logging.InternalLogger.configure_root_logger( + logging.DEBUG, self.__arguments.log_file + ) + else: + initial_logging.InternalLogger.configure_root_logger( + logging.ERROR, self.__arguments.log_file + ) + + def __process_arguments(self): + if self.__arguments.write_config: + self.__write_config() + else: + self.__run_builder() + + def __run_builder(self): + self.__execute.run( + self.__configuration, + self.__arguments.configuration_location + ) + + def __write_config(self): + self.__create_config.make_config( + self.__configuration, + self.__arguments.configuration_location + ) diff --git a/PyPWA/core/configurator/storage.py b/PyPWA/core/configurator/storage.py new file mode 100644 index 00000000..6f356b79 --- /dev/null +++ b/PyPWA/core/configurator/storage.py @@ -0,0 +1,104 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +The Root Storage objects for the configurator. +---------------------------------------------- +- _InternalStorage - The true storage of the plugins and shells, should act as + a singleton. + +- Storage - Provides a programmatic interface to the plugins and shells, and + has the ability to update internal data when called if new plugin locations + have been added. +""" + +import logging +from typing import Any, List + +import PyPWA.builtin_plugins +import PyPWA.core +import PyPWA.shell +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import options +from PyPWA.core.shared import plugin_loader + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class _InternalStorage(object): + + plugins = [] # type: List[options.Plugin] + shells = [] # type: List[options.Main] + index = 0 + + +class Storage(object): + + __LOGGER = logging.getLogger(__name__ + ".ConfiguratorStorage") + __STORAGE = _InternalStorage() + + def __init__(self): + self.__loader = plugin_loader.PluginLoader() + self.__loader.add_plugin_location( + {PyPWA.builtin_plugins, PyPWA.shell, PyPWA.core} + ) + self.__index = 0 + self._check_for_updates() + + def _check_for_updates(self): + if self.__loader.storage_index < self.__STORAGE.index: + self.__LOGGER.critical( + "PluginStorage has a smaller index than Storage! " + "This means something broke with PluginStorage, and the " + "program is likely to fail!" + ) + if not self.__loader.storage_index == self.__STORAGE.index: + self.__LOGGER.debug( + "Storage is out of date with plugin module, " + "refreshing plugins" + ) + self.__update_storage() + + if not self.__STORAGE.index == self.__index: + self.__index = self.__STORAGE.index + self._update_extra() + + def __update_storage(self): + self.__STORAGE.plugins = self.__loader.get_by_class(options.Plugin) + self.__STORAGE.shells = self.__loader.get_by_class(options.Main) + self.__STORAGE.index = self.__loader.storage_index + + def _update_extra(self): + pass + + def add_location(self, location): + # type: (Any) -> None + self.__loader.add_plugin_location(location) + self._check_for_updates() + + def _get_plugins(self): + # type: () -> Any + self._check_for_updates() + return self.__STORAGE.plugins + + def _get_shells(self): + # type: () -> Any + self._check_for_updates() + return self.__STORAGE.shells diff --git a/PyPWA/core/initial_logging.py b/PyPWA/core/initial_logging.py deleted file mode 100644 index 1ab1d3c3..00000000 --- a/PyPWA/core/initial_logging.py +++ /dev/null @@ -1,45 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -Defines the global logging settings. -""" - -import logging - -from PyPWA import VERSION, LICENSE, STATUS - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - -# Behold, the only single function inside PyPWA, bask in its unusual glory - - -def define_logger(level): - logger = logging.getLogger() - handler = logging.StreamHandler() - formatter = logging.Formatter( - "%(asctime)s %(name)-12s %(levelname)-8s %(message)s" - ) - - handler.setFormatter(formatter) - logger.addHandler(handler) - logger.setLevel(level) diff --git a/PyPWA/core/plugin_loader.py b/PyPWA/core/plugin_loader.py deleted file mode 100644 index dd6f37a1..00000000 --- a/PyPWA/core/plugin_loader.py +++ /dev/null @@ -1,229 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" - -""" - -import importlib -import logging -import os -import pkgutil -import sys - -import PyPWA -from PyPWA import VERSION, LICENSE, STATUS - -__author__ = ["Mark Jones"] -__credits__ = [ - "Mark Jones", - "jp. @ Stack Overflow", - "unutbu @ Stack Overflow" -] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class PluginLoading(object): - - _logger = logging.getLogger(__name__) - _root_object = object - - def __init__(self, root_object): - """ - Loads plugins from either a directory or an already loaded module. - Works by loading all attributes of that module then extracting - the objects that subclass the supplied TemplateObject. - - Args: - root_object (type): The Template Object to use for searching. - """ - self._logger.addHandler(logging.NullHandler()) - self._root_object = root_object - - @staticmethod - def _make_list_of_modules(module): - """ - See Also: - http://stackoverflow.com/a/1310912 - http://stackoverflow.com/a/1708706 - """ - # Should make a list of: - # [ ImporterInstance, name of module, is a package ] - names = [ - name for loader, name, is_loaded in pkgutil.iter_modules( - module.__path__ - ) - ] - # Credit to unutbu and jp. for the discovery of how pkgutil works. - return names - - @staticmethod - def _import_module(module_name): - return importlib.import_module(module_name) - - def _find_libs(self, module): - """ - Takes a package, finds all sub modules, then imports the - submodules and returns those submodules. - - Args: - module: The initial module. - - Returns: - list[module]: The list of submodules. - """ - libs = [] - for module_name in self._make_list_of_modules(module): - libs.append( - importlib.import_module( - module.__name__ + "." + module_name - ) - ) - return libs - - def _extract_initializer(self, plugins): - """ - Takes the loaded modules and searches them for the objects - that subclass the template. - - Args: - plugins list[module]: The list of modules that were found. - - Returns: - list[type]: The list of objects that sub-classed the - template. - """ - plugin_initializer = [] - for plugin in plugins: - self._logger.info( - "Found the following modules: \n{0}".format(repr(plugin)) - ) - for object_name in dir(plugin): - the_object = getattr(plugin, object_name) - try: - if issubclass(the_object, self._root_object): - plugin_initializer.append(the_object) - except TypeError: - pass - - return plugin_initializer - - def fetch_plugin(self, file_list): - """ - Takes a list of files or modules then returns the objects that - sub-classed the supplied Template. - - Args: - file_list (list): The list of modules or paths that need to be - loaded and searched - - Returns: - list[type]: The list of objects that were found that - sub-classed the object. - """ - potential_plugins = [] - for the_file in file_list: - if the_file == "": - pass - elif isinstance(the_file, str): - # Appends the directory containing the - sys.path.append( - os.path.dirname(os.path.abspath(the_file)) - ) - - module = self._import_module( - # Extracts the filename from the path provided - os.path.splitext(os.path.basename(the_file))[0] - ) - - potential_plugins.append(self._find_libs(module)) - elif isinstance(the_file, type(PyPWA)): - potential_plugins.append(self._find_libs(the_file)) - - flattened_potential = [] - for list_of_plugins in potential_plugins: - for plugin in list_of_plugins: - flattened_potential.append(plugin) - - plugins = self._extract_initializer(flattened_potential) - - return plugins - - -class SingleFunctionLoader(object): - - def __init__(self, the_file): - """ - - Args: - the_file: - """ - self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) - self._module = None # type: type(PyPWA) - - try: - self._load_module(the_file) - except AttributeError: - if isinstance(the_file, type(None)): - raise ValueError( - "Expected a file location, received None instead!" - ) - - def _load_module(self, the_file): - """ - - Args: - the_file: - - Returns: - - """ - sys.path.append( - os.path.dirname(os.path.abspath(the_file)) - ) - - self._module = importlib.import_module( - os.path.splitext(os.path.basename(the_file))[0] - ) - - def fetch_function(self, function_name, fail=False): - """ - - Args: - function_name: - fail: - - Returns: - - """ - try: - return getattr(self._module, function_name) - except Exception: - if fail: - raise - else: - return empty - - -# A simple empty function for when we don't care too much about what is -# loaded for the program. -def empty(): - pass diff --git a/PyPWA/core/shared/__init__.py b/PyPWA/core/shared/__init__.py new file mode 100644 index 00000000..54bd2f9e --- /dev/null +++ b/PyPWA/core/shared/__init__.py @@ -0,0 +1,47 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +The core libraries of PyPWA +--------------------------- +Any core libraries that are needed for PyPWA that wouldn't or shouldn't +function as a plugin, are located here. This means anything whose internal +function shouldn't really change should be here, such as hash generation, +data location, and such. + +- interfaces - The interfaces to the program, while the configurator and + other initializing packages may offer their own interfaces to load into + the program. These interfaces actually define how the objects should + interact with each other instead. + +- data_locator - A simple module that searches for a location for data. + Supports data, cache, logging, and configuration. + +- initial_logging - Controls how logging works in PyPWA. Currently is + limited to string logging. + +- plugin_loader - The main plugin loading module inside PyPWA. It's generic + enough to be used anywhere but also powerful enough to handle all plugin + needs. +""" + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION diff --git a/PyPWA/core/shared/data_locator.py b/PyPWA/core/shared/data_locator.py new file mode 100644 index 00000000..7a28eff2 --- /dev/null +++ b/PyPWA/core/shared/data_locator.py @@ -0,0 +1,88 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Here we use appdirs to determine the location of where data should be saved +on the system for cache, data, and logs. +""" + +import os + +import appdirs + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +def get_cache_uri(): + # type: () -> str + possible_uri = appdirs.user_cache_dir("PyPWA", "JLab", __version__) + return __find_usable_uri(possible_uri) + + +def get_data_uri(): + # type: () -> str + possible_uri = appdirs.user_data_dir("PyPWA", "JLab", __version__) + return __find_usable_uri(possible_uri) + + +def get_log_uri(): + # type: () -> str + possible_uri = appdirs.user_log_dir("PyPWA", "JLab", __version__) + return __find_usable_uri(possible_uri) + + +def get_config_uri(): + # type: () -> str + possible_uri = appdirs.user_config_dir("PyPWA", "JLab", __version__) + return __find_usable_uri(possible_uri) + + +def __find_usable_uri(potential_uri): + # type: (str) -> str + __recursively_make_uri_directories(potential_uri) + return __determine_potential_or_cwd(potential_uri) + + +def __recursively_make_uri_directories(potential_uri): + # type: (str) -> None + try: + os.makedirs(potential_uri) + except OSError: + pass + + +def __determine_potential_or_cwd(potential_uri): + # type: (str) -> str + try: + __check_writable(potential_uri) + return potential_uri + except OSError: + __check_writable(os.getcwd()) + return os.getcwd() + + +def __check_writable(potential_uri): + # type: (str) -> None + test_file = potential_uri + "/test" + with open(test_file, "w") as stream: + stream.write("test") + os.remove(test_file) diff --git a/PyPWA/core/shared/generate_hash.py b/PyPWA/core/shared/generate_hash.py new file mode 100644 index 00000000..f68f25f9 --- /dev/null +++ b/PyPWA/core/shared/generate_hash.py @@ -0,0 +1,91 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +This will take a str to a file location, then parse the entire file, returning +the hash of that file. Hashes are useful for detecting changes in a file +without comparing the enclosed data directly. +""" + +import hashlib +import io + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +def get_sha512_hash(file_location): + # type: (str) -> str + return __get_stream_hash(file_location, hashlib.sha512()) + + +def get_sha384_hash(file_location): + # type: (str) -> str + return __get_stream_hash(file_location, hashlib.sha384()) + + +def get_sha256_hash(file_location): + # type: (str) -> str + return __get_stream_hash(file_location, hashlib.sha256()) + + +def get_sha224_hash(file_location): + # type: (str) -> str + return __get_stream_hash(file_location, hashlib.sha224()) + + +def get_sha1_hash(file_location): + # type: (str) -> str + return __get_stream_hash(file_location, hashlib.sha1()) + + +def get_md5_hash(file_location): + # type: (str) -> str + return __get_stream_hash(file_location, hashlib.md5()) + + +def __get_stream_hash(file_location, file_hash): + # type: (str, hashlib._hashlib.HASH) -> str + stream = __open_stream(file_location) + __update_hash(stream, file_hash) + __close_stream(stream) + return __get_string_from_hash(file_hash) + + +def __open_stream(file_location): + # type: (str) -> io.FileIO + return open(file_location, "rb") + + +def __update_hash(stream, file_hash): + # type: (io.FileIO, hashlib._hashlib.HASH) -> None + for chunk in iter(lambda: stream.read(4096), b""): + file_hash.update(chunk) + + +def __close_stream(stream): + # type: (io.FileIO) -> None + stream.close() + + +def __get_string_from_hash(file_hash): + # type: (hashlib._hashlib.HASH) -> str + return file_hash.hexdigest() diff --git a/PyPWA/core/shared/initial_logging.py b/PyPWA/core/shared/initial_logging.py new file mode 100644 index 00000000..9c99c712 --- /dev/null +++ b/PyPWA/core/shared/initial_logging.py @@ -0,0 +1,97 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +A simple function that sets the logging conditions for the entire program. +This controls the formatting off the logs, where the logs are located, and +the level of verbosity of those logs. +""" + +import logging + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class _LoggerData(object): + + level = "" # type: str + filename = "" # type: str + + +class InternalLogger(object): + + __LOGGER = logging.getLogger() + __DATA = _LoggerData() + __FORMATTER = logging.Formatter( + "[%(asctime)s][%(processName)s][%(name)s][%(levelname)s]: " + "%(message)s", "%H:%M:%S" + ) + + @classmethod + def configure_root_logger(cls, level, file_name="", processor_id=""): + # type: (str, str, str) -> None + cls.__DATA.level = level + cls.__DATA.filename = file_name + cls.__setup_handlers(processor_id) + cls.__set_level() + + @classmethod + def __setup_handlers(cls, processor_id): + # type: (str) -> None + cls.__create_stream_handler() + if cls.__DATA.filename: + cls.__compute_file_name(processor_id) + cls.__create_file_handler() + + @classmethod + def __create_stream_handler(cls): + handler = logging.StreamHandler() + handler.setFormatter(cls.__FORMATTER) + cls.__LOGGER.addHandler(handler) + + @classmethod + def __compute_file_name(cls, processor_id): + # type: (str) -> None + if processor_id: + cls.__DATA.filename = processor_id + "--" + cls.__DATA.filename + + @classmethod + def __create_file_handler(cls): + handler = logging.FileHandler(cls.__DATA.filename) + handler.setFormatter(cls.__FORMATTER) + cls.__LOGGER.addHandler(handler) + + @classmethod + def __set_level(cls): + cls.__LOGGER.setLevel(cls.__DATA.level) + + @classmethod + def get_level(cls): + return cls.__DATA.level + + @classmethod + def get_filename(cls): + return cls.__DATA.filename + + @classmethod + def set_level_to_global(cls): + cls.__DATA.level = cls.__LOGGER.getEffectiveLevel() diff --git a/PyPWA/core/shared/interfaces/__init__.py b/PyPWA/core/shared/interfaces/__init__.py new file mode 100644 index 00000000..2479d8ac --- /dev/null +++ b/PyPWA/core/shared/interfaces/__init__.py @@ -0,0 +1,41 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +The universal interfaces for all of PyPWA. +------------------------------------------ +These interfaces define how the objects should interact with each other in +all circumstances inside PyPWA. These interfaces however do not define how +the plugins should interact with the initializer. + +.. note:: + Information and the needed interfaces to interact with an + initializer should be stated inside the respective initializer. + +- internals - This contains how the internal objects and information passed + around by the main objects should be defined. + +- plugins - This contains information on the methods that are expected to + exist inside the plugin objects. +""" + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION diff --git a/PyPWA/core/shared/interfaces/internals.py b/PyPWA/core/shared/interfaces/internals.py new file mode 100644 index 00000000..bf107e80 --- /dev/null +++ b/PyPWA/core/shared/interfaces/internals.py @@ -0,0 +1,239 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Where the internal operation of the plugins are located. +-------------------------------------------------------- +These interfaces reflect the internal design of the plugins, these should be +used when you are defining a portion of a plugin that will interact with +other plugins. + +- Reader - The reader object that is expected to be returned by the + DataIterator. + +- Writer - The writer object that is expected to be returned by the + DataIterator. + +- ProcessInterface - This is the interface that is expected from + KernelProcessing's fetch_interface method. This is the main interface + between the kernels and the executing program. + +- Kernel - The kernel of code that is expected to be sent to the + Kernel Processing plugins. + +- KernelInterface - This defines how data returned by each of the kernels + should be processed. + +- OptimizerOptionParser - This is to process the parameters by the + optimizer to be sent to the user's kernel or code. This is to either + package values in a easy to use dictionary and/or to remove extra + trailing information. + +- LikelihoodTypes - An enumeration of the various likelihoods that are used + internally. OTHER, LOG_LIKELIHOOD, and CHI_SQUARED. +""" + +import enum +from typing import Any, List +from typing import Optional as Opt + +import numpy + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class Reader(object): + + def next(self): + # type: () -> numpy.ndarray + """ + Called to get the next event from the reader. + + :return: A single event. + :rtype: numpy.ndarray + """ + raise NotImplementedError() + + def __next__(self): + return self.next() + + def __iter__(self): + return self + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + def close(self): + # type: () -> None + """ + Should close any open objects or streams. + """ + raise NotImplementedError() + + +class Writer(object): + + def write(self, data): + # type: (numpy.ndarray) -> None + """ + Should write the received event to the stream. + + :param numpy.ndarray data: The event data stored in a numpy array. + """ + raise NotImplementedError() + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + def close(self): + # type: () -> None + """ + Should close the stream and any open streams or objects. + """ + raise NotImplementedError() + + +class ProcessInterface(object): + + def run(self, *args): + # type: (*Any) -> Any + """ + This function will start the processing of the processes, whatever was + passed through the kernel will be started with this method. + + :param args: Anything that you want to pass to your kernel. + :return: The value kernel interface. + """ + raise NotImplementedError + + @property + def previous_value(self): + # type: () -> Any + """ + The previous value received from the kernel interface. + + :return: Previous calculated value. + """ + raise NotImplementedError + + def stop(self, force=False): + # type: (Opt[bool]) -> None + """ + Should stop all process, threads, etc, that are being used to + calculate. + + :param bool force: whether children should be stopped gently or + violently murdered. + """ + raise NotImplementedError + + @property + def is_alive(self): + # type: () -> bool + """ + Should return whether the children are still alive or have been + shutdown. + + :return: The state of the processes. + :rtype: bool + """ + raise NotImplementedError + + +class Kernel(object): + + # process_id should be set by the Kernel Processing plugin. + PROCESS_ID = None # type: int + + def setup(self): + # type: () -> None + """ + Anything that should be setup in the thread or process should be + put here, this will be called only once before any calculation begins. + """ + raise NotImplementedError() + + def process(self, data=False): + # type: (Opt[Any]) -> Any + """ + The actual calculation or function of the program, can optionally + support values from the main thread / process. + + :param data: Any data that you want to pass to the kernel. + :return: The final value or object that should be sent back to the + main thread. + """ + raise NotImplementedError() + + +class KernelInterface(object): + + # is_duplex controls whether the kernel will shutdown after its first + # run or if the kernel will wait for more information. If this is true + # the kernel will only be able to receive data and will shutdown after + # its first run; however, if this is true then the kernel will stay + # running and waiting for a value from the interface indefinitely until + # they are shutdown manually. + IS_DUPLEX = False + + def run(self, communicator, args): + # type: (List[Any], Any) -> Any + """ + The method that will be called to begin the calculation. This is + the interface between the kernels and the calling object. + + :param communicator: A list of objects that will be used to + communicate with the kernels. + :param args: Any values that are sent to the main interface. + :return: Whatever value that is calculated locally from the kernels. + """ + raise NotImplementedError("The run method must be extended!") + + +class OptimizerOptionParser(object): + + # A simple multiplier that will be multiplied to the final result of + # every run call. + MULTIPLIER = 1 + + def convert(self, passed_value): + # type: (Any) -> Any + """ + This should take any value sent by optimizer and clean up the value + to something easier for the user to interact with if possible. + + :param passed_value: The object sent by the optimizer. + :return: The cleaned up value. + """ + raise NotImplementedError + + +class LikelihoodTypes(enum.Enum): + OTHER = 1 + CHI_SQUARED = 2 + LOG_LIKELIHOOD = 3 diff --git a/PyPWA/core/shared/interfaces/plugins.py b/PyPWA/core/shared/interfaces/plugins.py new file mode 100644 index 00000000..ff5dbaf3 --- /dev/null +++ b/PyPWA/core/shared/interfaces/plugins.py @@ -0,0 +1,223 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +The core definition of plugins and how they work. +------------------------------------------------- +All the different plugin types are defined here, these interfaces should be +extended when writing your own plugins so that your own plugin can replace +the internal plugins without any issues. + +.. note:: + Some of these interfaces have a main method called "main_options", + this method exists so that options not passed via the __init__ can be + loaded into the object still before running. Typically this is for + runtime variables and not for user variables. + +- Optimizer - This is the interface for minimizer and maximizer alike. + +- KernelProcessing - This defines how kernel processing works, simply, + the kernel processing works by taking a kernel of code, a package of + data, then using those to calculate more data. The interface to interact + with the resulting processes, threads, etc, and the core kernel that you + should expect to return are all in internals.py + +- DataParser - This is a parser that will return a numpy array, + or something that operates a lot like a numpy array. It is expected that + all events will be returned at once, or a reference to all events. Should + also be able to write data as well. + +- DataIterator - This is more complex parser, this parser should be able to + read and write a single event at a time, as such should be able to be used + in iteration, or as a file handle. + +- Main - This is a simple interface for the main objects. +""" + +from typing import Any +from typing import Callable +from typing import Dict +from typing import Optional as Opt + +import numpy + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.shared.interfaces import internals + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class Optimizer(object): + + def main_options(self, calc_function, fitting_type=None): + # type: (Callable[[Any], Any], Opt[internals.LikelihoodTypes]) -> None + """ + The main options for the Optimizer, these are options that are + typically needed for optimization, but due to the design of the + program, these options can't be passed directly to the optimizer + via its __init__ method. + + :param calc_function: The main runtime function for the program. + This is often the likelihood, or amplitude, that needs to be + optimized. + :param internals.LikelihoodTypes fitting_type: One of the + enumerations from likelihood types. + """ + raise NotImplementedError + + def start(self): + # type: () -> None + """ + This should start all the actual processing and logic inside the + optimizer, anything being started before this is called could cause + an internal error. + """ + raise NotImplementedError + + def return_parser(self): + # type: () -> internals.OptimizerOptionParser + """ + Since each optimizer is different, and as such sends and receives + its arguments in a different way, this provides the object that + will attempt to 'normalize' these arguments to make interact with + them more transparent. + + :rtype: internals.OptimizerOptionParser + :return: An object that extended the option parsing interface that + will convert the received parameters. + """ + raise NotImplementedError + + def save_extra(self, save_name): + # type: (str) -> None + """ + Takes whatever information the optimizer found and saves it using + the supplied save_name. + + :param str save_name: The name of the file to save to, or the + template of the name depending on the optimizer. The optimizer + doesn't have to save all information to the file name provided + explicitly, and can instead do save along the lines of + "save_name_covariance" for example. + """ + raise NotImplementedError + + +class KernelProcessing(object): + + def main_options( + self, + data, # type: Dict[str, numpy.ndarray] + process_template, # type: internals.Kernel + interface_template # type: internals.KernelInterface + ): + # type: (...) -> None + """ + The main options for the KernelProcessor, these are options that are + typically needed for processing, but due to the design of the + program, these options can't be passed directly to the processor + via its __init__ method. + + :param dict data: A dictionary with values being numpy arrays, each + key should be loaded into the processing template as a public + variable. + :param internals.Kernel process_template: A predefined kernel that + holds all the logic and static data needed to calculate the + provided function. This static data does not include events, + but instead data that should be needed no matter the event being + calculated. Ex. the value of π. + :param internals.KernelInterface interface_template: The definition + of how the return values should be calculated from the kernels. + This could be a simple as a Sum, or as complicated as you could want. + """ + raise NotImplementedError + + def fetch_interface(self): + # type: () -> internals.ProcessInterface + """ + Returns the finished interface for the processing. + + :rtype: internals.ProcessInterface + :return: Returns a finalized implementation to the processing + kernel for the receiving object to use. + """ + raise NotImplementedError + + +class DataParser(object): + + def parse(self, text_file): + # type: (str) -> numpy.ndarray + """ + Called to read in the data from a file. + + :param str text_file: The path to the file to read. + :return: All the data from the file. + :rtype: numpy.ndarray + """ + raise NotImplementedError + + def write(self, text_file, data): + # type: (str, numpy.ndarray) -> None + """ + Called to write a numpy array out to file. + + :param str text_file: The file to write the data out to. + :param numpy.ndarray data: The array data to write. + """ + raise NotImplementedError + + +class DataIterator(object): + + def return_reader(self, text_file): + # type: (str) -> internals.Reader + """ + Returns an initialized reader for that text file. + + :param str text_file: The file to be read over. + :return: An initialized reader. + :rtype: internals.Reader + """ + raise NotImplementedError + + def return_writer(self, text_file, data): + # type: (str, numpy.ndarray) -> internals.Writer + """ + Returns an initialized writer that will work with the data type. + + :param str text_file: Where to write the data. + :param numpy.ndarray data: The array or event you want to write. + :return: An initialized writer. + :rtype: internals.Writer + """ + raise NotImplementedError + + +class Main(object): + + def start(self): + # type: () -> None + """ + This is the method that should start the execution on the main object. + It is assumed that basic setup of the program has been done by this + point, and this should simply start the function of the program. + """ + raise NotImplementedError diff --git a/PyPWA/core/shared/plugin_loader.py b/PyPWA/core/shared/plugin_loader.py new file mode 100644 index 00000000..064ce361 --- /dev/null +++ b/PyPWA/core/shared/plugin_loader.py @@ -0,0 +1,313 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +The core plugin parser for functions and packages. +-------------------------------------------------- +There are 5 objects here, _AppendPath, _Importer, _FilterBySubclass, +_PluginStorage and the main PluginLoader object. If you wish to use the +plugin storage module, you will need to call and use PluginLoader. + +.. note:: + This plugin will save all loaded plugins anywhere in the program. The + benefit to this is that all user plugins can be loaded once, then + +- _AppendPath - This object takes the path of modules that exist outside of + the defined Python Path and imports their root directory into the System + Path + +- _Importer - This object actually imports the module, and all of its + submodules, then returns those submodules. + +- _FilterBySubclass - this object takes all the loaded objects from the + PluginStorage then searches for all objects that are subclass-ed by the + provided class. + +- _PluginStorage - This object actually stores everything that was imported + from the provided locations. + +- PluginLoader - The main object, returns objects and functions based on the + provided search conditions. +""" + +import importlib +import logging +import os +import pkgutil +import sys + +from typing import Any, Callable, List, Union, Set +import types + +from PyPWA import AUTHOR, VERSION + +__credits__ = [ + "Mark Jones", + "jp. @ Stack Overflow", + "unutbu @ Stack Overflow" +] +__author__ = AUTHOR +__version__ = VERSION + + +class _AppendPath(object): + + __LOGGER = logging.getLogger(__name__ + "._AppendPath") + + def append_path(self, filename): + # type: (str) -> None + function_path = self.__get_function_path(filename) + self.__log_path(function_path) + sys.path.append(function_path) + + @staticmethod + def __get_function_path(filename): + # type: (str) -> str + absolute_path = os.path.abspath(filename) + path_without_basename = os.path.dirname(absolute_path) + return path_without_basename + + def __log_path(self, path): + # type: (str) -> None + self.__LOGGER.debug("Adding %s to the path." % path) + + +class _Importer(object): + + __LOGGER = logging.getLogger(__name__ + "._Importer") + + def __init__(self): + self.__path_handler = _AppendPath() + + def fetch_modules(self, package): + # type: (Union[str, types.ModuleType]) -> object + found_module = self.__load_module(package) + return self.__process_module(found_module) + + def __load_module(self, package): + # type: (Union[str, types.ModuleType]) -> object + if isinstance(package, types.ModuleType): + return package + else: + return self.__import_module(package) + + def __import_module(self, package): + # type: (str) -> types.ModuleType + self.__path_handler.append_path(package) + name = self.__get_module_name(package) + return self.__get_module(name) + + @staticmethod + def __get_module_name(package): + # type: (str) -> str + file_name = os.path.basename(package) + module_name = os.path.splitext(file_name)[0] + return module_name + + def __get_module(self, package): + # type: (str) -> types.ModuleType + try: + return importlib.import_module(package) + except Exception as Error: + self.__process_module_error(Error) + + def __process_module_error(self, error): + # type: (Exception) -> None + self.__LOGGER.exception(error) + + def __process_module(self, potential_module): + # type: (types.ModuleType) -> List[types.ModuleType] + if hasattr(potential_module, "__path__"): + return self.__load_multiple_modules(potential_module) + elif isinstance(potential_module, types.ModuleType): + return [potential_module] + else: + self.__raise_module_error() + + def __load_multiple_modules(self, package): + # type: (types.ModuleType) -> List[types.ModuleType] + """ + See Also: + - http://stackoverflow.com/a/1310912 + - http://stackoverflow.com/a/1708706 + """ + modules = [] + for loader, module, ispkg in pkgutil.iter_modules(package.__path__): + module_name = package.__name__ + "." + module + found_module = self.__get_module(module_name) + modules.append(found_module) + return modules + + @staticmethod + def __raise_module_error(): + raise ImportError("Failed to find the package!") + + +class _FilterBySubclass(object): + + __LOGGER = logging.getLogger(__name__ + "._FilterBySubclass") + + def __init__(self, storage): + # type: (_PluginStorage) -> None + self.__storage = storage + self.__found_classes = None + self.__template = None + + def filter(self, template): + # type: (type) -> List[type] + self.__clear_search() + self.__set_search_template(template) + plugins = self.__filter_plugins() + self.__log_plugin_search(plugins) + return plugins + + def __clear_search(self): + self.__found_classes = [] + self.__template = None + + def __set_search_template(self, template): + # type: (type) -> None + self.__template = template + + def __filter_plugins(self): + # type: () -> List[type] + for plugin in self.__storage.PLUGINS: + self.__process_plugin(plugin) + return self.__found_classes + + def __process_plugin(self, plugin): + # type: (type) -> None + for attribute_name in dir(plugin): + attribute = getattr(plugin, attribute_name) + self.__try_to_process_object(attribute) + + def __try_to_process_object(self, attribute): + # type: (type) -> None + try: + self.__process_attribute(attribute) + except TypeError: + pass + + def __process_attribute(self, attribute): + # type: (type) -> None + if issubclass(attribute, self.__template): + self.__found_classes.append(attribute) + + def __log_plugin_search(self, plugins): + # type: (List[type]) -> None + self.__LOGGER.debug("Using template: '%s'" % self.__template) + self.__LOGGER.debug("Found: '%s'" % plugins) + + +class _PluginStorage(object): + + __LOGGER = logging.getLogger(__name__ + "._PluginStorage") + PLUGINS = [] # type: List[type] + __LOCATIONS = [] # type: List[str] + __APPEND_COUNT = 0 + + @classmethod + def add_location(cls, location): + # type: (str) -> None + cls.__note_if_index_is_zero() + cls.__LOCATIONS.append(location) + cls.__APPEND_COUNT = cls.__APPEND_COUNT + 1 + + @classmethod + def __note_if_index_is_zero(cls): + if cls.__APPEND_COUNT == 0: + cls.__LOGGER.debug("Initializing _PluginStorage for first time") + + @classmethod + def location_already_added(cls, location): + # type: (str) -> bool + if location in cls.__LOCATIONS: + return True + else: + return False + + @classmethod + def plugin_index(cls): + # type: () -> int + return cls.__APPEND_COUNT + + +class PluginLoader(object): + + __LOGGER = logging.getLogger(__name__ + ".PluginStorage") + __STORAGE = _PluginStorage() + + def __init__(self): + self.__importer = _Importer() + self.__filter_subclass = _FilterBySubclass(self.__STORAGE) + + def add_plugin_location(self, location): + # type: (Any) -> None + if isinstance(location, list) or isinstance(location, set): + self.__process_multiple_modules(location) + else: + self.__process_single_module(location) + + def __process_multiple_modules(self, locations): + # type: (Union[List[str, Set[str]]]) -> None + for location in locations: + self.__process_single_module(location) + + def __process_single_module(self, location): + # type: (str) -> None + if location is not None and location is not "": + if not self.__STORAGE.location_already_added(location): + modules = self.__importer.fetch_modules(location) + self.__append_modules(modules) + self.__STORAGE.add_location(location) + self.__LOGGER.debug("Adding plugin location: %s" % location) + else: + self.__LOGGER.debug( + "Received blank location! This might be an error." + ) + + def __append_modules(self, modules): + # type: (List[type]) -> None + for the_module in modules: + self.__STORAGE.PLUGINS.append(the_module) + + def get_by_name(self, name, fail=True): + # type: (str, bool) -> Callable[Any, Any] + for plugin in self.__STORAGE.PLUGINS: + if hasattr(plugin, name): + possible_answer = getattr(plugin, name) + if callable(possible_answer): + return possible_answer + if fail: + raise ImportError + else: + return self.__empty_function + + @staticmethod + def __empty_function(*args, **kwargs): + # type: (Any, Any) -> None + pass + + def get_by_class(self, template): + # type: (type) -> List[type] + return self.__filter_subclass.filter(template) + + @property + def storage_index(self): + # type: () -> int + return self.__STORAGE.plugin_index() diff --git a/PyPWA/core/templates/configurator_templates.py b/PyPWA/core/templates/configurator_templates.py deleted file mode 100644 index e71e5c3a..00000000 --- a/PyPWA/core/templates/configurator_templates.py +++ /dev/null @@ -1,59 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" - -""" - -from PyPWA import VERSION, LICENSE, STATUS - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class ShellCoreTemplate(object): - """ - - """ - - def make_config(self, function_settings, application_data): - """ - - Args: - function_settings: - application_data: - - Returns: - - """ - raise NotImplementedError - - def run(self, function_settings, configuration_location): - """ - - Args: - function_settings: - configuration_location: - - Returns: - - """ - raise NotImplementedError diff --git a/PyPWA/core/templates/interface_templates.py b/PyPWA/core/templates/interface_templates.py deleted file mode 100644 index 3ab704fc..00000000 --- a/PyPWA/core/templates/interface_templates.py +++ /dev/null @@ -1,298 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" - -""" - -from PyPWA import VERSION, LICENSE, STATUS - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class ReaderInterfaceTemplate(object): - - def __init__(self, file_location): - """ - - Args: - file_location: - """ - self._the_file = file_location - - def reset(self): - """ - - Returns: - - """ - raise NotImplementedError( - "%s does not overwrite method write. This is the method that " - "you should overwrite to have the object reset properly when " - "this method is called." % self.__class__.__name__ - ) - - @property - def next_event(self): - """ - - Returns: - - """ - raise NotImplementedError( - "%s does not overwrite method write. This is the method that " - "you should overwrite to have the object read in the next " - "event properly when its called." % self.__class__.__name__ - ) - - def next(self): - return self.next_event - - def __next__(self): - return self.next_event - - def __iter__(self): - return self - - def __enter__(self): - return self - - def __exit__(self, *args): - self.close() - - @property - def previous_event(self): - raise NotImplementedError( - "%s does not overwrite method write. This is the method that " - "you should overwrite to have the object return the last " - "value that was parsed." % self.__class__.__name__ - ) - - def close(self): - """ - - Returns: - - """ - raise NotImplementedError( - "%s does not overwrite method write. This is the method that " - "you should overwrite to have the object return the last " - "value that was parsed." % self.__class__.__name__ - ) - - -class WriterInterfaceTemplate(object): - - def __init__(self, file_location): - """ - - Args: - file_location: - """ - self._the_file = file_location - - def write(self, data): - """ - - Args: - data: - - Returns: - - """ - raise NotImplementedError( - "%s does not overwrite method write. This is the method that " - "you should overwrite to have the object write the data out " - "to the disk correctly." % self.__class__.__name__ - ) - - def __enter__(self): - return self - - def __exit__(self, *args): - self.close() - - def close(self): - """ - - Returns: - - """ - raise NotImplementedError( - "%s does not overwrite method write. This is the method that " - "you should overwrite to have the object properly operated " - "properly when its called" % self.__class__.__name__ - ) - - -class InterfaceTemplate(object): - """ - Template for interface objects to be handed off by the KernelProcessor - """ - - def run(self, *args): - """ - - Args: - *args: - - Returns: - - """ - raise NotImplementedError - - @property - def previous_value(self): - raise NotImplementedError - - def stop(self, force=False): - """ - - Args: - force: - - Returns: - - """ - raise NotImplementedError - - @property - def is_alive(self): - """ - - Returns: - - """ - raise NotImplementedError - - -class AbstractKernel(object): - """ - This is the main kernel that is used inside the process. This kernel - needs to be nested with all the information that it needs in order to - run before it is sent to the foreman to be nested inside the - processes. - """ - - # The ID of the process to aid in ordering. - processor_id = None - - def setup(self): - """ - This method will be called once before any processing occurs, if - there is any logic that needs to be executed once per thread to - set up the process before any processing occurs that logic needs - to be placed here. - - Note: - This might have a return value of 1 for failure in the future - and a value of 0 for success so that the process can crash - silently and handle the error properly. This will be discussed - further. - - Returns: - Nothing. No return value will be handled here. - - Raises: - NotImplementedError: This will be raised if the developer - failed to extend the method. - """ - raise NotImplementedError("The setup method must be extended!") - - def process(self, data=False): - """ - This method will be called every single time the process receives - data from the main process. - - Args: - data (Optional[tuple]): Anything that you send out to all - threads through the interface object will be received - here. - - Returns: - Anything that is pickle-able that you want to send back to - your main thread. This excludes things like functions and - objects. - - Raises: - NotImplementedError: This will be raised if the developer - failed to extend the method. - """ - raise NotImplementedError("The process method must be extended!") - - -class AbstractInterface(object): - """ - This is kernel that will run inside the Interface object, this - object will be called every time the run method of the interface - is called. - - Args: - is_duplex (bool): Defines whether the object is duplex or not. - Is needed so that the foreman knows to call for duplex or - simplex processes. True if is duplex, False for simplex. - """ - - is_duplex = False - - def run(self, communicator, args): - """ - Method that is called by the interface. This will be the method - that you will use when you want to call something that - - Args: - communicator (_communication._CommunicationInterface): This - is how the interface will communicate to the threads. If - duplex is set to true this will be able to send and - receive data, if is false than will be able to receive - data only. - args (tuple): This will be whatever you sent to the run method - packaged together as a list with its index matching the - order of your arguments. - - Returns: - This can return whatever the developer needs it to return, - there are no limitations. - - Raises: - NotImplementedError: This is raised if this method isn't - overwritten by the developer before the method is sent to the - Interface Object. - """ - raise NotImplementedError("The run method must be extended!") - - -class MinimizerParserTemplate(object): - """ - - """ - - def convert(self, passed_value): - """ - - Args: - passed_value: - - Returns: - - """ - raise NotImplementedError diff --git a/PyPWA/core/templates/option_templates.py b/PyPWA/core/templates/option_templates.py deleted file mode 100644 index 8c71c594..00000000 --- a/PyPWA/core/templates/option_templates.py +++ /dev/null @@ -1,192 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" - -""" - -from PyPWA.core import tools -from PyPWA import VERSION, LICENSE, STATUS - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class _CoreOptionsParsing(object): - - _required = "required" - _optional = "optional" - _advanced = "advanced" - _kernel_processing = "kernel processing" - _minimization = "minimization" - _data_reader = "data reader" - _data_parser = "data parser" - __processed_options = tools.ProcessOptions - - def __init__(self, processed_options): - self.__processed_options = processed_options - - def _default_options(self): - raise NotImplementedError - - def _option_levels(self): - raise NotImplementedError - - def _option_types(self): - raise NotImplementedError - - def _module_comment(self): - raise NotImplementedError - - def _option_comments(self): - raise NotImplementedError - - @staticmethod - def _build_function(imports, function): - return {"function": function, "imports": set(imports)} - - def request_options(self, level): - return { - "required": self.__processed_options.required, - "optional": self.__processed_options.optional, - "advanced": self.__processed_options.advanced, - "template": self._option_types() - }[level] - - def request_metadata(self, data): - raise NotImplementedError - - -class PluginsOptionsTemplate(_CoreOptionsParsing): - - def __init__(self): - processed_options = tools.ProcessOptions( - self._plugin_name(), self._module_comment(), - self._option_comments(), self._option_types(), - self._default_options(), self._option_levels() - ) - - super(PluginsOptionsTemplate, self).__init__(processed_options) - - def _plugin_name(self): - raise NotImplementedError - - def _default_options(self): - raise NotImplementedError - - def _option_levels(self): - raise NotImplementedError - - def _option_types(self): - raise NotImplementedError - - def _module_comment(self): - raise NotImplementedError - - def _option_comments(self): - raise NotImplementedError - - def _plugin_interface(self): - raise NotImplementedError - - def _plugin_type(self): - raise NotImplementedError - - def _user_defined_function(self): - raise NotImplementedError - - def request_metadata(self, data): - return { - "name": self._plugin_name(), - "interface": self._plugin_interface(), - "provides": self._plugin_type(), - "user functions": self._user_defined_function() - }[data] - - -class MainOptionsTemplate(_CoreOptionsParsing): - - _shell_main = "main shell" - _gui_main = "main gui" - - def __init__(self): - processed_options = tools.ProcessOptions( - self._shell_id(), self._module_comment(), - self._option_comments(), self._option_types(), - self._default_options(), self._option_levels() - ) - - super(MainOptionsTemplate, self).__init__(processed_options) - - def _shell_id(self): - raise NotImplementedError - - def _default_options(self): - raise NotImplementedError - - def _option_levels(self): - raise NotImplementedError - - def _option_types(self): - raise NotImplementedError - - def _module_comment(self): - raise NotImplementedError - - def _option_comments(self): - raise NotImplementedError - - def _main_type(self): - raise NotImplementedError - - def _user_defined_function(self): - raise NotImplementedError - - def _interface_object(self): - raise NotImplementedError - - def _requires_data_parser(self): - raise NotImplementedError - - def _requires_kernel_processing(self): - raise NotImplementedError - - def _requires_minimization(self): - raise NotImplementedError - - def _requires_data_reader(self): - raise NotImplementedError - - def request_metadata(self, data): - return { - "id": self._shell_id(), - "ui": self._main_type(), - "object": self._interface_object(), - "user functions": self._user_defined_function() - }[data] - - def requires(self, the_type): - return { - self._data_parser: self._requires_data_parser(), - self._data_reader: self._requires_data_reader(), - self._kernel_processing: self._requires_kernel_processing(), - self._minimization: self._requires_minimization() - }[the_type] diff --git a/PyPWA/core/templates/option_templates.pyi b/PyPWA/core/templates/option_templates.pyi deleted file mode 100644 index ccfb09a3..00000000 --- a/PyPWA/core/templates/option_templates.pyi +++ /dev/null @@ -1,125 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import ruamel.yaml.comments - -import typing -from PyPWA.core import tools -from PyPWA import VERSION, LICENSE, STATUS - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class _CoreOptionsParsing(object): - - _required = "required" - _optional = "optional" - _advanced = "advanced" - _kernel_processing = "kernel processing" - _minimization = "minimization" - _data_reader = "data reader" - _data_parser = "data parser" - __processed_options = ... # type: tools.ProcessOptions - - def __init__(self, processed_options): - self.__processed_options = processed_options - - def _default_options(self)-> typing.Dict: ... - - def _option_levels(self) -> typing.Dict: ... - - def _option_types(self) -> typing.Dict: ... - - def _module_comment(self) -> typing.Dict: ... - - def _option_comments(self) -> typing.Dict: ... - - @staticmethod - def _build_function(imports, function) -> typing.Dict: ... - - def request_options(self, level: str) -> \ - ruamel.yaml.comments.CommentedMap: ... - - def request_metadata(self, data: str) -> object: ... - - -class PluginsOptionsTemplate(_CoreOptionsParsing): - - def __init__(self): ... - - def _plugin_name(self) -> str: ... - - def _default_options(self) -> typing.Dict: ... - - def _option_levels(self) -> typing.Dict: ... - - def _option_types(self) -> typing.Dict: ... - - def _module_comment(self) -> str: ... - - def _option_comments(self) -> typing.Dict: ... - - def _plugin_interface(self) -> object: ... - - def _plugin_type(self) -> str: ... - - def _user_defined_function(self) -> typing.Dict: ... - - def request_metadata(self, data) -> object: ... - - -class MainOptionsTemplate(_CoreOptionsParsing): - - _shell_main = "main shell" - _gui_main = "main gui" - - def __init__(self): ... - - def _shell_id(self) -> str: ... - - def _default_options(self) -> typing.Dict: ... - - def _option_levels(self) -> typing.Dict: ... - - def _option_types(self) -> typing.Dict: ... - - def _module_comment(self) -> str: ... - - def _option_comments(self) -> typing.Dict: ... - - def _main_type(self) -> str: ... - - def _user_defined_function(self) -> typing.Dict: ... - - def _interface_object(self) -> object: ... - - def _requires_data_parser(self) -> bool: ... - - def _requires_kernel_processing(self) -> bool: ... - - def _requires_minimization(self) -> bool: ... - - def _requires_data_reader(self) -> bool: ... - - def request_metadata(self, data: str) -> object: ... - - def requires(self, the_type: str) -> bool: ... diff --git a/PyPWA/core/templates/plugin_templates.py b/PyPWA/core/templates/plugin_templates.py deleted file mode 100644 index ee6f7e7b..00000000 --- a/PyPWA/core/templates/plugin_templates.py +++ /dev/null @@ -1,229 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" - -""" - -import logging -import re - -from PyPWA import VERSION, LICENSE, STATUS - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class _InitialOptions(object): - def __init__(self, options): - """ - - Args: - options: - """ - local_logger = logging.getLogger(__name__) - local_logger.addHandler(logging.NullHandler()) - - for key in list(options.keys()): - underscores = "_" + key.replace(" ", "_") - lowercase = underscores.lower() - final = re.sub(r'[^a-z0-9_]', '', lowercase) - local_logger.debug("Converted {0} to {1}".format(key, final)) - setattr(self, final, options[key]) - - -class MinimizerTemplate(_InitialOptions): - """ - Template for minimization plugins. - """ - def __init__(self, options): - """ - - Args: - options: - """ - super(MinimizerTemplate, self).__init__(options) - - def main_options(self, calc_function, fitting_type=False): - """ - - Args: - calc_function: - fitting_type: - - Returns: - - """ - raise NotImplementedError - - def start(self): - """ - - Returns: - - """ - raise NotImplementedError - - def return_parser(self): - """ - - Returns: - - """ - raise NotImplementedError - - def save_extra(self, save_name): - """ - - Args: - save_name: - - Returns: - - """ - raise NotImplementedError - - -class KernelProcessingTemplate(_InitialOptions): - """ - Template for kernel processing plugins. - """ - def __init__(self, options): - """ - - Args: - options: - """ - super(KernelProcessingTemplate, self).__init__(options) - - def main_options(self, data, process_template, interface_template): - """ - - Args: - data: - process_template: - interface_template: - - Returns: - - """ - raise NotImplementedError - - def fetch_interface(self): - """ - - Returns: - - """ - raise NotImplementedError - - -class DataParserTemplate(_InitialOptions): - """ - Template for data parser and writing plugins - """ - - def __init__(self, options): - """ - - Args: - options: - """ - super(DataParserTemplate, self).__init__(options) - - def parse(self, text_file): - """ - - Args: - text_file: - - Returns: - - """ - raise NotImplementedError - - def write(self, data, text_file): - """ - - Args: - data: - text_file: - - Returns: - - """ - raise NotImplementedError - - -class DataReaderTemplate(_InitialOptions): - """ - Template for data reader and writers plugins. - """ - - def __init__(self, options): - """ - - Args: - options: - """ - super(DataReaderTemplate, self).__init__(options) - - def return_reader(self, text_file): - """ - - Args: - text_file: - - Returns: - - """ - raise NotImplementedError - - def return_writer(self, text_file, data_shape): - """ - - Args: - text_file: - data_shape: - - Returns: - - """ - raise NotImplementedError - - -class ShellMain(_InitialOptions): - - def __init__(self, options): - """ - - Args: - options: - """ - super(ShellMain, self).__init__(options) - - def start(self): - """ - - Returns: - - """ - raise NotImplementedError diff --git a/PyPWA/core/tools.py b/PyPWA/core/tools.py deleted file mode 100644 index 880fe92a..00000000 --- a/PyPWA/core/tools.py +++ /dev/null @@ -1,251 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" - -""" - -import copy -import hashlib -import io -import logging -import os - -import appdirs -import ruamel.yaml.comments - -from PyPWA import VERSION, LICENSE, STATUS - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class ProcessOptions(object): - - _module_name = None - _module_comment = None - _option_comments = None - _option_types = None - _option_defaults = None - _option_difficulties = None - - _built_options = None - _required = None - _optional = None - _advanced = None - - def __init__( - self, module, module_comment, options_comment, - option_types, option_defaults, option_difficulty - ): - self._module_name = module - self._module_comment = module_comment - self._option_comments = options_comment - self._option_types = option_types - self._option_defaults = option_defaults - self._option_difficulties = option_difficulty - - self._set_header_into_built_options() - self._set_content_into_built_options() - self._set_difficulties() - - def _set_header_into_built_options(self): - header = ruamel.yaml.comments.CommentedMap() - header.yaml_add_eol_comment( - self._module_comment, self._module_name - ) - self._built_options = header - - def _set_content_into_built_options(self): - content = ruamel.yaml.comments.CommentedMap() - populated_content = self._add_options_defaults(content) - commented_content = self._add_option_comments(populated_content) - self._built_options[self._module_name] = commented_content - - def _add_options_defaults(self, content): - for option, value in self._option_defaults.items(): - content[option] = value - return content - - def _add_option_comments(self, content): - for option, comment in self._option_comments.items(): - content.yaml_add_eol_comment(comment, option) - return content - - def _set_difficulties(self): - self._make_separate_difficulties() - self._process_separate_difficulties() - - def _make_separate_difficulties(self): - required = copy.deepcopy(self._built_options) - optional = copy.deepcopy(self._built_options) - advanced = copy.deepcopy(self._built_options) - - self._required = required - self._optional = optional - self._advanced = advanced - - def _process_separate_difficulties(self): - for option, difficulty in self._option_difficulties.items(): - if difficulty == "optional": - self._required[self._module_name].pop(option) - elif difficulty == "advanced": - self._required[self._module_name].pop(option) - self._optional[self._module_name].pop(option) - - @property - def required(self): - return self._required - - @property - def optional(self): - return self._optional - - @property - def advanced(self): - return self._advanced - - -class DataLocation(object): - """ - Locates a place to store cache, logs, configuration, and data. - """ - _cwd = os.getcwd() - _found_uri = "" - - def get_cache_uri(self): - possible_uri = appdirs.user_cache_dir("PyPWA", "JLab", __version__) - self._find_usable_uri(possible_uri) - return self._found_uri - - def get_data_uri(self): - possible_uri = appdirs.user_data_dir("PyPWA", "JLab", __version__) - self._find_usable_uri(possible_uri) - return self._found_uri - - def get_log_uri(self): - possible_uri = appdirs.user_log_dir("PyPWA", "JLab", __version__) - self._find_usable_uri(possible_uri) - return self._found_uri - - def get_config_uri(self): - possible_uri = appdirs.user_config_dir("PyPWA", "JLab", __version__) - self._find_usable_uri(possible_uri) - return self._found_uri - - def _find_usable_uri(self, potential_uri): - self._recursively_make_uri_directories(potential_uri) - self._determine_potential_or_cwd(potential_uri) - - @staticmethod - def _recursively_make_uri_directories(potential_uri): - try: - os.makedirs(potential_uri) - except OSError: - pass - - def _determine_potential_or_cwd(self, potential_uri): - try: - self._check_writable(potential_uri) - self._found_uri = potential_uri - except OSError: - self._check_writable(self._cwd) - self._found_uri = self._cwd - - @staticmethod - def _check_writable(potential_uri): - test_file = potential_uri + "/test" - with open(test_file, "w") as stream: - stream.write("test") - os.remove(test_file) - - -class FileHashString(object): - - _logger = logging.getLogger(__name__) - _stream = io.FileIO - _hash = hashlib.md5() - _current = 0 - - def __init__(self): - """ - A simple utility that takes an io.open stream and returns its hash - """ - self._logger.addHandler(logging.NullHandler()) - - def get_sha512_hash(self, stream): - self._set_stream(stream) - self._set_hash_type(hashlib.sha512()) - return self._get_stream_hash() - - def get_sha384_hash(self, stream): - self._set_stream(stream) - self._set_hash_type(hashlib.sha384()) - return self._get_stream_hash() - - def get_sha256_hash(self, stream): - self._set_stream(stream) - self._set_hash_type(hashlib.sha256()) - return self._get_stream_hash() - - def get_sha224_hash(self, stream): - self._set_stream(stream) - self._set_hash_type(hashlib.sha224()) - return self._get_stream_hash() - - def get_sha1_hash(self, stream): - self._set_stream(stream) - self._set_hash_type(hashlib.sha1()) - return self._get_stream_hash() - - def get_md5_hash(self, stream): - self._set_stream(stream) - self._set_hash_type(hashlib.md5()) - return self._get_stream_hash() - - def _set_stream(self, stream): - self._stream = stream - - def _set_hash_type(self, hash_type): - self._hash = hash_type - - def _get_stream_hash(self): - self._record_stream_cursor_location() - self._set_location_to_file_start() - self._update_hash() - self._set_stream_to_recorded_cursor_position() - return self._get_string_from_hash() - - def _record_stream_cursor_location(self): - self._current = self._stream.tell() - - def _set_location_to_file_start(self): - self._stream.seek(0) - - def _update_hash(self): - for chunk in iter(lambda: self._stream.read(4096), b""): - self._hash.update(chunk) - - def _set_stream_to_recorded_cursor_position(self): - self._stream.seek(self._current) - - def _get_string_from_hash(self): - return self._hash.hexdigest() diff --git a/PyPWA/core/tools.pyi b/PyPWA/core/tools.pyi deleted file mode 100644 index 5d2ef405..00000000 --- a/PyPWA/core/tools.pyi +++ /dev/null @@ -1,135 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import hashlib -import io -import logging -import os -import ruamel.yaml.comments -import typing - - -class ProcessOptions(object): - - _module_name = ... # type: str - _module_comment = ... # type: str - _option_comments = ... # type: typing.Dict - _option_types = ... # type: typing.Dict - _option_defaults = ... # type: typing.Dict - _option_difficulties = ... # type: typing.Dict - - _built_options = ... # type: ruamel.yaml.comments.CommentedMap - _required = ... # type: ruamel.yaml.comments.CommentedMap - _optional = ... # type: ruamel.yaml.comments.CommentedMap - _advanced = ... # type: ruamel.yaml.comments.CommentedMap - - def __init__( - self, module: str, module_comment: str, - options_comment: typing.Dict, option_types: typing.Dict, - option_defaults: typing.Dict, option_difficulty: typing.Dict - ): ... - - def _set_header_into_built_options(self): ... - - def _set_content_into_built_options(self): ... - - def _add_options_defaults( - self, content: ruamel.yaml.comments.CommentedMap - ): ... - - def _add_option_comments( - self, content: ruamel.yaml.comments.CommentedMap - ) -> ruamel.yaml.comments.CommentedMap: ... - - def _set_difficulties(self): ... - - def _make_separate_difficulties(self): ... - - def _process_separate_difficulties(self): ... - - @property - def required(self): ... - - @property - def optional(self): ... - - @property - def advanced(self): ... - -class DataLocation(object): - - _cwd = os.getcwd() - _found_uri = "" - - def __init__(self): ... - - def get_cache_uri(self) -> str: ... - - def get_data_uri(self) -> str: ... - - def get_log_uri(self) -> str: ... - - def get_config_uri(self) -> str: ... - - def _find_usable_uri(self, potential_uri: str) -> str: ... - - @staticmethod - def _recursively_make_uri_directories(potential_uri: str): ... - - def _determine_potential_or_cwd(self, potential_uri: str): ... - - @staticmethod - def _check_writable(potential_uri: str): ... - - def _add_filename_to_uri(self, filename: str): ... - - -class FileHashString(object): - - _logger = logging.getLogger(__name__) - _stream = io.FileIO - _hash = hashlib.md5() - _current = 0 - - def __init__(self): ... - - def get_sha512_hash(self, stream: io.FileIO) -> str: ... - - def get_sha384_hash(self, stream: io.FileIO) -> str: ... - - def get_sha256_hash(self, stream: io.FileIO) -> str: ... - - def get_sha224_hash(self, stream: io.FileIO) -> str: ... - - def get_sha1_hash(self, stream: io.FileIO) -> str: ... - - def get_md5_hash(self, stream: io.FileIO) -> str: ... - - def _set_stream(self, stream: io.FileIO): ... - - def _set_hash_type(self, hash_type: hashlib.md5): ... - - def _get_stream_hash(self) -> str: ... - - def _record_stream_cursor_location(self): ... - - def _set_location_to_file_start(self): ... - - def _update_hash(self): ... - - def _set_stream_to_recorded_cursor_position(self): ... - - def _get_string_from_hash(self) -> str: ... diff --git a/PyPWA/core/wrappers.py b/PyPWA/core/wrappers.py deleted file mode 100644 index ceeb5602..00000000 --- a/PyPWA/core/wrappers.py +++ /dev/null @@ -1,193 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -This file is the main file for all of PyPWA. This file takes a -configuration file, processes it, then contacts the main module that is -requested to determine what information is needed to be loaded and how it -needs to be structured to be able to function in the users desired way. -""" - -import argparse -import logging -import sys - -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core import initial_logging - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class StartProgram(object): - def __init__(self, builder, *args): - """ - This is the wrapping object for the entry points, it takes the - object as a input, parses it, and sends the result to the builder - along with any arguments received for the builder. - - Args: - builder (PyPWA.configurator.Configurator): The object that - will build the main from the plugins and execute it to - begin the actual processing. - *args: The arguments received from the wrapper. - """ - self.builder = builder(*args) - - def start(self, configuration): - """ - The method that will be passed the function when the function is - called. - - Args: - configuration (dict): The configuration that should be passed - to the builder. - - Returns: - The final value of the wrapped function. - """ - - if configuration["extras"]: - print( - "[INFO] Caught something unaccounted for, " - "this should be reported, caught: " - "{}".format(configuration["extras"][0]) - ) - - arguments = self.parse_arguments( - configuration["description"] - ) - - if arguments.verbose: - self._return_logging_level(arguments.verbose) - else: - self._return_logging_level() - - if arguments.WriteConfig: - self.write_config(configuration, arguments) - sys.exit() - - sys.stdout.write("\x1b[2J\x1b[H") - sys.stdout.write(self._opening_art()) - - self.builder.run( - configuration, arguments.configuration - ) - - @staticmethod - def parse_arguments(description): - """ - Parses the standard arguments for the PyPWA program. - - Args: - description (str): Description for the . - - Returns: - The parsed arguments. - """ - parser = argparse.ArgumentParser( - description=description - ) - - parser.add_argument( - "configuration", type=str, default="", nargs="?" - ) - parser.add_argument( - "--WriteConfig", "-wc", action="store_true", - help="Write an example configuration to the current working " - "directory" - ) - - parser.add_argument( - "--Version", "-V", action="version", - version="%(prog)s (version " + __version__ + ")" - ) - - parser.add_argument( - "--verbose", "-v", action="count", - help="Adds logging, defaults to errors, then setups up on " - "from there. -v will include warning, -vv will show " - "warnings and info, and -vvv will show info, warnings, " - "debugging." - ) - - arguments = parser.parse_args() - - if not arguments.WriteConfig and arguments.configuration == "": - parser.print_help() - sys.exit() - - return arguments - - @staticmethod - def _return_logging_level(count=1): - """ - Sets the logging level for the program. - - Args: - count (int): The count of the logging counter. - """ - if count == 1: - initial_logging.define_logger(logging.WARNING) - elif count == 2: - initial_logging.define_logger(logging.INFO) - elif count >= 3: - initial_logging.define_logger(logging.DEBUG) - else: - initial_logging.define_logger(logging.ERROR) - - def write_config(self, function_settings, arguments): - """ - Writes the configuration files for the program. - - Args: - function_settings (dict): - arguments: The settings received from the - start function. - """ - self.builder.make_config(function_settings, arguments) - - @staticmethod - def _opening_art(): - return """\ -######### ######### ## ## ### -## ## ## ## ## ## ## ## -## ## ## ## ## ## ## ## -######### ######### ## ## ## ## ## -## ## ## ## ## #### ## ## ##### ## -## ## ## ## #### #### ## ## -## ## ## ## ## ## ## ## - ## - ## $$$$$$$$ $ $ $$$$$ $$ $$ - ### $$$ $$ $$ $ $$ $$ - $$$$$$$ $$$$$$$ $$$$$$ $$ $$ - $$$ $$ $$ $ $$ $$ - $$$$$$$$ $ $ $$$$$ $$$$$$ $$$$$$ - -Developed By: - Mark Jones: maj@jlab.org - -Credit: - Dr. Carlos Salgado: salgado@jlab.org - Will Phelps: wphelps@jlab.org - Joshua Pond -""" - diff --git a/PyPWA/entries/__init__.py b/PyPWA/entries/__init__.py index e5939ec5..a46f5a52 100644 --- a/PyPWA/entries/__init__.py +++ b/PyPWA/entries/__init__.py @@ -1,29 +1,29 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ - +Every entry point for the program is defined in this package. Currently +there is only the configurator program, but eventually there will be two +more, one for explicit arguments instead of Yml, and one for GUIs. """ -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION diff --git a/PyPWA/entries/shell.py b/PyPWA/entries/configurator.py similarity index 65% rename from PyPWA/entries/shell.py rename to PyPWA/entries/configurator.py index 12269608..9e376dec 100644 --- a/PyPWA/entries/shell.py +++ b/PyPWA/entries/configurator.py @@ -1,42 +1,37 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ -Entry point for console PyShell +Here the entry points for PyPWA are defined that use the Configuration +package. Each function is a program. """ -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core.configurator import configurator -from PyPWA.core.wrappers import StartProgram +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator.start import StartProgram -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION -initializer = StartProgram(configurator.Configurator) - +initializer = StartProgram() -def general_fitting(): - """ - """ +def py_fit(): description = u"A fitting shell that allows the User " \ u"to select their own likelihood and function." configuration = { @@ -48,10 +43,7 @@ def general_fitting(): initializer.start(configuration) -def likelihood_fitting(): - """ - - """ +def likelihood_fit(): description = u"Amplitude Fitting using the Likelihood Estimation " \ u"Method." configuration = { @@ -64,10 +56,7 @@ def likelihood_fitting(): initializer.start(configuration) -def chi_squared(): - """ - - """ +def chi_squared_fit(): description = u"Amplitude Fitting using the ChiSquared Method." configuration = { "description": description, @@ -83,10 +72,7 @@ def chi_squared(): initializer.start(configuration) -def simulator(): - """ - - """ +def py_simulate(): description = u"Simulation using the the Acceptance Reject Method." configuration = { "description": description, @@ -101,10 +87,7 @@ def simulator(): initializer.start(configuration) -def intensities(): - """ - - """ +def generate_intensities(): description = u"Generates the Intensities for Rejection Method." configuration = { "description": description, @@ -119,10 +102,7 @@ def intensities(): initializer.start(configuration) -def rejection_method(): - """ - - """ +def generate_weights(): description = u"Takes generated intensities to run through the " \ u"Rejection Method." configuration = { diff --git a/PyPWA/shell/__init__.py b/PyPWA/shell/__init__.py index 85e03432..9515dc7a 100644 --- a/PyPWA/shell/__init__.py +++ b/PyPWA/shell/__init__.py @@ -1,30 +1,47 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab +# coding=utf-8 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab # -# 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 General Public License for more details. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. # -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . """ -This module is the main module for the shell and all the things needed for -the shell to operate. +============ +Main Objects +============ + +This is where the main logic of the programs is defined. Each folder here +represents a core program and contains the main logic required for the +program to function. + +Each of the programs act as a plugin, and their metadata is stored in each +of their __init__.py files. + +- pyfit - the package that dictates how PyFit, PyLikelihood, + and PyChiSquared operate + +- pysimulate - defines how PySimulate, PyIntensities, and PyWeighting operate. + +- pyshell_functions - Defines the output functions for PyShell applications. + +There is no actual core logic defined here, data loading, processing, and +optimization is all defined elsewhere, however the algorithms used to +calculate the final values are found here. """ -from PyPWA import VERSION, LICENSE, STATUS +from PyPWA import AUTHOR, VERSION -__author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE +__author__ = AUTHOR __version__ = VERSION diff --git a/PyPWA/shell/blank/__init__.py b/PyPWA/shell/blank/__init__.py new file mode 100644 index 00000000..b9a72bd5 --- /dev/null +++ b/PyPWA/shell/blank/__init__.py @@ -0,0 +1,63 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" + +""" + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import options +from PyPWA.shell.blank import setup + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class BlankModule(options.Main): + + plugin_name = "blank shell module" + setup = setup.BlankSetup + required_plugins = [ + options.Types.DATA_PARSER + ] + + default_options = { + "Option 1": 1, + "Option 2": "A string value", + "Option 3": "Preset 1" + } + + option_difficulties = { + "Option 1": options.Levels.REQUIRED, + "Option 2": options.Levels.OPTIONAL, + "Option 3": options.Levels.ADVANCED + } + + option_types = { + "Option 1": int, + "Option 2": str, + "Option 3": ["Preset 1", "Preset 2", "Preset 3"] + } + + module_comment = "BLANK MODULE" + option_comments = { + "Option 1": "If you see this in production something went wrong.", + "Option 2": "If you see this in production something went wrong.", + "Option 3": "If you see this in production something went wrong." + } diff --git a/PyPWA/shell/blank/blank.py b/PyPWA/shell/blank/blank.py new file mode 100644 index 00000000..b4192361 --- /dev/null +++ b/PyPWA/shell/blank/blank.py @@ -0,0 +1,42 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" + +""" + +from PyPWA import AUTHOR, VERSION +from PyPWA.builtin_plugins.data import memory +from PyPWA.core.configurator import option_tools +from PyPWA.core.shared.interfaces import plugins + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class Blank(plugins.Main): + + def __init__(self, options_object): + # type: (option_tools.CommandOptions) -> None + self.__options = options_object + + def start(self): + assert isinstance(self.__options.data_parser, memory.Memory) + assert self.__options.option_1 == 123 + assert isinstance(self.__options.option_2, str) diff --git a/PyPWA/shell/blank/setup.py b/PyPWA/shell/blank/setup.py new file mode 100644 index 00000000..317580b4 --- /dev/null +++ b/PyPWA/shell/blank/setup.py @@ -0,0 +1,41 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" + +""" + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import option_tools +from PyPWA.core.configurator import options +from PyPWA.shell.blank import blank + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class BlankSetup(options.Setup): + + def __init__(self, options_object): + # type: (option_tools.CommandOptions) -> None + self.__options = options_object + + def return_interface(self): + # type: () -> blank.Blank + return blank.Blank(self.__options) diff --git a/PyPWA/shell/fitting/__init__.py b/PyPWA/shell/fitting/__init__.py deleted file mode 100644 index 30462104..00000000 --- a/PyPWA/shell/fitting/__init__.py +++ /dev/null @@ -1,127 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -This line is green in PyCharm, however in Github its blue. -""" - -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core.templates import option_templates -from PyPWA.shell.fitting import main - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class ShellFitting(option_templates.MainOptionsTemplate): - - def _user_defined_function(self): - return self._build_function("numpy", """\ - -def processing_function(the_array, the params): - pass - -def setup_function(): - pass - - """) - - def _shell_id(self): - return "shell fitting method" - - def _default_options(self): - return { - "likelihood type": "likelihood", - "generated length": 10000, - "function's location": "/path/to/the/function.py", - "processing name": "processing_function", - "setup name": "setup_function", - "qfactor location": "/path/to/the/data.csv", - "data location": "/path/to/the/data.csv", - "accepted monte carlo location": "/path/to/monte/carlo.csv", - "save name": "output" - } - - def _option_levels(self): - return { - "likelihood type": self._required, - "generated length": self._optional, - "function's location": self._required, - "processing name": self._required, - "setup name": self._required, - "qfactor location": self._optional, - "data location": self._required, - "accepted monte carlo location": self._optional, - "save name": self._required - } - - def _option_types(self): - return { - "likelihood type": ["likelihood", "chi-squared"], - "generated length": int, - "function's location": str, - "processing name": str, - "setup name": str, - "qfactor location": str, - "data location": str, - "accepted monte carlo location": str, - "save name": str - } - - def _module_comment(self): - return "The General Shell, a simple multiprocessing enabled " \ - "data analysis tool." - - def _option_comments(self): - return { - "likelihood type": - "The type of likelihood to calculate with, possible " - "values are 'likelihood' and 'chi-squared'", - "generated length": "The length of the generated data.", - "function's location": - "The location of the file that holds your defined " - "functions.", - "processing name": "The name of your main function.", - "setup name": "The name of your setup function", - "qfactor location": "The location of the qfactors.", - "data location": "The location of your data.", - "accepted monte carlo location": - "The location to your accepted monte carlo", - "save name": "The name out the output files." - } - - def _main_type(self): - return self._shell_main - - def _requires_data_parser(self): - return True - - def _requires_data_reader(self): - return False - - def _requires_kernel_processing(self): - return True - - def _requires_minimization(self): - return True - - def _interface_object(self): - return main.Fitting diff --git a/PyPWA/shell/fitting/calculations.py b/PyPWA/shell/fitting/calculations.py deleted file mode 100644 index ac1cfbdd..00000000 --- a/PyPWA/shell/fitting/calculations.py +++ /dev/null @@ -1,392 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -Holds the various likelihood calculations. -""" - -from __future__ import print_function - -import logging -import threading -import time - -try: - from queue import Queue -except ImportError: - from Queue import Queue - -import numpy -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core.templates import interface_templates - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class _CoreProcessingKernel(interface_templates.AbstractKernel): - - def __init__(self, setup_function, processing_function): - """ - - Args: - setup_function: - processing_function: - """ - self._setup_function = setup_function - self._processing_function = processing_function - - def setup(self): - """ - - Returns: - - """ - if self._setup_function: - self._setup_function() - - def process(self, data=False): - """ - - Args: - data: - - Returns: - - """ - raise NotImplementedError - - -class ExtendedLikelihoodAmplitude(_CoreProcessingKernel): - - def __init__( - self, setup_function, processing_function, generated_length - ): - """ - - Args: - setup_function: - processing_function: - generated_length: - """ - super(ExtendedLikelihoodAmplitude, self).__init__( - setup_function, processing_function - ) - - self._processed = 1.0/generated_length - self.data = None # type: numpy.ndarray - self.monte_carlo = None # type: numpy.ndarray - self.qfactor = 1 # type: numpy.ndarray - - def process(self, data=False): - """ - - Args: - data: - - Returns: - - """ - processed_data = self._processing_function(self.data, data) - processed_monte_carlo = self._processing_function( - self.monte_carlo, data - ) - return self._likelihood(processed_data, processed_monte_carlo) - - def _likelihood(self, data, accepted): - """ - Calculates the extended likelihood function - - Args: - data: - accepted: - """ - if numpy.any(data == 0): - print("WARNING, Found Zeros! " + repr( - numpy.count_nonzero(data == 0) - )) - value = -(numpy.sum(self.qfactor * numpy.log(data))) + \ - (self._processed * numpy.sum(accepted)) - - return value - - -class UnextendedLikelihoodAmplitude(_CoreProcessingKernel): - - def __init__(self, setup_function, processing_function): - """ - - Args: - setup_function: - processing_function: - """ - super(UnextendedLikelihoodAmplitude, self).__init__( - setup_function, processing_function - ) - - self.data = None # type: numpy.ndarray - self.qfactor = 1 # type: numpy.ndarray - self.binned = 1 # type: numpy.ndarray - - def process(self, data=False): - """ - - Args: - data: - - Returns: - - """ - processed_data = self._processing_function(self.data, data) - return self._likelihood(processed_data) - - def _likelihood(self, data): - """ - Calculates the binned likelihood function - - Args: - data: - """ - value = -( - numpy.sum(self.qfactor * self.binned * numpy.log(data)) - ) - return value - - -class Chi(_CoreProcessingKernel): - - def __init__(self, setup_function, processing_function): - """ - - Args: - setup_function: - processing_function: - """ - super(Chi, self).__init__(setup_function, processing_function) - - self.data = None # type: numpy.ndarray - self.binned = None # type: numpy.ndarray - - def process(self, data=False): - """ - - Args: - data: - - Returns: - - """ - processed_data = self._processing_function(self.data, data) - return self._likelihood(processed_data) - - def _likelihood(self, data): - """ - Calculates the ChiSquare function - - Args: - data: - """ - return ((data - self.binned)**2) / self.binned - - -class FittingInterfaceKernel(interface_templates.AbstractInterface): - - is_duplex = True - - def __init__(self, minimizer_function): - """ - - Args: - minimizer_function (interface_templates.MinimizerParserTemplate): - """ - self._logger = logging.getLogger(__name__) - - self._parameter_parser = minimizer_function - self._last_value = None - self._send_queue = Queue() - self._receive_queue = Queue() - self._times = [] - self._thread = None - - def run(self, communication, *args): - """ - This is the function is called by minuit and acts as a wrapper for - the users function - - Args: - communication: Communication Pipes - *args: The parameters in list format - - Returns: - float: The final value from the likelihood function - """ - self._output_handler() - - parsed_arguments = self._parameter_parser.convert(args) - - for pipe in communication: - pipe.send(parsed_arguments) - - values = numpy.zeros(shape=len(communication)) - - for index, pipe in enumerate(communication): - values[index] = pipe.receive() - - final_value = numpy.sum(values) - self._last_value = final_value - self._output_handler(True) - self._logger.info("Final Value is: %f15" % final_value) - return final_value - - def _output_handler(self, end=False): - """ - - Args: - end: - - Returns: - - """ - if end: - self._kill_thread() - else: - self._create_thread() - - def _kill_thread(self): - """ - - Returns: - - """ - self._send_queue.put("die") - self._times.append(float(self._receive_queue.get())) - - def _average_time(self): - """ - - Returns: - - """ - if len(self._times) > 0: - return sum(self._times) / len(self._times) - else: - return 0 - - def _create_thread(self): - """ - - Returns: - - """ - if len(self._times) == 0: - last_time = 0 - else: - last_time = self._times[-1] - - self._thread = OutputThread( - self._receive_queue, self._send_queue, - self._last_value, last_time, self._average_time() - ) - self._thread.start() - - -class OutputThread(threading.Thread): - - def __init__( - self, send_queue, receive_queue, last_value, - last_time, average_time - ): - """ - - Args: - send_queue: - receive_queue: - last_value: - last_time: - average_time: - """ - self._output_pulse = "-" - self._send_queue = send_queue - self._receive_queue = receive_queue - self._last_value = last_value - self._last_time = last_time - self._average_time = average_time - self._initial_time = time.time() - super(OutputThread, self).__init__() - - def _pulse(self): - """ - - Returns: - - """ - if self._output_pulse is "-": - self._output_pulse = "/" - elif self._output_pulse is "/": - self._output_pulse = "\\" - elif self._output_pulse is "\\": - self._output_pulse = "-" - - def _create_output(self): - """ - - Returns: - - """ - self._pulse() - - current_time = time.time() - self._initial_time - - if isinstance(self._last_value, type(None)): - string = "Elapsed time: {0:.2f} {1}".format( - current_time, self._output_pulse - ) - else: - string = "Last Value: {0}, Average Time: {1:.4f}, " \ - "Elapsed Time: {2:.2f} {3}".format( - self._last_value, self._average_time, - current_time, self._output_pulse - ) - - return string - - def _return_time(self): - """ - - Returns: - - """ - self._receive_queue.get() - current_time = time.time() - self._initial_time - self._send_queue.put(current_time) - - def run(self): - """ - - Returns: - - """ - while True: - if not self._receive_queue.empty(): - self._return_time() - break - time.sleep(.05) - print("\r" + self._create_output(), end="\r") diff --git a/PyPWA/shell/fitting/main.py b/PyPWA/shell/fitting/main.py deleted file mode 100644 index 5695a23a..00000000 --- a/PyPWA/shell/fitting/main.py +++ /dev/null @@ -1,329 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -Holds the various likelihood calculations. -""" - -import logging -import os - -import numpy -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core import plugin_loader -from PyPWA.core.templates import plugin_templates -from PyPWA.shell.fitting import calculations - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class Fitting(plugin_templates.ShellMain): - - _logger = logging.getLogger(__name__) - _data_parser = None - _minimization = None - _kernel_processing = None - _likelihood_type = None - _generated_length = None - _functions_location = None - _processing_name = None - _setup_name = None - _data_location = None - _accepted_monte_carlo_location = None - _qfactor_location = None - _save_name = None - _monte_carlo_raw_data = None # type: numpy.ndarray - _qfactor_data = None # type: numpy.ndarray - _data_raw_data = None # type: numpy.ndarray - _corrected_data = None # type: dict - _processing_function = None # type: object - _setup_function = None # type: object - - def __init__( - self, data_parser=None, minimization=None, - kernel_processing=None, likelihood_type=None, - generated_length=None, functions_location=None, - processing_name=None, setup_name=None, data_location=None, - qfactor_location=None, accepted_monte_carlo_location=None, - save_name=None, **options - ): - """ - - Args: - data_parser (plugin_templates.DataParserTemplate): - minimization (plugin_templates.MinimizerTemplate): - kernel_processing (plugin_templates.KernelProcessingTemplate): - likelihood_type (str): - generated_length (int): - functions_location (str): - processing_name (str): - setup_name (str): - data_location (str): - accepted_monte_carlo_location (str): - save_name (str): - options (dict): - """ - - self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) - - self._data_parser = data_parser - self._minimization = minimization - self._kernel_processing = kernel_processing - self._likelihood_type = likelihood_type - self._generated_length = generated_length - self._functions_location = functions_location - self._processing_name = processing_name - self._setup_name = setup_name - self._data_location = data_location - self._accepted_monte_carlo_location \ - = accepted_monte_carlo_location - self._qfactor_location = qfactor_location - self._save_name = save_name - if options: - super(Fitting, self).__init__(options) - - def _check_params(self): - """ - - Returns: - - """ - if isinstance(self._functions_location, type(None)): - raise ValueError( - "Received nothing for the function's location! \n" - "Set 'function's location' under 'General Fitting'" - ) - if not os.path.exists(os.path.abspath(self._functions_location)): - raise ValueError( - "The 'function's location' doesn't point to a valid path!" - ) - - def _load_data(self): - """ - - Returns: - - """ - self._logger.info("Found data.") - self._data_raw_data = self._data_parser.parse(self._data_location) - - if self._accepted_monte_carlo_location: - self._logger.info("Found monte carlo.") - self._monte_carlo_raw_data = self._data_parser.parse( - self._accepted_monte_carlo_location - ) - - if self._qfactor_location: - self._logger.info("Found QFactor.") - self._qfactor_data = self._data_parser.parse( - self._qfactor_location - ) - - def _setup_data(self): - """ - - Returns: - - """ - corrected = {} - - self._logger.info("Corrected data.") - corrected_data = self._filter_data( - self._data_raw_data, "data" - ) - - data_length = len( - corrected_data["data"][corrected_data["data"].dtype.names[0]] - ) - - if isinstance(self._monte_carlo_raw_data, numpy.ndarray): - self._logger.info("Corrected monte carlo") - corrected_monte_carlo = self._filter_data( - self._monte_carlo_raw_data, "monte_carlo" - ) - - corrected["monte_carlo"] \ - = corrected_monte_carlo["monte_carlo"] - - if isinstance(self._qfactor_data, numpy.ndarray): - self._logger.info("Merging QFactors") - corrected["qfactor"] = self._qfactor_data - elif "qfactor" in corrected_data.keys(): - self._logger.info("Extracted QFactors") - corrected["qfactor"] = corrected_data["qfactor"] - else: - self._logger.info("No QFactor found, defaulting to ones.") - corrected["qfactor"] = numpy.ones(data_length) - - if "binned" in corrected_data.keys(): - self._logger.info("Found binned data.") - corrected["binned"] = corrected_data["binned"] - else: - self._logger.info("No binned data found, defaulting to ones.") - corrected["binned"] = numpy.ones(data_length) - - corrected["data"] = corrected_data["data"] - self._logger.debug("Corrected data: " + repr(corrected)) - self._corrected_data = corrected - - def _load_functions(self): - """ - - Returns: - - """ - loader = plugin_loader.SingleFunctionLoader( - self._functions_location - ) - - self._processing_function = loader.fetch_function( - self._processing_name, True - ) - - self._setup_function = loader.fetch_function( - self._setup_name, False - ) - - def start(self): - """ - - Returns: - - """ - self._check_params() - self._load_data() - self._setup_data() - self._load_functions() - - minimizer_parser = self._minimization.return_parser() - - interface_kernel = calculations.FittingInterfaceKernel( - minimizer_parser - ) - - if self._likelihood_type is "chi-squared": - self._start_chi(interface_kernel) - else: - self._start_likelihood(interface_kernel) - - def _start_chi(self, interface_kernel): - """ - - Args: - interface_kernel: - - Returns: - - """ - self._logger.info("Using likelihood: chi-squared") - - chi_kernel = calculations.Chi( - self._setup_function, self._processing_function - ) - - self._kernel_processing.main_options( - self._corrected_data, chi_kernel, interface_kernel - ) - - interface = self._kernel_processing.fetch_interface() - - self._the_end(interface, "chi-squared") - - def _start_likelihood(self, interface_kernel): - """ - - Args: - interface_kernel: - - Returns: - - """ - if "monte_carlo" in list(self._corrected_data.keys()): - self._logger.info("Using likelihood: Extended Likelihood") - - kernel = calculations.ExtendedLikelihoodAmplitude( - self._setup_function, self._processing_function, - self._generated_length - ) - else: - self._logger.info( - "Using likelihood: Unextended binned likelihood" - ) - - kernel = calculations.UnextendedLikelihoodAmplitude( - self._setup_function, self._processing_function - ) - - self._kernel_processing.main_options( - self._corrected_data, kernel, interface_kernel - ) - - interface = self._kernel_processing.fetch_interface() - - self._the_end(interface, "likelihood") - - def _the_end(self, interface, fitting_type): - """ - - Args: - interface (interface_: - - Returns: - - """ - self._minimization.main_options(interface.run, fitting_type) - - self._minimization.start() - interface.stop() - self._minimization.save_extra(self._save_name) - - @staticmethod - def _filter_data(array, main_name): - """ - - Args: - array (numpy.ndarray): - - Returns: - - """ - if "BinN" in array.dtype.names: - where_zero = numpy.where(array["BinN"] == 0)[0] - - for key in array.dtype.names: - array[key] = numpy.delete(array[key], where_zero) - - names_list = list(array.dtype.names) - segregated_data = {} - - if "QFactor" in names_list: - names_list.remove("QFactor") - segregated_data["qfactor"] = array["QFactor"] - - if "BinN" in names_list: - names_list.remove("BinN") - segregated_data["binned"] = array["BinN"] - - segregated_data[main_name] = array[names_list] - - return segregated_data diff --git a/PyPWA/shell/loaders.py b/PyPWA/shell/loaders.py new file mode 100644 index 00000000..196493cf --- /dev/null +++ b/PyPWA/shell/loaders.py @@ -0,0 +1,231 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Shared logic between PyFit and PySimulate +----------------------------------------- + +- DataLoading - takes a data parsing object and use it to load data + for the two programs in a way that the data can be easily repacked into + processes. + +- FunctionLoader - used to load the setup and processing functions in a + predictable way. +""" + +import logging +import os +from typing import Optional as Opt +from typing import Union + +import numpy +from numpy import ndarray + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.shared import plugin_loader +from PyPWA.core.shared.interfaces import plugins +from PyPWA.shell import shell_types + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class DataLoading(object): + + __LOGGER = logging.getLogger(__name__ + ".DataLoading") + + def __init__( + self, + parser, # type: plugins.DataParser + data, # type: str + internal_data=None, # type: Opt[Dict[str, str]] + qfactor=None, # type: Opt[str] + monte_carlo=None # type: Opt[str] + ): + # type: (...) -> None + self._parser = parser + self._data_file = data + self._qfactor_file = qfactor + self._monte_carlo_file = monte_carlo + if internal_data: + self.__internal_names = internal_data + else: + self.__internal_names = dict() + self.__data = None # type: ndarray + self.__qfactor = None # type: ndarray + self.__monte_carlo = None # type: ndarray + self.__binned = None # type: ndarray + self.__event_errors = None # type: ndarray + self.__expected_values = None # type: ndarray + self.__load_data() + + def __load_data(self): + self.__parse_data_file() + self.__process_data() + self.__parse_qfactor_file() + self.__parse_monte_carlo_file() + + def __parse_data_file(self): + if self.__is_file(self._data_file): + self.__LOGGER.info("Loading data.") + self.__data = self._parser.parse(self._data_file) + else: + raise ValueError('"' + self._data_file + '"' + " is not a file!") + + def __process_data(self): + if "quality factor" in self.__internal_names: + self.__qfactor = self.__extract_data( + self.__internal_names["quality factor"] + ) + else: + self.__qfactor = self.__extract_data("qfactor") + + if "binned data" in self.__internal_names: + self.__binned = self.__extract_data( + self.__internal_names["binned data"] + ) + else: + self.__binned = self.__extract_data("BinN") + + if "event errors" in self.__internal_names: + self.__event_errors = self.__extract_data( + self.__internal_names["event errors"] + ) + + if "expected values" in self.__internal_names: + self.__expected_values = self.__extract_data( + self.__internal_names["expected values"] + ) + + def __extract_data(self, column): + # type: (str) -> ndarray + names = list(self.__data.dtype.names) + if column in names: + self.__LOGGER.info("Extracting '%s' from data." % column) + names.remove(column) + data = self.__data[column] + self.__data = self.__data[names] + else: + data = numpy.ones(len(self.__data)) + + return data + + def __parse_qfactor_file(self): + if self.__is_file(self._qfactor_file): + self.__LOGGER.info("Loading QFactor data.") + self.__qfactor = self._parser.parse(self._qfactor_file) + elif self.__qfactor is None: + self.__qfactor = numpy.ones(len(self.__data)) + + def __parse_monte_carlo_file(self): + if self.__is_file(self._monte_carlo_file): + self.__LOGGER.info("Loading Monte Carlo Data.") + self.__monte_carlo = self._parser.parse(self._monte_carlo_file) + else: + self.__monte_carlo = None + + @staticmethod + def __is_file(file_location): + # type: (str) -> bool + if isinstance(file_location, str) and os.path.isfile(file_location): + return True + else: + return False + + def write(self, file_location, data): + # type: (str, ndarray) -> None + self._parser.write(file_location, data) + + @property + def data(self): + # type: () -> ndarray + return self.__data + + @property + def qfactor(self): + # type: () -> ndarray + return self.__qfactor + + @property + def monte_carlo(self): + # type: () -> Union[ndarray, None] + return self.__monte_carlo + + @property + def binned(self): + # type: () -> ndarray + return self.__binned + + @property + def event_errors(self): + # type: () -> ndarray + return self.__event_errors + + @property + def expected_values(self): + # type: () -> ndarray + return self.__expected_values + + +class FunctionLoader(object): + + __LOGGER = logging.getLogger(__name__ + ".FunctionLoader") + + def __init__(self, location, process_name, setup_name=None): + # type: (str, str, Opt[str]) -> None + self.__loader = plugin_loader.PluginLoader() + self.__loader.add_plugin_location(location) + self.__process_name = process_name + self.__setup_name = setup_name + self.__process = None # type: shell_types.users_processing + self.__setup = None # type: shell_types.users_setup + self.__load_functions() + + def __load_functions(self): + self.__load_process() + self.__load_setup() + + def __load_process(self): + self.__process = self.__loader.get_by_name(self.__process_name) + + def __load_setup(self): + if isinstance(self.__setup_name, str): + self.__setup = self.__loader.get_by_name(self.__setup_name, False) + self.__LOGGER.debug("Found setup type %s" % repr(self.__setup)) + self.__set_none_to_empty() + + def __set_none_to_empty(self): + if self.__setup is None: + self.__LOGGER.info("No setup function found, settings to empty.") + self.__setup = self.__empty + + @staticmethod + def __empty(): + # type: () -> None + pass + + @property + def process(self): + # type: () -> shell_types.users_processing + return self.__process + + @property + def setup(self): + # type: () -> shell_types.users_setup + return self.__setup diff --git a/PyPWA/shell/pyfit/__init__.py b/PyPWA/shell/pyfit/__init__.py new file mode 100644 index 00000000..8a7a6c1c --- /dev/null +++ b/PyPWA/shell/pyfit/__init__.py @@ -0,0 +1,116 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +PyFit, LikelihoodFitting, and ChiSquaredFitting +----------------------------------------------- +PyFit is a simple fitting tool that can use multiple processes depending on +the processing module that is picked. + +- likelihoods - the various builtin likelihoods the PyFit supports. + +- _processing_interface - PyFits interface with the processing package, also + handles the output mechanism in a second thread. + +- interfaces - the interfaces that need to be extended to define a new + likelihood function. + +- initial_setup - how the configurator package interfaces the PyFit + Main object. + +- pyfit - the main object and the likelihood loading object are contained. +""" + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import options +from PyPWA.shell import pyshell_functions +from PyPWA.shell.pyfit import intial_setup +from PyPWA.shell.pyfit import pyfit + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class ShellFitting(options.Main): + + __likelihood_loader = pyfit.LikelihoodPackager() + + plugin_name = "shell fitting method" + setup = intial_setup.FittingSetup + defined_function = pyshell_functions.ShellFunctionFile + required_plugins = [ + options.Types.OPTIMIZER, + options.Types.DATA_PARSER, + options.Types.KERNEL_PROCESSING + ] + + default_options = { + "likelihood type": "likelihood", + "generated length": 10000, + "function's location": "/path/to/the/function.py", + "processing name": "processing_function", + "setup name": "setup_function", + "qfactor location": None, + "data location": "/path/to/the/data.csv", + "internal data": {"quality factor": "Qfactors"}, + "accepted monte carlo location": None, + "save name": "output" + } + + option_difficulties = { + "likelihood type": options.Levels.REQUIRED, + "generated length": options.Levels.OPTIONAL, + "function's location": options.Levels.REQUIRED, + "processing name": options.Levels.REQUIRED, + "setup name": options.Levels.REQUIRED, + "qfactor location": options.Levels.OPTIONAL, + "data location": options.Levels.REQUIRED, + "internal data": options.Levels.OPTIONAL, + "accepted monte carlo location": options.Levels.OPTIONAL, + "save name": options.Levels.REQUIRED + } + + option_types = { + "likelihood type": __likelihood_loader.get_likelihood_name_list(), + "generated length": int, + "function's location": str, + "processing name": str, + "setup name": str, + "qfactor location": str, + "data location": str, + "internal data": dict, + "accepted monte carlo location": str, + "save name": str + } + + module_comment = "PyFit, a simple python data analysis tool." + option_comments = { + "likelihood type": + "Likelihood to use: Chi-Squared, Likelihood, or Empty", + "generated length": "The number of generated events", + "function's location": "The path of your functions file", + "processing name": "The name of your processing function.", + "setup name": "The name of your setup function.", + "qfactor location": "The path of the qfactors file.", + "data location": "The path of your data file.", + "internal data": "Internal name mapping.", + "accepted monte carlo location": + "The path to your accepted monte carlo file", + "save name": "The name out the output files." + } diff --git a/PyPWA/shell/pyfit/_process_interface.py b/PyPWA/shell/pyfit/_process_interface.py new file mode 100644 index 00000000..01850fd1 --- /dev/null +++ b/PyPWA/shell/pyfit/_process_interface.py @@ -0,0 +1,214 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Processing and Output +--------------------- +This is where the processing interface is defined along with the automated +output from the the parallel thread. + +- _ThreadInterface - The object between the main thread and the output thread. + +- _OutputThread - The actual output thread, its started with each call to the + likelihood. Has a 1hz output rate. + +- FittingInterface - The interface between the Likelihood Kernels and the + optimizer module. +""" + +from __future__ import print_function + +try: + from queue import Queue +except ImportError: + from Queue import Queue + +import numpy +import logging +import time +import threading + +from PyPWA.core.shared.interfaces import internals + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class _ThreadInterface(object): + + __logger = logging.getLogger(__name__ + "_ThreadInterface") + __root_logger = logging.getLogger() + __send_queue = Queue() + __receive_queue = Queue() + __times = [] + __initial_time = None + __enabled = False + + def __init__(self): + self.__initial_time = time.time() + + if not self.__root_logger.isEnabledFor(logging.INFO): + self.__enabled = True + else: + self.__logger.info( + "Processor Output is disabled while info logging is enabled" + ) + + def start(self, last_value): + if self.__enabled: + thread = _OutputThread( + self.__receive_queue, self.__send_queue, + last_value, self.__get_last_time(), self.__average_time(), + self.__initial_time + ) + + thread.start() + + def __get_last_time(self): + if len(self.__times) == 0: + return 0 + else: + return self.__times[-1] + + def __average_time(self): + if len(self.__times) == 0: + return 0 + else: + return sum(self.__times) / len(self.__times) + + def stop(self): + if self.__enabled: + self.__send_queue.put("die") + self.__times.append(float(self.__receive_queue.get())) + + +class _OutputThread(threading.Thread): + + __output_pulse = "-" + __send_queue = None # type: Queue + __receive_queue = None # type: Queue + __last_value = None # type: numpy.float64 + __last_time = None # type: float + __average_time = None # type: float + __initial_time = None # type: float + __start_time = None + __index = None + + def __init__( + self, send_queue, receive_queue, last_value, + last_time, average_time, start_time + ): + self.__send_queue = send_queue + self.__receive_queue = receive_queue + self.__last_value = last_value + self.__last_time = last_time + self.__average_time = average_time + self.__start_time = start_time + self.__initial_time = time.time() + super(_OutputThread, self).__init__() + + def run(self): + while True: + if not self.__receive_queue.empty(): + self.__send_runtime() + break + self.__output() + + def __output(self): + print("\r" + self.__create_output(), end="\r") + + def __create_output(self): + if isinstance(self.__last_value, type(None)): + return self.__simple_output() + else: + return self.__full_output() + + def __simple_output(self): + self.__pulse() + runtime = self.__get_current_runtime() + return "Elapsed time: {0: .2f} {1}".format( + runtime, self.__output_pulse + ) + + def __full_output(self): + self.__pulse() + runtime = self.__get_current_runtime() + return "Last Value: {0: .3f}, Average Time: {1: .2f}, " \ + "Elapsed Time: {2: .2f}, " \ + "Total Runtime {3: .2f} {4}".format( + self.__last_value, self.__average_time, + runtime, self.__get_total_runtime(), self.__output_pulse + ) + + def __get_current_runtime(self): + return time.time() - self.__initial_time + + def __get_total_runtime(self): + return time.time() - self.__start_time + + def __pulse(self): + if self.__output_pulse is "-": + self.__output_pulse = "/" + elif self.__output_pulse is "/": + self.__output_pulse = "\\" + elif self.__output_pulse is "\\": + self.__output_pulse = "-" + + def __send_runtime(self): + self.__receive_queue.get() + self.__send_queue.put(self.__get_current_runtime()) + + +class FittingInterface(internals.KernelInterface): + + IS_DUPLEX = True + __logger = logging.getLogger(__name__ + ".FittingInterfaceKernel") + __parameter_parser = None # type: internals.OptimizerOptionParser + __last_value = None # type: numpy.float64 + __thread_interface = None + + def __init__(self, minimizer_function): + self.__parameter_parser = minimizer_function + self.__thread_interface = _ThreadInterface() + + def run(self, communication, *args): + self.__send_arguments(communication, args) + self.__thread_interface.start(self.__last_value) + self.__get_final_value(communication) + self.__thread_interface.stop() + self.__log_final_value() + return self.__last_value + + def __send_arguments(self, communication, args): + parsed_arguments = self.__parameter_parser.convert(args) + + for pipe in communication: + pipe.send(parsed_arguments) + + def __get_final_value(self, communication): + values = numpy.zeros(shape=len(communication)) + for index, pipe in enumerate(communication): + values[index] = pipe.receive() + final_value = numpy.sum(values) + self.__last_value = self.__parameter_parser.MULTIPLIER * final_value + + def __log_final_value(self): + self.__logger.info("Final Value is: %f15" % self.__last_value) diff --git a/PyPWA/shell/pyfit/interfaces.py b/PyPWA/shell/pyfit/interfaces.py new file mode 100644 index 00000000..f0027be8 --- /dev/null +++ b/PyPWA/shell/pyfit/interfaces.py @@ -0,0 +1,79 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +These are the interfaces needed to define a new likelihood. +----------------------------------------------------------- + +- Likelihood - used for the actual algorithm to calculate the likelihood. + +- Setup - used to define how to interact with the likelihood and the name of + the likelihood. +""" + +from typing import Any, Dict +from typing import Optional as Opt + +import numpy + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.shared.interfaces import internals +from PyPWA.shell import loaders +from PyPWA.shell import shell_types + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class Likelihood(internals.Kernel): + + def __init__(self, setup_function=None): + # type: (shell_types.users_setup) -> None + self.__setup_function = setup_function + + def setup(self): + # type: () -> None + if self.__setup_function: + self.__setup_function() + + def process(self, data=False): + # type: (Dict[str, numpy.float64]) -> numpy.float64 + raise NotImplementedError + + +class Setup(object): + + NAME = NotImplemented + + def setup_likelihood( + self, + data_package, # type: loaders.DataLoading + function_package, # type: loaders.FunctionLoader + extra_info=None # type: Opt[Dict[str, Any]] + ): + # type: (...) -> None + raise NotImplementedError + + def get_likelihood(self): + # type: () -> Likelihood + raise NotImplementedError + + def get_data(self): + # type: () -> Dict[str, numpy.ndarray] + raise NotImplementedError diff --git a/PyPWA/shell/pyfit/intial_setup.py b/PyPWA/shell/pyfit/intial_setup.py new file mode 100644 index 00000000..cee36dc7 --- /dev/null +++ b/PyPWA/shell/pyfit/intial_setup.py @@ -0,0 +1,70 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Defines how the configurator will interact with PyFit. +""" + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import options +from PyPWA.shell import loaders +from PyPWA.shell.pyfit import pyfit + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class FittingSetup(options.Setup): + + def __init__(self, options_object): + self.__options = options_object + self.__interface = None # type: pyfit.Fitting + self.__data_loader = None # type: loaders.DataLoading + self.__functions = None # type: loaders.FunctionLoader + self.__run_setup() + + def __run_setup(self): + self.__load_data() + self.__load_functions() + self.__setup_interface() + + def __load_data(self): + self.__data_loader = loaders.DataLoading( + self.__options.data_parser, self.__options.data_location, + self.__options.internal_data, self.__options.qfactor_location, + self.__options.accepted_monte_carlo_location + ) + + def __load_functions(self): + self.__functions = loaders.FunctionLoader( + self.__options.functions_location, self.__options.processing_name, + self.__options.setup_name + ) + + def __setup_interface(self): + self.__interface = pyfit.Fitting( + self.__options.optimizer, self.__options.kernel_processing, + self.__data_loader, self.__functions, + self.__options.likelihood_type, self.__options.generated_length, + self.__options.save_name + ) + + def return_interface(self): + # type: () -> pyfit.Fitting + return self.__interface diff --git a/PyPWA/shell/pyfit/likelihoods/__init__.py b/PyPWA/shell/pyfit/likelihoods/__init__.py new file mode 100644 index 00000000..e207e59d --- /dev/null +++ b/PyPWA/shell/pyfit/likelihoods/__init__.py @@ -0,0 +1,45 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Builtin Likelihoods +------------------- +This package contains all of PyFit's likelihoods that it supports out of the +box. + +None of these likelihoods are actually explicitly stated in the program, +instead the likelihoods are dynamically loaded from this package using +PyPWA's builtin plugin loader, meaning that a new likelihood can be defined +here without it ever needing to adjust any of the already defined objects. + +.. note:: + In the docs for each likelihood the actual formula for each likelihood + is defined. To clarify some symbols: + + - I°() = Intensity, this would be the function passed by the user. + - D = The data loaded for the function. + - MC = The acceptance data. + - B = Binned data. + - Q = QFactor Data. +""" + +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION diff --git a/PyPWA/shell/pyfit/likelihoods/chi_squared.py b/PyPWA/shell/pyfit/likelihoods/chi_squared.py new file mode 100644 index 00000000..8ce3cf1e --- /dev/null +++ b/PyPWA/shell/pyfit/likelihoods/chi_squared.py @@ -0,0 +1,143 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +The ChiSquared Likelihood is defined here: +------------------------------------------ +- Σ(((I°(D) - B)^2) / B) +""" + +from typing import Optional as Opt +from typing import Any, Dict + +import numpy + +from PyPWA import AUTHOR, VERSION +from PyPWA.shell import loaders +from PyPWA.shell.pyfit import interfaces +from PyPWA.shell import shell_types + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class ChiLikelihood(interfaces.Setup): + + NAME = "chi-squared" + + def __init__(self): + super(ChiLikelihood, self).__init__() + self.__data = dict() # type: Dict[str, numpy.ndarray] + self.__likelihood = None # type: interfaces.Likelihood + + def setup_likelihood( + self, + data_package, # type: loaders.DataLoading + function_package, # type: loaders.FunctionLoader + extra_info=None # type: Opt[Dict[str, Any]] + ): + # type: (...) -> None + self.__setup_data(data_package) + self.__setup_likelihood(function_package) + + def __setup_data(self, data_package): + # type: (loaders.DataLoading) -> None + self.__data["data"] = data_package.data + self.__data["qfactor"] = data_package.qfactor + self.__data["binned"] = data_package.binned + self.__data["event errors"] = data_package.event_errors + self.__data["expected values"] = data_package.expected_values + + def __setup_likelihood(self, function_package): + # type: (loaders.FunctionLoader) -> None + if not numpy.all(self.__data.binned == 1): + self.__setup_chi(function_package) + elif self.__data["event errors"] and self.__data["expected values"]: + self.__setup_unbinned_chi(function_package) + else: + raise ValueError( + "Given UnBinned data without expected value and error" + ) + + def __setup_chi(self, function_package): + # type: (loaders.FunctionLoader) -> None + self._likelihood = Chi( + function_package.setup, function_package.process + ) + + def __setup_unbinned_chi(self, function_package): + # type: (loaders.FunctionLoader) -> None + self._likelihood = UnBinnedChi( + function_package.setup, function_package.process + ) + + def get_data(self): + # type: () -> Dict[str, numpy.ndarray] + return self.__data + + def get_likelihood(self): + # type: () -> interfaces.Likelihood + return self.__likelihood + + +class Chi(interfaces.Likelihood): + + def __init__( + self, + setup_function, # type: shell_types.users_setup + processing_function # type: shell_types.users_processing + ): + # type: (...) -> None + super(Chi, self).__init__(setup_function) + self.__processing_function = processing_function + self.data = None # type: numpy.ndarray + self.binned = None # type: numpy.ndarray + + def process(self, data=False): + # type: (Dict[str, float]) -> float + processed_data = self.__processing_function(self.data, data) + return self.__likelihood(processed_data) + + def __likelihood(self, data): + # type: (numpy.ndarray) -> float + return numpy.sum(((data - self.binned)**2) / self.binned) + + +class UnBinnedChi(interfaces.Likelihood): + + def __init__( + self, + setup_function, # type: shell_types.users_setup + processing_function # type: shell_types.users_processing + ): + # type: (...) -> None + super(UnBinnedChi, self).__init__(setup_function) + self.__processing_function = processing_function + self.data = None # type: numpy.ndarray + self.expected = None # type: numpy.ndarray + self.error = None # type: numpy.ndarray + + def process(self, data=False): + # type: (Dict[str, float]) -> float + processed_data = self.__processing_function(self.data, data) + return self.__likelihood(processed_data) + + def __likelihood(self, data): + # type: (numpy.ndarray) -> float + return numpy.sum(((data - self.expected)**2) / self.error) diff --git a/PyPWA/shell/pyfit/likelihoods/empty.py b/PyPWA/shell/pyfit/likelihoods/empty.py new file mode 100644 index 00000000..b593db97 --- /dev/null +++ b/PyPWA/shell/pyfit/likelihoods/empty.py @@ -0,0 +1,91 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +The Empty likelihood is defined here: +------------------------------------- +- Σ(I°(D)) +""" + +from typing import Any, Dict +from typing import Optional as Opt + +import numpy + +from PyPWA import AUTHOR, VERSION +from PyPWA.shell import loaders +from PyPWA.shell import shell_types +from PyPWA.shell.pyfit import interfaces + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class EmptyLikelihood(interfaces.Setup): + + NAME = "empty" + + def __init__(self): + super(EmptyLikelihood, self).__init__() + self.__data = dict() + self.__likelihood = None # type: interfaces.Likelihood + + def setup_likelihood( + self, + data_package, # type: loaders.DataLoading + function_package, # type: loaders.FunctionLoader + extra_info=None # type: Opt[Dict[str, Any]] + ): + # type: (...) -> None + self.__setup_data(data_package) + self.__setup_likelihood(function_package) + + def __setup_data(self, data_package): + # type: (loaders.DataLoading) -> None + self.__data["data"] = data_package.data + + def __setup_likelihood(self, function_package): + # type: (loaders.FunctionLoader) -> None + self._likelihood = Empty( + function_package.setup, function_package.process + ) + + def get_likelihood(self): + # type: () -> interfaces.Likelihood + return self.__likelihood + + def get_data(self): + # type: () -> Dict[str, numpy.ndarray] + return self.__data + + +class Empty(interfaces.Likelihood): + + def __init__( + self, + setup_function, # type: shell_types.users_setup + processing_function # type: shell_types.users_processing + ): + super(Empty, self).__init__(setup_function) + self.__processing_function = processing_function + self.data = None # type: numpy.ndarray + + def process(self, data=False): + # type: (Dict[str, float]) -> float + return numpy.sum(self.__processing_function(self.data, data)) diff --git a/PyPWA/shell/pyfit/likelihoods/log_likelihood.py b/PyPWA/shell/pyfit/likelihoods/log_likelihood.py new file mode 100644 index 00000000..111c0f0d --- /dev/null +++ b/PyPWA/shell/pyfit/likelihoods/log_likelihood.py @@ -0,0 +1,178 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +The Log-Likelihood Extended and UnExtended are defined here: +------------------------------------------------------------ +- UnExtended Σln(Q*B*I°(D)) +- Extended Σln(Q*I°(D)) - 1/total_number * Σ(I°(MC)) +""" + +from typing import Any, Dict +from typing import Optional as Opt + +import logging +import numpy + +from PyPWA import AUTHOR, VERSION +from PyPWA.shell import loaders +from PyPWA.shell import shell_types +from PyPWA.shell.pyfit import interfaces + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class LogLikelihood(interfaces.Setup): + + NAME = "likelihood" + + def __init__(self): + self.__data = dict() # type: Dict[str, numpy.ndarray] + self.__generated_length = None # type: float + self.__likelihood = None # type: interfaces.Likelihood + + def setup_likelihood( + self, + data_package, # type: loaders.DataLoading + function_package, # type: loaders.FunctionLoader + extra_info=None # type: Opt[Dict[str, Any]] + ): + # type: (...) -> None + self.__setup_data(data_package) + self.__setup_likelihood(function_package) + self.__extract_generated_length(extra_info) + + def __setup_data(self, data_package): + # type: (loaders.DataLoading) -> None + self.__data["data"] = data_package.data + self.__data["qfactor"] = data_package.qfactor + self.__data["binned"] = data_package.binned + if data_package.monte_carlo: + self.__data["monte_carlo"] = data_package.monte_carlo + + def __extract_generated_length(self, extra_info): + # type: (Dict[str, float]) -> None + if extra_info: + self.__generated_length = extra_info["generated length"] + + def __setup_likelihood(self, function_package): + # type: (loaders.FunctionLoader) -> None + if "monte_carlo" in self.__data: + self.__setup_extended_monte_carlo(function_package) + else: + self.__setup_standard_likelihood(function_package) + + def __setup_extended_monte_carlo(self, function_package): + # type: (loaders.FunctionLoader) -> None + self.__likelihood = ExtendedLikelihoodAmplitude( + function_package.setup, function_package.process, + self.__generated_length + ) + + def __setup_standard_likelihood(self, function_package): + # type: (loaders.FunctionLoader) -> None + self.__likelihood = UnExtendedLikelihoodAmplitude( + function_package.setup, function_package.process + ) + + def get_data(self): + # type: () -> Dict[str, numpy.ndarray] + return self.__data + + def get_likelihood(self): + # type: () -> interfaces.Likelihood + return self.__likelihood + + +class ExtendedLikelihoodAmplitude(interfaces.Likelihood): + + __LOGGER = logging.getLogger(__name__ + ".ExtendedLikelihoodAmplitude") + + def __init__( + self, + setup_function, # type: shell_types.users_setup + processing_function, # type: shell_types.users_processing + generated_length # type: float + ): + # type: (...) -> None + super(ExtendedLikelihoodAmplitude, self).__init__(setup_function) + self.__processing_function = processing_function + self.__processed = 1.0 / generated_length + self.data = None # type: numpy.ndarray + self.monte_carlo = None # type: numpy.ndarray + self.qfactor = 1 # type: numpy.ndarray + + def process(self, data=False): + # type: (Dict[str, float]) -> float + processed_data = self.__processing_function(self.data, data) + processed_monte_carlo = self.__processing_function( + self.monte_carlo, data + ) + return self.__likelihood(processed_data, processed_monte_carlo) + + def __likelihood(self, data, monte_carlo): + # type: (numpy.ndarray, numpy.ndarray) -> float + self.__check_data_for_zeros(data) + data_result = self.__process_log_likelihood(data) + monte_carlo_result = self.__process_monte_carlo(monte_carlo) + return data_result + monte_carlo_result + + def __check_data_for_zeros(self, data): + # type: (numpy.ndarray) -> None + if numpy.count_nonzero(data == 0): + self.__LOGGER.warning( + "WARNING, Found Zeros! " + repr( + numpy.count_nonzero(data == 0) + ) + ) + + def __process_log_likelihood(self, data): + # type: (numpy.ndarray) -> float + return numpy.sum(self.qfactor * numpy.log(data)) + + def __process_monte_carlo(self, monte_carlo): + # type: (numpy.ndarray) -> float + return self.__processed * numpy.sum(monte_carlo) + + +class UnExtendedLikelihoodAmplitude(interfaces.Likelihood): + + def __init__( + self, + setup_function, # type: shell_types.users_setup + processing_function # type: shell_types.users_processing + ): + # type: (...) -> None + super(UnExtendedLikelihoodAmplitude, self).__init__(setup_function) + self.__processing_function = processing_function + self.data = None # type: numpy.ndarray + self.qfactor = 1 # type: numpy.ndarray + self.binned = 1 # type: numpy.ndarray + + def process(self, data=False): + # type: (Dict[str, float]) -> float + processed_data = self.__processing_function(self.data, data) + return self.__likelihood(processed_data) + + def __likelihood(self, data): + # type: (numpy.ndarray) -> float + processed = self.qfactor * self.binned * numpy.log(data) + value = numpy.sum(processed) + return value diff --git a/PyPWA/shell/pyfit/pyfit.py b/PyPWA/shell/pyfit/pyfit.py new file mode 100644 index 00000000..1ebf8223 --- /dev/null +++ b/PyPWA/shell/pyfit/pyfit.py @@ -0,0 +1,145 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +PyFit, a flexible python fitting utility. +----------------------------------------- + +- _LikelihoodPackager - a simple object that searches the 'likehoods' + package for the user's selected likelihood. + +- Fitting - defines the actual main logic for the program. +""" + +from typing import List + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.shared import plugin_loader +from PyPWA.core.shared.interfaces import internals +from PyPWA.core.shared.interfaces import plugins +from PyPWA.shell import loaders +from PyPWA.shell.pyfit._process_interface import FittingInterface +from PyPWA.shell.pyfit import interfaces +from PyPWA.shell.pyfit import likelihoods + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class LikelihoodPackager(object): + + def __init__(self): + self.__plugin_search = plugin_loader.PluginLoader() + self.__plugin_search.add_plugin_location(likelihoods) + + def get_likelihood(self, name): + # type: (str) -> interfaces.Setup + likelihood_list = self.__get_likelihoods() + return self.__get_likelihood_by_name(likelihood_list, name) + + def __get_likelihoods(self): + # type: () -> List[type(interfaces.Setup)] + return self.__plugin_search.get_by_class(interfaces.Setup) + + def __get_likelihood_by_name(self, potential_likelihoods, name): + # type: (List[type(interfaces.Setup)], str) -> interfaces.Setup + for likelihood in potential_likelihoods: + if likelihood.NAME == name: + return likelihood() + self.__failed_to_find_likelihood(name) + + @staticmethod + def __failed_to_find_likelihood(name): + # type: (str) -> None + raise ValueError("Failed to find likelihood: %s" % name) + + def get_likelihood_name_list(self): + # type: () -> List[str] + names = [] + for likelihood in self.__get_likelihoods(): + names.append(likelihood.NAME) + return names + + +class Fitting(plugins.Main): + + def __init__( + self, + optimizer, # type: plugins.Optimizer + kernel_processing, # type: plugins.KernelProcessing + data_loader, # type: loaders.DataLoading + function_loader, # type: loaders.FunctionLoader + likelihood_type, # type: str + generated_length, # type: int + save_name # type: str + ): + self.__optimizer = optimizer + self.__processing = kernel_processing + self.__data_loader = data_loader + self.__function_loader = function_loader + self.__likelihood_type = likelihood_type + self.__generated_length = generated_length + self.__save_name = save_name + + self.__likelihood_loader = LikelihoodPackager() + self.__process_interface = None # type: FittingInterface + self.__likelihood = None # type: interfaces.Setup + self.__interface = None # type: internals.ProcessInterface + + def start(self): + self.__setup_interface() + self.__setup_likelihood() + self.__setup_processing() + self.__set_interface() + self.__start_optimizer() + self.__finalize_program() + + def __setup_interface(self): + self.__processing_interface = FittingInterface( + self.__optimizer.return_parser() + ) + + def __setup_likelihood(self): + self.__likelihood = self.__likelihood_loader.get_likelihood( + self.__likelihood_type + ) + + self.__likelihood.setup_likelihood( + self.__data_loader, self.__function_loader, + {"generated length": self.__generated_length} + ) + + def __setup_processing(self): + self.__processing.main_options( + self.__likelihood.get_data(), self.__likelihood.get_likelihood(), + self.__processing_interface + ) + + def __set_interface(self): + self.__interface = self.__processing.fetch_interface() + + def __start_optimizer(self): + self.__optimizer.main_options( + self.__interface.run, self.__likelihood_type + ) + self.__optimizer.start() + + def __finalize_program(self): + self.__interface.stop() + self.__optimizer.save_extra(self.__save_name) diff --git a/PyPWA/shell/pyshell_functions.py b/PyPWA/shell/pyshell_functions.py new file mode 100644 index 00000000..4a72c846 --- /dev/null +++ b/PyPWA/shell/pyshell_functions.py @@ -0,0 +1,50 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Simply defines the user's functions that are shared between PyFit, PySimulate, +and their derivative programs. +""" + +from PyPWA.core.configurator import options +from PyPWA import AUTHOR, VERSION + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class ShellFunctionFile(options.FileBuilder): + imports = {"numpy"} + functions = [ + """ +def processing_function(the_array, the_params): + # The Params is passed by your optimizer, each optimizer passes something + # different to check with the documentation if you are unsure how to use + # it. + + final_value = the_array["x"] * the_params["A1"] + return final_value + """, + """ +def setup_function(): + # If you have an amplitude that needs a method are function called before + # you can begin processing, call it here. + pass + """ + ] diff --git a/PyPWA/shell/pysimulate/__init__.py b/PyPWA/shell/pysimulate/__init__.py new file mode 100644 index 00000000..d3fe0540 --- /dev/null +++ b/PyPWA/shell/pysimulate/__init__.py @@ -0,0 +1,105 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Package for PySimulate, GenerateIntensities, and GenerateWeights +---------------------------------------------------------------- +PySimulate is used to generate simulated data for a amplitude using a flat +plane of data provided by the user. + +- _libs - where the actual logic of the program is defined. + +- _processing - contains the objects required to interface with a Kernel + Processing package. + +- initial_setup - where the Setup object is defined for the Configurator to + interface with PySimulate properly. + +- pysimulate - where the 'main' object is, though all it does it route + information between the various objects defined in _libs.py +""" + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import options +from PyPWA.shell import pyshell_functions +from PyPWA.shell.pysimulate import initial_setup + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class ShellSimulation(options.Main): + + plugin_name = "shell simulation" + setup = initial_setup.SimulationSetup + defined_function = pyshell_functions.ShellFunctionFile + + required_plugins = [ + options.Types.DATA_PARSER, + options.Types.KERNEL_PROCESSING + ] + + module_comment = "A Python Statistical Simulation Tool" + + option_comments = { + "the type": + "If you are seeing this, something went very wrong.", + "function's location": + "The path to the intensity function.", + "processing name": "The name of the intensity function.", + "setup name": "The name of the setup function.", + "data location": "The path to your data.", + "parameters": "The parameters to simulate against.", + "max intensity": + "The largest intensity in your entire data set", + "save name": "The name to use for saving data." + } + + default_options = { + "the type": "full", + "function's location": "/path/to/the/function.py", + "processing name": "processing_function", + "setup name": "setup_function", + "data location": "/path/to/the/data.csv", + "parameters": {"A1": 1, "A2": 2, "A3": 0.1, "A4": -10.0001}, + "max intensity": "2.123123", + "save name": "output" + } + + option_difficulties = { + "the type": options.Levels.REQUIRED, + "function's location": options.Levels.REQUIRED, + "processing name": options.Levels.REQUIRED, + "setup name": options.Levels.REQUIRED, + "data location": options.Levels.REQUIRED, + "parameters": options.Levels.REQUIRED, + "max intensity": options.Levels.REQUIRED, + "save name": options.Levels.REQUIRED + } + + option_types = { + "the type": ["full", "intensities", "weighting"], + "function's location": str, + "processing name": str, + "setup name": str, + "data location": str, + "parameters": dict, + "max intensity": float, + "save name": str + } diff --git a/PyPWA/shell/pysimulate/_libs.py b/PyPWA/shell/pysimulate/_libs.py new file mode 100644 index 00000000..8710cd34 --- /dev/null +++ b/PyPWA/shell/pysimulate/_libs.py @@ -0,0 +1,167 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +General Objects needed for PySimulate +------------------------------------- +A collection of objects are defined here that influence how the PySimulate +works. All here is the true main logic of the program. + +- DataHandler - takes the data objects, data location, and save location, + the providing access to whatever data it can load, and exposing methods + that will handle to writing of all the different types of data the + simulation object would need written. + +- Intensities - calculates the intensities using the provided processing + function and setup. + +- RejectionList - takes an array of calculated intensities along with a max + intensity, normalizes the intensities, then using the Rejection Method, + randomly throws out events. +""" + +import io +import random +import time +from typing import Dict + +import numpy + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.shared.interfaces import plugins +from PyPWA.shell import loaders +from PyPWA.shell.pysimulate import _processing + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class DataHandler(loaders.DataLoading): + + def __init__(self, data_parser, data_location, save_name): + # type: (plugins.DataParser, str, str) -> None + super(DataHandler, self).__init__(data_parser, data_location) + self.__save_location = save_name + + def write_intensity_data(self, intensities, max_intensity): + # type: (numpy.ndarray, float) -> None + self.__write_intensity_array(intensities) + self.__write_max_intensity(max_intensity) + + def __write_intensity_array(self, intensities): + # type: (numpy.ndarray) -> None + save_location = self.__save_location + "_intensities.txt" + self.write(save_location, intensities) + + def __write_max_intensity(self, max_intensity): + # type: (float) -> None + save_location = self.__save_location + "_max.txt" + with io.open(save_location, "w") as stream: + stream.write(str(max_intensity)) + + def write_rejection_list(self, rejection_list): + # type: (numpy.ndarray) -> None + rejection_list_name = self.__save_location + "_rejection.txt" + self.write(rejection_list_name, rejection_list) + + +class Intensities(object): + + def __init__( + self, + data_loader, # type: DataHandler + function_loader, # type: loaders.FunctionLoader + processing, # type: plugins.KernelProcessing + parameters # type: Dict[str, float] + ): + self.__data_loader = data_loader + self.__function_loader = function_loader + self.__processing = processing + self.__parameters = parameters + + self.__found_intensities = None # type: numpy.ndarray + self.__max_intensity = None # type: float + + def calc_intensities(self): + self.__load_processing_module() + self.__process_intensities() + + def __load_processing_module(self): + the_kernel = _processing.IntensityKernel( + self.__function_loader.setup, self.__function_loader.process, + self.__parameters + ) + the_interface = _processing.IntensityInterface() + + self.__processing.main_options( + self.__get_kernel_data(), the_kernel, the_interface + ) + + def __get_kernel_data(self): + # type: () -> Dict[str, numpy.ndarray] + return {"data": self.__data_loader.data} + + def __process_intensities(self): + operational_interface = self.__processing.fetch_interface() + self.__found_intensities, self.__max_intensity = \ + operational_interface.run() + + @property + def processed_intensities(self): + # type: () -> numpy.ndarray + return self.__found_intensities + + @property + def max_intensity(self): + # type: () -> float + return self.__max_intensity + + +class RejectionList(object): + + __RANDOM = random.SystemRandom(time.gmtime()) + + def __init__(self, intensities, max_intensity): + # type: (numpy.ndarray, float) -> None + self.__intensities = intensities + self.__max_intensity = max_intensity + + self.__rejection_list = None # type: numpy.ndarray + self.__set_rejection_list() + + def __set_rejection_list(self): + array_length = len(self.__intensities) + self.__rejection_list = numpy.zeros(shape=array_length, dtype=bool) + + def rejection_method(self): + self.__normalize_intensities() + self.__loop_over_intensities() + + def __normalize_intensities(self): + self.__intensities = self.__intensities / self.__max_intensity + + def __loop_over_intensities(self): + for index, event in enumerate(self.__intensities): + if event > self.__RANDOM.random(): + self.__rejection_list[index] = True + + @property + def rejection_list(self): + # type: () -> numpy.ndarray + return self.__rejection_list diff --git a/PyPWA/shell/pysimulate/_processing.py b/PyPWA/shell/pysimulate/_processing.py new file mode 100644 index 00000000..b36359fb --- /dev/null +++ b/PyPWA/shell/pysimulate/_processing.py @@ -0,0 +1,104 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Needed objects for kernel processing. +------------------------------------- +These objects implement the internal interfaces for kernel processing so +that Simulation's intensities calculations can be executed quicker. +""" + +import logging +from typing import Any, Dict, List, Tuple + +import numpy +from numpy import ndarray + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.shared.interfaces import internals +from PyPWA.shell import shell_types + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class IntensityInterface(internals.KernelInterface): + + IS_DUPLEX = False + __LOGGER = logging.getLogger(__name__ + "IntensityInterface") + + def run(self, communicator, args): + # type: (List[Any], Any) -> Tuple[ndarray, float] + data = self.__receive_data(communicator) + return self.__process_data(data) + + def __receive_data(self, communicator): + # type: (List[Any]) -> List[ndarray] + list_of_data = list(range(len(communicator))) + + for communication in communicator: + data = communication.receive() + self.__LOGGER.debug("Received data: " + repr(data)) + list_of_data[data[0]] = data[1] + + return list_of_data + + def __process_data(self, list_of_data): + # type: (List[ndarray]) -> Tuple[ndarray, float] + final_array = numpy.concatenate(list_of_data) + self.__log_final_array_statistics(final_array) + return final_array, final_array.max() + + def __log_final_array_statistics(self, array): + # type: (ndarray) -> None + self.__LOGGER.debug("Final Array: " + repr(array)) + self.__LOGGER.info("Max Intensity: %f" % array.max()) + self.__LOGGER.info("Min Intensity: %f" % array.min()) + self.__LOGGER.info("Intensities Range: %f" % array.ptp()) + self.__LOGGER.info("Intensities STD: %f" % array.std()) + self.__LOGGER.info("Intensities Mean: %f" % array.mean()) + + +class IntensityKernel(internals.Kernel): + + __LOGGER = logging.getLogger(__name__ + ".IntensityKernel") + + def __init__( + self, + setup_function, # type: shell_types.users_setup + processing_function, # type: shell_types.users_processing + parameters # type: Dict[str, float] + ): + # type: (...) -> None + self.__setup_function = setup_function + self.__processing_function = processing_function + self.__parameters = parameters + self.data = None # type: ndarray + + def setup(self): + self.__setup_function() + + def process(self, data=False): + # type: (Any) -> Tuple[int, ndarray] + self.__LOGGER.debug("%d is alive!" % self.PROCESS_ID) + calculated_data = self.__processing_function( + self.data, self.__parameters + ) + + return self.PROCESS_ID, calculated_data diff --git a/PyPWA/shell/pysimulate/initial_setup.py b/PyPWA/shell/pysimulate/initial_setup.py new file mode 100644 index 00000000..da67c7fe --- /dev/null +++ b/PyPWA/shell/pysimulate/initial_setup.py @@ -0,0 +1,74 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Translates the command object from the configurator into arguments that +can be used by the Simulation package and its various objects. +""" + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.configurator import option_tools +from PyPWA.core.configurator import options +from PyPWA.shell import loaders +from PyPWA.shell.pysimulate import _libs +from PyPWA.shell.pysimulate import pysimulate + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class SimulationSetup(options.Setup): + + def __init__(self, options_object): + # type: (option_tools.CommandOptions) -> None + self.__options = options_object + + self.__simulator = None # type: pysimulate.Simulator + self.__functions = None # type: loaders.FunctionLoader + self.__data_loader = None # type: _libs.DataHandler + + self.__load_functions() + self.__load_data() + self.__set_interface() + + def __load_functions(self): + the_type = self.__options.the_type + + if the_type == "full" or the_type == "intensities": + self.__functions = loaders.FunctionLoader( + self.__options.functions_location, + self.__options.processing_name, self.__options.setup_name + ) + + def __load_data(self): + self.__data_loader = _libs.DataHandler( + self.__options.data_parser, self.__options.data_location, + self.__options.save_name + ) + + def __set_interface(self): + self.__simulator = pysimulate.Simulator( + self.__data_loader, self.__options.the_type, + self.__options.kernel_processing, self.__functions, + self.__options.parameters, self.__options.max_intensity + ) + + def return_interface(self): + # type: () -> pysimulate.Simulator + return self.__simulator diff --git a/PyPWA/shell/pysimulate/pysimulate.py b/PyPWA/shell/pysimulate/pysimulate.py new file mode 100644 index 00000000..d63f0229 --- /dev/null +++ b/PyPWA/shell/pysimulate/pysimulate.py @@ -0,0 +1,128 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +The Simulation program, this object simply routes the data around depending +on the type of program execution passed to it, the actual logic for the +program exists in _libs.py +""" + +import logging +from typing import Dict, Union +from typing import Optional as Opt + +import numpy + +from PyPWA import AUTHOR, VERSION +from PyPWA.core.shared.interfaces import plugins +from PyPWA.shell import loaders +from PyPWA.shell.pysimulate import _libs + +__credits__ = ["Mark Jones"] +__author__ = AUTHOR +__version__ = VERSION + + +class Simulator(plugins.Main): + + __LOGGER = logging.getLogger(__name__ + ".Simulator") + + def __init__( + self, + data_loader, # type: _libs.DataHandler + the_type, # type: Union["full", "intensities", "weighting"] + kernel_processing=None, # type: Opt[plugins.KernelProcessing] + function_loader=None, # type: Opt[loaders.FunctionLoader] + parameters=None, # type: Opt[Dict[str, numpy.float64]] + max_intensity=None # type: Opt[numpy.float64] + ): + # type: (...) -> None + self.__data_loader = data_loader + self.__program_type = the_type + self.__kernel_processing = kernel_processing + self.__function_loader = function_loader + self.__parameters = parameters + self.__max_intensity = max_intensity + + self.__intensity_calc = None # type: _libs.Intensities + self.__rejection_calc = None # type: _libs.RejectionList + self.__intensity_array = None # type: numpy.ndarray + + def start(self): + if self.__program_type == "full": + self.__full_program_run() + elif self.__program_type == "intensities": + self.__intensity_program() + elif self.__program_type == "weighting": + self.__rejection_program() + else: + self.__raise_program_type_error() + + def __full_program_run(self): + self.__setup_intensity_calc() + self.__intensity_calc.calc_intensities() + self.__set_intensities_from_intensity_calc() + self.__setup_rejection_calc() + self.__rejection_calc.rejection_method() + self.__write_rejection_data() + + def __setup_intensity_calc(self): + self.__LOGGER.debug("Setting up Intensity Calculation.") + self.__intensity_calc = _libs.Intensities( + self.__data_loader, self.__function_loader, + self.__kernel_processing, self.__parameters + ) + + def __set_intensities_from_intensity_calc(self): + self.__max_intensity = self.__intensity_calc.max_intensity + self.__intensity_array = self.__intensity_calc.processed_intensities + + def __setup_rejection_calc(self): + self.__LOGGER.debug("Setting up Rejection Method.") + self.__rejection_calc = _libs.RejectionList( + self.__intensity_array, self.__max_intensity + ) + + def __write_rejection_data(self): + self.__data_loader.write_rejection_list( + self.__rejection_calc.rejection_list + ) + + def __intensity_program(self): + self.__setup_intensity_calc() + self.__intensity_calc.calc_intensities() + self.__write_intensity_data() + + def __rejection_program(self): + self.__intensity_array = self.__data_loader.data + self.__setup_rejection_calc() + self.__rejection_calc.rejection_method() + self.__write_rejection_data() + + def __write_intensity_data(self): + self.__data_loader.write_intensity_data( + self.__intensity_calc.processed_intensities, + self.__intensity_calc.max_intensity + ) + + def __raise_program_type_error(self): + error = "The type is not set correctly! Found: %s but expected " \ + "either full, intensities, or weighting." % \ + repr(self.__program_type) + + raise ValueError(error) diff --git a/PyPWA/shell/shell_types.py b/PyPWA/shell/shell_types.py new file mode 100644 index 00000000..6b3369f6 --- /dev/null +++ b/PyPWA/shell/shell_types.py @@ -0,0 +1,27 @@ +# coding=utf-8 +# +# PyPWA, a scientific analysis toolkit. +# Copyright (C) 2016 JLab +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Unique types needed for PyFit and PySimulate +""" + +from typing import Callable, Dict +from numpy import ndarray + +users_processing = Callable[[ndarray, Dict[str, float]], ndarray] +users_setup = Callable[[], None] diff --git a/PyPWA/shell/simulation/__init__.py b/PyPWA/shell/simulation/__init__.py deleted file mode 100644 index 863dfec9..00000000 --- a/PyPWA/shell/simulation/__init__.py +++ /dev/null @@ -1,121 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -This line is green in PyCharm, however in Github its blue. -""" - -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core.templates import option_templates -from PyPWA.shell.simulation import main - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class ShellSimulation(option_templates.MainOptionsTemplate): - - def _user_defined_function(self): - return self._build_function("numpy", """\ - -def processing_function(the_array, the params): - pass - -def setup_function(): - pass - - """) - - def _shell_id(self): - return "shell simulation" - - def _default_options(self): - return { - "the type": "full", - "function's location": "/path/to/the/function.py", - "processing name": "processing_function", - "setup name": "setup_function", - "data location": "/path/to/the/data.csv", - "parameters": {"A1": 1, "A2": 2, "A3": 0.1, "A4": -10.0001}, - "max intensity": "2.123123", - "save name": "output" - } - - def _option_levels(self): - return { - "the type": self._required, - "function's location": self._required, - "processing name": self._required, - "setup name": self._required, - "data location": self._required, - "parameters": self._required, - "max intensity": self._required, - "save name": self._required - } - - def _option_types(self): - return { - "the type": ["full", "intensities", "weighting"], - "function's location": str, - "processing name": str, - "setup name": str, - "data location": str, - "parameters": dict, - "max intensity": float, - "save name": str - } - - def _module_comment(self): - return "The General Shell, a simple multiprocessing enabled " \ - "data analysis tool." - - def _option_comments(self): - return { - "the type": - "If you are seeing this, something went very wrong.", - "function's location": - "The location to the intensity function.", - "processing name": "The name of the intensity function.", - "setup name": "The name of the setup function.", - "data location": "The path to your data.", - "parameters": "The parameters to simulate against.", - "max intensity": - "The largest intensity in your entire data set", - "save name": "The name to use for saving data." - } - - def _main_type(self): - return self._shell_main - - def _requires_data_parser(self): - return True - - def _requires_data_reader(self): - return False - - def _requires_kernel_processing(self): - return True - - def _requires_minimization(self): - return False - - def _interface_object(self): - return main.Simulator diff --git a/PyPWA/shell/simulation/main.py b/PyPWA/shell/simulation/main.py deleted file mode 100644 index 6ab1deb1..00000000 --- a/PyPWA/shell/simulation/main.py +++ /dev/null @@ -1,234 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -This line is green in PyCharm, however in Github its blue. -""" - -import io -import logging -import random -import time - -import numpy -from PyPWA import VERSION, LICENSE, STATUS -from PyPWA.core import plugin_loader -from PyPWA.core.templates import interface_templates -from PyPWA.core.templates import plugin_templates - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" -__status__ = STATUS -__license__ = LICENSE -__version__ = VERSION - - -class Simulator(plugin_templates.ShellMain): - - def __init__( - self, data_parser=None, kernel_processing=None, - the_type=None, functions_location=None, - processing_name=None, setup_name=None, data_location=None, - parameters=None, max_intensity=None, save_name=None, - **options - ): - """ - - Args: - data_parser (plugin_templates.DataParserTemplate): - kernel_processing (plugin_templates.KernelProcessingTemplate): - the_type (str): - functions_location (str): - processing_name (str): - setup_name (str): - data_location (str): - parameters (dict): - max_intensity (numpy.float64): - save_name (str): - options (dict): - """ - - self._data_parser = data_parser - self._kernel_processing = kernel_processing - self._the_type = the_type - self._functions_location = functions_location - self._processing_name = processing_name - self._setup_name = setup_name - self._data_location = data_location - self._intensities = False - self._rejection_list = False - self._parameters = parameters - self._max_intensity = max_intensity - self._save_name = save_name - - if options: - super(Simulator, self).__init__(options) - - self._raw_data = {} - self._intensities = None # type: numpy.ndarray - - def start(self): - """ - - Returns: - - """ - if self._the_type == "full": - self._calc_intensities() - self._rejection_method() - elif self._the_type == "intensities": - self._calc_intensities() - elif self._the_type == "weighting": - self._rejection_method() - else: - raise RuntimeError( - "The type is not set correctly! Found: " + - repr(self._the_type) - ) - - if self._the_type == "intesities": - self._data_parser.write( - self._save_name + "_intensities.txt", self._intensities - ) - - with io.open(self._save_name + "_max.txt") as stream: - stream.write(str(self._max_intensity)) - - elif self._the_type == "weighting" or self._the_type == "full": - self._data_parser.write( - self._save_name + "_rejection.txt", - self._rejection_list - ) - - def _calc_intensities(self): - """ - - Returns: - - """ - loader = plugin_loader.SingleFunctionLoader( - self._functions_location - ) - - processing = loader.fetch_function(self._processing_name) - setup = loader.fetch_function(self._setup_name) - - self._raw_data["data"] = self._data_parser.parse( - self._data_location - ) - - the_kernel = IntensityKernel(setup, processing, self._parameters) - the_interface = IntensityInterface() - - self._kernel_processing.main_options( - self._raw_data, the_kernel, the_interface - ) - - operational_interface = self._kernel_processing.fetch_interface() - self._intensities, self._max_intensity = operational_interface.run() - - def _rejection_method(self): - """ - - Returns: - - """ - if not isinstance(self._intensities, numpy.ndarray): - self._intensities = self._data_parser.parse(self._data_location) - - the_random = random.SystemRandom(time.gmtime()) - - weighted_list = self._intensities / self._max_intensity - rejection = numpy.zeros(shape=len(weighted_list), dtype=bool) - for index, event in enumerate(weighted_list): - if event > the_random.random(): - rejection[index] = True - - self._rejection_list = rejection - - -class IntensityInterface(interface_templates.AbstractInterface): - - is_duplex = False - - def __init__(self): - """ - - """ - self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) - - def run(self, communicator, args): - """ - - Args: - communicator (list): - args: - - Returns: - - """ - - list_of_data = list(range(len(communicator))) - - for communication in communicator: - data = communication.receive() - self._logger.debug("Received data: " + repr(data)) - list_of_data[data[0]] = data[1] - - final_array = numpy.concatenate(list_of_data) - self._logger.debug("Final Array: " + repr(final_array)) - return [final_array, final_array.max()] - - -class IntensityKernel(interface_templates.AbstractKernel): - - def __init__(self, setup_function, processing_function, parameters): - """ - - Args: - setup_function: - processing_function: - parameters: - """ - self._setup_function = setup_function - self._processing_function = processing_function - self._parameters = parameters - self.data = None # type: numpy.ndarray - - def setup(self): - """ - - Returns: - - """ - self._setup_function() - - def process(self, data=False): - """ - - Args: - data: - - Returns: - - """ - return [ - self.processor_id, - self._processing_function(self.data, self._parameters) - ] diff --git a/README.md b/README.md index 7e217b1c..da61e815 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,74 @@ -# PyPWA [![Build Status](https://travis-ci.org/JeffersonLab/PyPWA.svg?branch=master)](https://travis-ci.org/JeffersonLab/PyPWA) -A python based software framework designed to perform Partial Wave and Amplitude Analysis with the goal of extracting resonance information from multiparticle final states. Supports the Un/Extended Un/Binned likelihood maximum estimation, Acceptance Rejection Method, and ISOBAR Model. +PyPWA [![Build Status](https://travis-ci.org/JeffersonLab/PyPWA.svg?branch=master)](https://travis-ci.org/JeffersonLab/PyPWA) [![Coverage Status](https://coveralls.io/repos/github/JeffersonLab/PyPWA/badge.svg?branch=master)](https://coveralls.io/github/JeffersonLab/PyPWA?branch=master) +===== -## General Shell +A python based software framework designed to perform Partial Wave and +Amplitude Analysis with the goal of extracting resonance information from +multi-particle final states. +Is constantly tested to work with Python Versions 2.7, 3.4, 3.5, and 3.6. -The new General Shell is iminuit based threaded fitting tool, it is designed to run from your machines path or from a virtualenv. +Has support for multiple likelihoods, including: + - Extended Log Likelihood + - Standard Log Likelihood, Optionally Binned + - Binned ChiSquared Likelihood + - Standard ChiSquared Likelihood + + You can even define your own likelihood, or calculate entirely without one + if you chose to do so! + +Features +-------- -To install simply run "python setup.py install", or optionally "python setup.py install --user" to install it locally instead of to your system +Generic Fitting Tools +- PyFit + - Can fit to a log-likelihood, chi-square, or you can define your own + - Supports Binned Data + - Supports a quality factor per event +- PySimulate +- Easy to use Yaml based configuration +- A configuration builder, to walk you through the initial creation of + the configuration +- Supports using all the threads on the machine + + +Installation from GitHub +------------------------ + +Clone the master branch onto your computer, or if you are daring clone the +development branch + + $ git clone https://github.com/JeffersonLab/PyPWA + +Then install the package to your system, run this from inside the PyPWA +folder: + + $ sudo python setup.py install + + +Using PyFit and PySimulate +-------------------------- + +Go to the directory that you would like to do your analysis in and run: + + $ [PyFit/PySimulate] -wc [configuration_name] + +Fill in the data in that configuration file using your favorite editor, +then run your analysis: + + $ [PyFit/PySimulate] [configuration_name] + + +Contribute or Support +--------------------- +If you have any issues, or would like to see any features added to the +project, let us know! + +- Feature Tracker: +- Issue Tracker: +- Source Code: + + +License +------- + +The project is licensed under the GPLv3 license. -To use, run "GeneralFitting -wc" to have the GeneralShell write an Example.py and Example.yml to your current working directory. -After modifying the Examples to fit your use case, run "GeneralFitting -c .yml" \ No newline at end of file diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 5143f9ca..00000000 --- a/doc/Makefile +++ /dev/null @@ -1,192 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " applehelp to make an Apple Help Book" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - @echo " coverage to run coverage check of the documentation (if enabled)" - -clean: - rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PyPWA.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PyPWA.qhc" - -applehelp: - $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp - @echo - @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." - @echo "N.B. You won't be able to view it unless you put it in" \ - "~/Library/Documentation/Help or install it in your application" \ - "bundle." - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/PyPWA" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PyPWA" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -coverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage - @echo "Testing of coverage in the sources finished, look at the " \ - "results in $(BUILDDIR)/coverage/python.txt." - -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/doc/source/General_Fitting.rst b/doc/source/General_Fitting.rst deleted file mode 100644 index 5d29303e..00000000 --- a/doc/source/General_Fitting.rst +++ /dev/null @@ -1,130 +0,0 @@ -General Fitting -======================== -Section 1.1 ------------------------- - -:Authors: C. Salgado, L.M.Hare - -:Version: 1.0 of 08/01/2016 - -:Dedication: To my Beautiful Wife Patrice. - -This tutorial is being written to compliment and assist with the use of the General Fitting model through the Computational Computing. This can be used either through a desktop or through the interactive computing farm. - -1) First create a directory which should be named after the experiment that was completed. (For the purposes of this Tutorial we shall use "MAIN".) - a- All data should be located in this directory. - b- Ensure that you keep track of where this directory. - -2) Copy the programs files from the following site: https://github.com/JeffersonLab/PyPWA/releases. - - a- The latest version is called PyPWA-.tar.gz will need to be installed. - -3) To install run "pip install --user PyPWA-.tar.gz". Omit quotes. - -4) Run General Fitting -wc - :: - - a- This will create 2 files: - Example.py - Example.yml - b- Rename Example.py to MAIN.py. - c- Rename Example.yml to MAIN.yml - -5) Within the MAIN.yml is the configuration file for the actual computational process. You will see:: - - Likelihood Information: #There must be a space between the colon and the data - Generated Length : 10000 #Number of Generated events - Function's Location : Example.py #The python file that has the functions in it - Processing Name : the_function #The name of the processing function - Setup Name : the_setup #The name of the setup function, called only once before fitting - Data Information: - Data Location : /home/user/foobar/data.txt #The location of the data - # Accepted Monte Carlo Location: /home/foobar/fit/AccMonCar.txt # Optional, Path to your accepted data - # QFactor List Location : /home/foobar/fit/Qfactor.txt #Optional, The location of the QFactors - Save Name : output #Will make a file called output.txt and output.npy - Minuit's Settings: - Minuit's Initial Settings : { A1: 1, limit_A1: [0, 2500], # You can arrange this value however you would like as long as the each line ends in either a "," or a "}" - A2: 2, limit_A2: [-2,3], - A3: 0.1, A4: -10, - A5: -0.00001 } #Iminuit settings in a single line - Minuit's Parameters: [ A1, A2, A3, A4, A5 ] #The name of the Parameters passed to Minuit - Minuit's Strategy : 1 - Minuit's Set Up: 0.5 - Minuit's ncall: 1000 - General Settings: - Number of Threads: 1 #Number of threads to use. Set to one for debug - Logging Level: warn #Supports debug info warn - -6) You must edit:: - - Generated Length - Function Length - Processing Name - Set Up Name - Data Location - Save Name - Minuit Settings - General Setting - - a- Within this configuration file, there are several parameters that must be set before the program can be run. Several of the parameters can be set to be exempt from being run by using the "#" before the desired parameter. This will prevent that parameter from being used within the process. - - b- Following this the process will begin running showing each calculation. Once completed, the program will create several tables showing the completed computations. - -7) Within this program we can fit the data to the model that is given using the Chi function, for this you must again ensure that your data is within the same directory. - -8) You must run the the command "ChiSquared -wc". Omit quotes. - -9) This will create two files:: - - Example.py - Example.yml - -10) You must rename the Example.yml to MAINChi.yml. - -11) You must edit MAINChi.yml to the parameters of your experiment, you will see the following:: - - ChiSquared Information: #There must be a space between the colon and the data - Function's Location : Example.py #The python file that has the functions in it - Processing Name : the_function #The name of the processing function - Setup Name : the_setup #The name of the setup function, called only once before fitting - Data Information: - Data Location : /home/user/foobar/data.txt #The location of the data - # QFactor List Location : /home/foobar/fit/Qfactor.txt #Optional, The location of the QFactors - Save Name : output #Will make a file called output.txt and output.npy - Minuit's Settings: - Minuit's Initial Settings : { A1: 1, limit_A1: [0, 2500], # You can arrange this value however you would like as long as the each line ends in either a "," or a "}" - A2: 2, limit_A2: [-2,3], - A3: 0.1, A4: -10, - A5: -0.00001 } #Iminuit settings in a single line - Minuit's Parameters: [ A1, A2, A3, A4, A5 ] #The name of the Parameters passed to Minuit - Minuit's Strategy : 1 - Minuit's Set Up: 0.5 - Minuit's ncall: 1000 - General Settings: - Number of Threads: 1 #Number of threads to use. Set to one for debug - Logging Level: warn #Supports debug info warn - -12 You must edit:: - - ChiSquared Information - Function's Location - Processing Location - Data Information - Minuit's Initial Settings - Minuit's Strategy - Minuit's Set Up - Minuit's ncall - Number of Threads - - You must enter your data location via it's absolute path. - - The data must be in one of 3 forms:: - - Comma Seperated Variable Sheet - - Tab Seperated Variable Sheet - - EVIL - - It must be in a text file. - -13) Once complete, run the command "GeneralChiSquared MAINChi.yml". - -14) This will begin the computations. - -15) Once this has completed a set of tables will be created with the computations. - \ No newline at end of file diff --git a/doc/source/PyPWA.core.rst b/doc/source/PyPWA.core.rst deleted file mode 100644 index d46c96b7..00000000 --- a/doc/source/PyPWA.core.rst +++ /dev/null @@ -1,22 +0,0 @@ -PyPWA.core package -================== - -Submodules ----------- - -PyPWA.core.console_main module ------------------------------- - -.. automodule:: PyPWA.core.console_main - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: PyPWA.core - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/source/PyPWA.data.rst b/doc/source/PyPWA.data.rst deleted file mode 100644 index 74f1b62f..00000000 --- a/doc/source/PyPWA.data.rst +++ /dev/null @@ -1,62 +0,0 @@ -PyPWA.data package -================== - -Submodules ----------- - -PyPWA.data.cache module ------------------------ - -.. automodule:: PyPWA.data.cache - :members: - :undoc-members: - :show-inheritance: - -PyPWA.data.data_tools module ----------------------------- - -.. automodule:: PyPWA.data.data_tools - :members: - :undoc-members: - :show-inheritance: - -PyPWA.data.file_manager module ------------------------------- - -.. automodule:: PyPWA.data.file_manager - :members: - :undoc-members: - :show-inheritance: - -PyPWA.data.gampdata module --------------------------- - -.. automodule:: PyPWA.data.gampdata - :members: - :undoc-members: - :show-inheritance: - -PyPWA.data.iterators module ---------------------------- - -.. automodule:: PyPWA.data.iterators - :members: - :undoc-members: - :show-inheritance: - -PyPWA.data.memory_wrapper module --------------------------------- - -.. automodule:: PyPWA.data.memory_wrapper - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: PyPWA.data - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/source/PyPWA.entry.rst b/doc/source/PyPWA.entry.rst deleted file mode 100644 index 4947b400..00000000 --- a/doc/source/PyPWA.entry.rst +++ /dev/null @@ -1,22 +0,0 @@ -PyPWA.entry package -=================== - -Submodules ----------- - -PyPWA.entry.console module --------------------------- - -.. automodule:: PyPWA.entry.console - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: PyPWA.entry - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/source/PyPWA.proc.rst b/doc/source/PyPWA.proc.rst deleted file mode 100644 index 80fc554e..00000000 --- a/doc/source/PyPWA.proc.rst +++ /dev/null @@ -1,46 +0,0 @@ -PyPWA.proc package -================== - -Submodules ----------- - -PyPWA.proc.calculation module ------------------------------ - -.. automodule:: PyPWA.proc.calculation - :members: - :undoc-members: - :show-inheritance: - -PyPWA.proc.calculation_tools module ------------------------------------ - -.. automodule:: PyPWA.proc.calculation_tools - :members: - :undoc-members: - :show-inheritance: - -PyPWA.proc.process_calculation module -------------------------------------- - -.. automodule:: PyPWA.proc.process_calculation - :members: - :undoc-members: - :show-inheritance: - -PyPWA.proc.process_communication module ---------------------------------------- - -.. automodule:: PyPWA.proc.process_communication - :members: - :undoc-members: - :show-inheritance: - - -Module contents ---------------- - -.. automodule:: PyPWA.proc - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/source/PyPWA.rst b/doc/source/PyPWA.rst deleted file mode 100644 index 8f9c7aa4..00000000 --- a/doc/source/PyPWA.rst +++ /dev/null @@ -1,20 +0,0 @@ -PyPWA package -============= - -Subpackages ------------ - -.. toctree:: - - PyPWA.core - PyPWA.data - PyPWA.entry - PyPWA.proc - -Module contents ---------------- - -.. automodule:: PyPWA - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100644 index 6e3a2004..00000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,292 +0,0 @@ -# -*- coding: utf-8 -*- -# -# PyPWA documentation build configuration file, created by -# sphinx-quickstart on Sun Nov 22 13:23:29 2015. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os -import shlex - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('../..')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -needs_sphinx = '1.3' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.napoleon', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.pngmath', - 'sphinx.ext.ifconfig', - 'sphinx.ext.viewcode', -] - -# Add any paths that contain templates here, relative to this directory. -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' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'PyPWA' -copyright = u'2015, PyPWA Team' -author = u'PyPWA Team' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '2.0.0' -# The full version, including alpha/beta/rc tags. -release = '2.0.0b0' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = True - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'alabaster' - -# 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 -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# 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'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Language to be used for generating the HTML full-text search index. -# Sphinx supports the following languages: -# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' -# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' -#html_search_language = 'en' - -# A dictionary with options for the search language support, empty by default. -# Now only 'ja' uses this config value -#html_search_options = {'type': 'default'} - -# The name of a javascript file (relative to the configuration directory) that -# implements a search results scorer. If empty, the default will be used. -#html_search_scorer = 'scorer.js' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'PyPWAdoc' - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# 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', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'PyPWA.tex', u'PyPWA Documentation', - u'PyPWA Team', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'pypwa', u'PyPWA Documentation', - [author], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'PyPWA', u'PyPWA Documentation', - author, 'PyPWA', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index aaeb5803..00000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. PyPWA documentation master file, created by - sphinx-quickstart on Sun Nov 22 13:23:29 2015. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to PyPWA's documentation! -================================= - -Contents: - -.. toctree:: - :maxdepth: 2 - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/doc/source/isobar-fitting-tutorial.rst b/doc/source/isobar-fitting-tutorial.rst deleted file mode 100644 index 84574159..00000000 --- a/doc/source/isobar-fitting-tutorial.rst +++ /dev/null @@ -1,271 +0,0 @@ -===== -PyPWA Manual - Fitting -===== ------------------- -Step-by-step guide to PWA (mass-independent data fitting) using PyPWA -(using the scientific JLab batch farm) -(February 2015) ------------------- -:Authors: - C. Salgado, - M. Jones, - W. Phelps - -:Version: 1.0 07/01/2016 - - All software used by PyPWA can be downloaded from https://pypwa.jlab.org/. - - Installing PyPWA software needs full internet access i.e go to jlabs1 as ifarm1102 - doesn't have internet access. - - Create a PyPWA directory in your home directory. - - Untar your software. - - The general procedure of using PyPWA in the standard format (helicity formalism - and isobar model) to perform partial wave analysis is the following:: - - NOTE: - - It is advised that you read the general documentation in PyPWA/docs/, in the - wiki PyPWA, or the website before proceedings. For the general formalism consult: - C. W. Salgado and D. P. Weygand, Physics Report 537 (2014) 1-58 and references - within. - - These are detailed step-by-step instructions for PWA (fitting): - - Requirements (You'll need your own software for these steps): - - 1) Analyze your data to select the signal and crate a gamp format file with all - your events and name it data_events.gamp. - - We also allow for the use of a Q factor (i.e. the probability for each event to be - a signal, ie. Q=signal/(signal+background), to be included in the PWA fit. - Just create a file named QFactor.txt with the Q values of all events, one per line, written in the same order that the events are entered in data_events.gamp. - - 2) Run a full monte carlo simulation (generate+geant(detector + reconstruction + - analysis) using a flat phase-space generator (you can or can't include your t distribution there). Create two gamp formatted files: raw_events.gamp - with all the generated events, and acc_events.gamp with all the events obtained after the full simulation. - - You are ready to start using the PyPWA software. - - [1] Log in to an interactive farm machine (e.g. ifarm1102). (Note: You may need to contact your hall's scientific computing liason to get access to the Jlab scientific computing farm!) - - [2] Create a directory named as you like (for example after your reaction: e.g. Pippimpi0 – called here “MAIN”) - - [3] Move your files: data_events.gamp, raw_events.gamp, acc_events.gamp and QFactor.txt(if you have one) into that directory. - Copy PyPWA/pythonPWA/ from your home directory into that directory. - - [4] Go to the pythonPWA/batchFarmServices directory and run: fitting_Install - - A GUI called pwa_controls will pop-up (Note: There is a "help" button in the GUI itself). - - [5] Fill in the information and save. - {GUI HERE} - - - Figure 1: “Pwa_controls” GUI. The HELP button helps you to navigate this GUI. - - This action will create your full directory structure needed for your PWA. It can - take up to 30 minutes of execution (if you have a lot of events). This action prepares the directory structure, re-bin the data, move data to the right directories, transfer some information into numpy format and setup the necessary software. - - You will have the following directory structure such that name-of-reaction (“MAIN”):: - - - | - |_____________ fitting - | - |_____________ keyfiles - | - |_____________ scripts - |______________GUI - |______________pythonPWA - | |____batchFarmServices - | |____pythonPWA - | - |______________simulation - - - and - - fitting:: - - | - |_______overflow - |_______results - |_______mass_bin - | - |_______ data - | |_____ events.gamp - | |_____ events.num - | |_____ QFactor.txt (if you have any) - | - |_______ mc - | - |______ raw - | |____ events.gamp - | |____ events.num - | ______ acc - |____ events.gamp - |____ events.num ---------------------------------------- - - [6] Determine all waves you want to use and write a name .keyfile for each according to the gamp format (see general documentation). - Populate the MAIN/keyfiles/ directory with all your waves as for example: 0-1--1-P_rho.keyfile - (name includes wave definition: IGJPCMepsL_(isobar-if any).keyfile) - - After this is done you are ready to start running farm jobs. - - [7] go to the MAIN/GUI directory and run - - PWA_GUI - - This is the main GUI for the analysis. It will start with one column an after you make selections two new columns will be opening. - - - Figure 2: Main PWA GUI. - - - Then, what you need to do (in this order) is: - - [8] click fitting - - - A new layer if buttons will open (second column in figure 3),(the next commands will send farm jobs to run the programs: gamp, genAlpha for each of the waves and data sets:: - - [9] click Run Gamp - [10]click data - [11]click accMC - [12]click rawMC - - (these actions will create the necessary “waves” in binary format in each correct directory – files called name.bamp). These jobs can be run simultaneously. - - - Figure 3: Main GUI with selections for the second column and third column. - - - After clicking data, accMC and rawMC, command lines will be printed out (a line for each job, one per mass bin and keyfile) as they are being submitted to the batch system. All jobs, (3 * # mass bins * # of waves) will all run as separate jobs and not interfere with each other:: - - [13]click Gen Alpha - [14]click data - [15]click accMC - [16]click rawMC - - - (these actions create the alphaevents.txt files in each directory) - - You can submit the Run Gamp and Gen Alpha simultaneously, they will not interfere with each other. - - WAIT until everything is done in the farm. - You need to look at http://scicomp.jlab.org/scicomp/ to check that your jobs are all done and that there were successful (and with Exit Code of 0). - -------------------------------------------- - - - - [17]go back and click normint:: - - [18]click accMC - [19]click rawMC - - (these actions calculates accepted and raw normalization integrals for each mass bin) - - You can run accMC and rawMC jobs simultaneously. - - WAIT until everything is done in the farm. - You need to look at http://scicomp.jlab.org/scicomp/ to check that your jobs are all done and that there were successful (and with Exit Code of 0). - --------------------------------------------------- - - NOTE: before proceeding, check that all directories are filled with the necessary files for your PWA. - - The number of events in the files alphaevents.txt, events.gamp and events.num must be the same and the structure should look like this below (for example, for 9 waves in a 1000_MeV mass bin):: - - - 1000_MeV/ - |-- data - | |-- 0++0-S.bamp - | |-- 1--0-P.bamp - | |-- 1--1-P.bamp - | |-- 1--1+P.bamp - | |-- 2++0-D.bamp - | |-- 2++1-D.bamp - | |-- 2++1+D.bamp - | |-- 2++2-D.bamp - | |-- 2++2+D.bamp - | |-- alphaevents.txt - | |-- events.gamp - | |-- events.num - | |-- events.npy - | |-- rhoAA.npy - | -- QFactor.txt (if you have any) - `-- mc - |-- acc - | |-- 0++0-S.bamp - | |-- 1--0-P.bamp - | |-- 1--1-P.bamp - | |-- 1--1+P.bamp - | |-- 2++0-D.bamp - | |-- 2++1-D.bamp - | |-- 2++1+D.bamp - | |-- 2++2-D.bamp - | |-- 2++2+D.bamp - | |-- alphaevents.txt - | |-- events.gamp - | |-- events.npy - | |-- events.num - | `-- normint.npy - `-- raw - |-- 0++0-S.bamp - |-- 1--0-P.bamp - |-- 1--1-P.bamp - |-- 1--1+P.bamp - |-- 2++0-D.bamp - |-- 2++1-D.bamp - |-- 2++1+D.bamp - |-- 2++2-D.bamp - |-- 2++2+D.bamp - |-- alphaevents.txt - |-- events.gamp - |-- events.npy - |-- events.num - `-- normint.npy - - ------------------------------------------------------------------------------------- - - -- Fitting for each mass_bin (Mass-independent fit using Minuit) - - From the main GUI: - - [18] click Fitter (second column after clicking FITTING) - - All fitting jobs (one for each mass bin) will be submitted to the farm. The time required to run each job depends on number of events and number of waves used. - - WAIT until everything is done in the farm. You need to look at http://scicomp.jlab.org/scicomp/ to check that your jobs are all done and that there were successful (and with EC=0). - ---------------------------------------------------------------- - - --Calculate N_true and N_expected for each mass_bin - - [19] click nTrue (second column after clicking FITTING) - - All jobs will be submitted to the farm. The time required depends on number of events and number of waves used. These jobs calculate the number of events expected to be observed and the true (nature produce) for each mass bin as predicted from the fit, for each wave and in total. - WAIT until everything is done in the farm. You need to look at http://scicomp.jlab.org/scicomp/ to check that your jobs are all done and that there were successful (and with EC=0). - - -- Produce plots (for total and for each wave) - From the main GUI go back and - - [20] click Graphic Plot - - This will open a GUI (takes a few seconds). - - Figure Four: Graphic Plot Table - - If it is the first time looking at your results you need to Click "UPDATE RANGE", "UPDATE data", "UPDATE accMC", "UPDATE rawMC", and "UPDATE - FITTED (in that order) and then "SAVE" Select what you want to plot (one or more distributions from the panel. All are plotted as function of mass bin.) - - "PLOT" will plot all selected distributions. (see full description in documentation). - - - YOU ARE DONE WITH YOUR FIRST PWA FIT! diff --git a/doc/source/isobar-simulation-tutorial.rst b/doc/source/isobar-simulation-tutorial.rst deleted file mode 100644 index 5f635e75..00000000 --- a/doc/source/isobar-simulation-tutorial.rst +++ /dev/null @@ -1,315 +0,0 @@ -========================= PyPWA Manual - Simulation ========================= - ------------------------------------------------------------------------------- ---------------------------------- Step-by-step guide to PWA (mass-independent -data simulation) using PyPWA (using the scientific JLab batch farm) ---------- ------------------------------------------------------------------------------- ------------------------ - -:Authors C. Salgado, M. Jones, W. Phelps Version February 2015 - -All software used by PyPWA can be downloaded from https://pypwa.jlab.org/. - -Installing PyPWA software needs full internet access i.e go to jlabs1 as -ifarm1102 doesn't have internet access. - -For your new installation: Create a PyPWA directory in your home directory. -Untar your software. - -.. note:: It is advised that you read the general documentation, in the wiki -PyPWA, or the website before proceeding. For an overview of the general -formalism consult: C. W. Salgado and D. P. Weygand, Physics Report 537 (2014) -1-58 and references within. - -These are detailed step-by-step instructions for SIMULATION using the Isobar- -model based partial waves formalism: There are two ways to perform -simulations: - -A. You select a set of resonances, and for each resonance a set of waves, -decaying to the final state that you want to simulate. Then, you will -simulate mass distributions and produce sets of events in “gamp” format -(raw/generated) and accepted. :: resolution is not yet incorporated into -the framework. - -B. After you have fitted the data in a PWA (fitting). You can simulate -sets of events in “gamp” format (raw/generated) and accepted) according to -the waves and production amplitude (V's) that you obtained. The angular -distributions of the simulated events can be then compared with your data -to check your fits. We describe option - -C. first: Requirements (You'll need your own software for these steps) - -1) Run a full monte carlo simulation "(generate + Geant(detector -simulation) + Reconstruction(and analysis))" using a flat phase-space -generator (you can simulate using your reaction's t distribution). Create -a gamp formatted file: raw_events .gamp with all the generated events. -Create a pass/fail file events.pf (with 0 \(fail\) and 1 \(pass\) in each -line and the same order than the gamp file\). - -2) This file will map the accepted events after the full simulation -\(for weighting of the events without resubmitting new simulation). - -3) Create a “resonances.txt” file with the resonances you want to -simulate. You need to choose a set of resonances and the weight of each -resonance. - -For each resonance you can pick one or more waves from your wave set (in your -keyfiles/ directory). For a given resonance the waves will be given a weight -(0 to 1) for the participation in the resonance production. Determine all -waves you want to use and write a name .keyfile for each according to the gamp -format (see general documentation). Populate the MAIN/ directory with all your -waves as for example: 0-1--1-P_rho.keyfile. - -(name includes wave definition: IGJPCMepsL_isobar-ifany).keyfile) - -After this is done you are ready to start running farm jobs: - -For example if you want to generate a1_1(1260),a_2(1320), pi_1(1600) and -pi_2(1670), with a 27%, 45%, 6% and 22% relative weights. Suppose also that -you have four waves P1, D1, P0, D1 and you want to assign only one of the -waves to each of the resonances. For example: - - - - # resonances.txt is the control file that simulatorMain uses to get -resonances to simulate from waves. # Add resonances starting on line 7 in -the format cR (float) wR (list) w0 (float) r0 (float) phase (float) # The -sum of all cR for /all/ resonances needs to be 1.0 and the sum of the wR list -for /each/ resonance needs to be 1.0 # Ex: 1.0 1.0,0.0 1.0 0.5 0.0 -# One resonance to a line and use the # to comment. # 0.27 1,0,0,0 -1260. 300. 0. 0.45 0,1,0,0 1320. 107. 0. 0.06 0,0,1,0 1600. 234. 0. -0.22 0,0,0,1 1670. 259. 0. - - - -You are ready to start using the PyPWA software. - -1. Log in to a interactive farm machine (e.g. ifarm1102). (Note: You may -need to contact your hall's scientific computing liason to get access to -the Jlab scientific computing farm!) - -2. Create a directory named as you like (for example after your -reaction: e.g. Pippimpi0 – called here “MAIN”) - -3. Move your files: raw_events.gamp, events.pf and the keyfiles of the -waves you want to simulate into that directory. Copy also, from your home -directory, PyPWA/pythonPWA/ into that directory. - - Go to the pythonPWA/batchFarmServices directory and - -4. run: simulation_Install - -A GUI called pwa_controls will pop-up - -.. note:: There is a "help" button in the GUI itself. - -5. Fill in the information and save. - -Figure 1: “Pwa_controls” GUI. The HELP button helps you to navigate this GUI. -This action will create your full directory structure needed for SIMULATION. -It can take up to 30 minutes of execution (if you have a lot of events). This -action prepares the directory structure, re-bin the data, move data to the -right directories, transfer some information into numpy format and setup the -necessary software. - - - -You will have the following directory structure such that-name-of-reaction -(“MAIN”):: - - - | |_____________ keyfiles - | |_____________ scripts - |______________GUI - |______________pythonPWA - | - |____batchFarmServices - | \____pythonPWA - | - |______________simulation - - and: - - simulation | - |_______overflow - |_______mass_bin (chosen set) | - |_______ - |flat - | - |_____ events.gamp - | |_____ events.num - | |_____ events.pf - | - |_______|weight - | |______ raw | - |____ empty-for-now (events.gamp) | | - |______ acc - |____ empty-for-now (events.gamp - |____ and events_pf.gamp) - - - -6. Go to the MAIN/GUI directory and run PWA_GUI This is the main GUI for -the analysis. It will start with one column an after you make selections -two new columns will be opening. - - Figure 2: Main PWA GUI. - -Then, what you need to do (in this order) is: - -7. click simulation :: - - A new layer if buttons will open (second column in figure 3),(the next - commands will send farm jobs to run the programs: gamp, genAlpha for each - of the waves and data sets. - -8. click Run Gamp - -9. click Gen Alpha - - These actions will: - - a) Create the necessary “waves” in binary format in each correct - directory – files called name.bamp in the flat/ directory). - - - Figure 3: Main GUI with selections for the second column. - - -After clicking command lines will be printed out (a line for each job, one per -mass bin and keyfile) as they are being submitted to the batch system. All -jobs, (# of mass bins) will all run as separate jobs and not interfere with -each other. b) create the alphaevents.txt files in each mass-flat directory. - -You can submit the Run Gamp and Gen Alpha simultaneously, they will not -interfere with each other. WAIT until everything is done in the farm. - -You need to look at http://scicomp.jlab.org/scicomp/ to check that your jobs -are all done and that there were successful (and with Exit Code of 0). - - - -10. click normint :: - - (these actions calculates raw normalization integrals for each mass bin) - (WAIT until everything is done on the farm. You need to look at - (http://scicomp.jlab.org/scicomp/ to check that your jobs are all done and - (that there were successful (and with Exit Code of 0). - -11. click iList :: - - This creates the iList.npy with the calculated intensities for each event - in each mass bin. Also rhoAA.npy to be used to calculate intensities. - -12. click iMax :: - - This calculates the maximum intensity in all masses to normalize MC. It is - running in your computer is very fast it will print "DONE!". - - -.. note :: - - Before proceeding, check that all directories are filled with the - corresponding necessary files for your SIMULATION.The number of events in - the files alphaevents.txt, events.gamp and events.num must be the same and - the structure should look like this below (for example, for 4 waves in a - 1000_MeV mass bin). - - - - - 1000_MeV/ - |-- flat - | |-- 1--1-P.bamp - | |--1--1+P.bamp - | |-- 2++0-D.bamp - | |-- 2++1-D.bamp - | |-- alphaevents.txt - | |-- events.gamp - | |-- events.num - | |-- events.npy - | |-- rhoAA.npy - | |-- events.pf - | |-- iList.npy - | |-- normint.npy - | |-- rhoAA.npy - `-- weight - |-- acc - `-- raw - - -Simulation for each mass_bin (Mass-independent fit using Minuit) from the main -GUI: - -13. click Simulator - - All simulation jobs (one for each mass bin) will be submitted to the farm. - The time required to run each job depends on number of events and number - of waves used. :: WAIT until everything is done in the farm. You need to - look at http://scicomp.jlab.org/scicomp/ to check that your jobs are all - done and that there were successful (and with Exit Code of 0). - -The simulation will produce the following files: - - - (for each mass bin) weight/raw/events.gamp Generated events (weighted) - according to resonance/wave set intensity. weight/raw/events_pf.gamp - Accepted eventsno-weighted (phase space) weight/acc/events.gamp Accepted - events (weighted) according to resonance/wave set intensity. - flat/wnList.npy List of weights (intensity normalized) for each event. - flat/calcVvalues.npy Calculated values of the production amplitudes - (V's). flat/nTrueListR.npy nTrue values (total and for each wave). - - -Produce plots (for total and for each wave) from the main GUI go back and - -14. click Graphic Plot :: - - This will open a GUI (takes a few seconds). If it is the first time - looking at your results you need to Click "UPDATE RANGE", "UPDATE flat", - "UPDATE accUM", "UPDATE rawW", and "UPDATE accW" and nTrue(in that - order) and then "SAVE". - -Select what you want to plot (one or more distributions from the panel. All -are plotted as function of mass bin.) "PLOT" will plot all selected -distributions. (see full description in documentation). - -YOU ARE DONE WITH YOUR FIRST PWA FIT! - -Subsection 1.1.1 Option (B) ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Now, we will describe option (B): - - -Working from step 1 of the “Requirements” section (Monte Carlo). Instead of -the resonances.txt, you will need to move the Vvalues.npy files from each mass -bin to the created (below) mass bin in the new directory structure. You also -need to be sure to have the same keyfiles you used in your fit into the -keyfile/ directory (see below). - -Execute [1] and [9] Be sure that you have the correspondent “bamp” files to -your waves, and the Vvalues.npy files on each of the mas bin directories. As -for example, for waves 1—1-P and 1—1+P you will have - - - - 1000_MeV/ - |--Vvalues.npy - |-- flat | - |-- 1--1-P.bamp - |-- 1--1+P.bamp | - |-- alphaevents.txt | - |-- events.gamp | - |--events.num | - |-- events.npy | - |-- rhoAA.npy | - |-- events.pf | - |-- iList.npy | - |-- normint.npy | - |-- rhoAA.npy - `-- weight - |--acc - `-- raw - -Proceed as in option (A) from [10]. - diff --git a/doc/source/modules.rst b/doc/source/modules.rst deleted file mode 100644 index cc25689e..00000000 --- a/doc/source/modules.rst +++ /dev/null @@ -1,7 +0,0 @@ -PyPWA -===== - -.. toctree:: - :maxdepth: 4 - - PyPWA diff --git a/setup.cfg b/setup.cfg index 1ff32256..b0fc2709 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,9 +1,9 @@ [bdist_rpm] -release = 2.0.0-rc4 -packager = PyPWA Team +release = 2.0.0 +packager = PyPWA Team doc_files = README.md provides = PyPWA -requires = python numpy PyYaml +requires = python numpy [bdist_wheel] universal = 1 diff --git a/setup.py b/setup.py index 04a01eae..05853917 100644 --- a/setup.py +++ b/setup.py @@ -14,51 +14,56 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import sys from setuptools import setup, find_packages -__author__ = "Mark Jones" +__author__ = "PyPWA Team and Contributors" __license__ = "GPLv3" -__version__ = "2.0.0-rc5" -__maintainer__ = "Mark Jones" -__email__ = "maj@jlab.org" -__status__ = "development" +__version__ = "2.0.0" +__email__ = "pypwa@jlab.org" +__status__ = "production" +requires = [ + "iminuit<2.0", # Default minimizer + "scipy", # Needed for Nestle with multiple ellipsoids. + "nestle", # New more advanced minimizer + "numpy>1,<2.0", # Arrays and optimizations + "ruamel.yaml", # Advanced YAML Parser + "tabulate", # Great aesthetic tables + "appdirs", # Attempts to find data locations + "fuzzywuzzy", # Fuzzes the user input + "python-Levenshtein", + 'enum34;python_version<"3.4"', + 'typing;python_version<"3.5"' +] + +configurator_entry = "PyPWA.entries.configurator" + +entry_points = { + "console_scripts": [ + "PyFit = %s:py_fit" % configurator_entry, + "LikelihoodFit = %s:likelihood_fit" % configurator_entry, + "ChiSquaredFit = %s:chi_squared_fit" % configurator_entry, + "PySimulate = %s:py_simulate" % configurator_entry, + "GenerateIntensities = %s:generate_intensities" % configurator_entry, + "GenerateWeights = %s:generate_weights" % configurator_entry + ] +} + setup( name="PyPWA", version=__version__, - author="PyPWA Team", - author_email="maj@jlab.org", + author=__author__, + author_email=__email__, packages=find_packages(), url="http//pypwa.jlab.org", license=__license__, description="General Partial Wave Analysis", test_suite="tests", - entry_points={ - "console_scripts": [ - "PyFit = PyPWA.entries.shell:general_fitting", - "LikelihoodFit = PyPWA.entries.shell:likelihood_fitting", - "ChiSquaredFit = PyPWA.entries.shell:chi_squared", - "PySimulate = PyPWA.entries.shell:simulator", - "GenerateIntensities = PyPWA.entries.shell:intensities", - "GenerateWeights = PyPWA.entries.shell:rejection_method" - ] - }, + entry_points=entry_points, keywords="PyPWA GeneralFitting Partial Wave Analysis Minimization", - install_requires=[ - "typing", # Support for function typing - "iminuit<2.0", # Default minimizer - "nestle", # New more advanced minimizer - "numpy<2.0", # Arrays and optimizations - "ruamel.yaml", # Advanced YAML Parser - "tabulate", # Great aesthetic tables - "appdirs", # Attempts to find data locations - "fuzzywuzzy", # Fuzzes the user input - "python-Levenshtein" - ], - extras_require={ - 'multinest': ["pymultinest"] - }, + install_requires=requires, setup_requires=['pytest-runner'], tests_require=['pytest', "pytest-cov", "pytest-logging"], classifiers=[ diff --git a/tests/builtin_plugins/data/builtin/sv/test_s_memory.py b/tests/builtin_plugins/data/builtin/sv/test_s_memory.py index 810a9bd3..9ec5f38d 100644 --- a/tests/builtin_plugins/data/builtin/sv/test_s_memory.py +++ b/tests/builtin_plugins/data/builtin/sv/test_s_memory.py @@ -21,18 +21,29 @@ from PyPWA.builtin_plugins.data.builtin.sv import s_memory TEMP_WRITE_LOCATION = os.path.join( - os.path.dirname(__file__), "../test_docs/temporary_write_data" + os.path.dirname(__file__), + "../../../../data/test_docs/temporary_write_data" ) CSV_TEST_DATA = os.path.join( - os.path.dirname(__file__), "../test_docs/sv_test_data.csv" + os.path.dirname(__file__), "../../../../data/test_docs/sv_test_data.csv" +) + +CSV_TEST_DATA_2 = os.path.join( + os.path.dirname(__file__), "../../../../data/pyfit/data/data.csv" ) TSV_TEST_DATA = os.path.join( - os.path.dirname(__file__), "../test_docs/sv_test_data.tsv" + os.path.dirname(__file__), "../../../../data/test_docs/sv_test_data.tsv" ) +@pytest.fixture +def full_data(): + parser = s_memory.SvMemory() + return parser.parse(CSV_TEST_DATA_2) + + @pytest.fixture(scope="module") def numpy_flat(): data = numpy.zeros(30, [("x", "f8"), ("y", "f8"), ("z", "f8")]) @@ -67,6 +78,10 @@ def looping_parser_test_data(numpy_flat, request): os.remove(request.param) +def test_full_data_has_expected_data(full_data): + assert full_data['v'][3] == 0.19246017603470056 + + def test_read_data_matches_expected(return_parsed_data): """ Args: diff --git a/tests/builtin_plugins/data/builtin/sv/test_s_read_test.py b/tests/builtin_plugins/data/builtin/sv/test_s_read_test.py index c4e3e6cf..56dca587 100644 --- a/tests/builtin_plugins/data/builtin/sv/test_s_read_test.py +++ b/tests/builtin_plugins/data/builtin/sv/test_s_read_test.py @@ -21,19 +21,20 @@ from PyPWA.builtin_plugins.data.builtin.sv import s_read_tests CSV_TEST_DATA = os.path.join( - os.path.dirname(__file__), "../test_docs/sv_test_data.csv" + os.path.dirname(__file__), "../../../../data/test_docs/sv_test_data.csv" ) TSV_TEST_DATA = os.path.join( - os.path.dirname(__file__), "../test_docs/sv_test_data.tsv" + os.path.dirname(__file__), "../../../../data/test_docs/sv_test_data.tsv" ) BAD_CSV_TEST_DATA = os.path.join( - os.path.dirname(__file__), "../test_docs/sv_test_data_bad.csv" + os.path.dirname(__file__), + "../../../../data/test_docs/sv_test_data_bad.csv" ) NOISE_TEST_DATA = os.path.join( - os.path.dirname(__file__), "../test_docs/noise_test_data" + os.path.dirname(__file__), "../../../../data/test_docs/noise_test_data" ) diff --git a/tests/builtin_plugins/data/builtin/test_data_plugin.py b/tests/builtin_plugins/data/builtin/test_data_plugin.py index 63aaf366..310a1b22 100644 --- a/tests/builtin_plugins/data/builtin/test_data_plugin.py +++ b/tests/builtin_plugins/data/builtin/test_data_plugin.py @@ -19,22 +19,22 @@ import pytest from PyPWA.builtin_plugins.data import data_templates from PyPWA.builtin_plugins.data.builtin import sv, kv, gamp -from PyPWA.core.templates import interface_templates +from PyPWA.core.shared.interfaces import internals TEMP_WRITE_LOCATION = os.path.join( - os.path.dirname(__file__), "test_docs/temporary_write_data" + os.path.dirname(__file__), "../../../data/test_docs/temporary_write_data" ) CSV_TEST_DATA = os.path.join( - os.path.dirname(__file__), "test_docs/sv_test_data.csv" + os.path.dirname(__file__), "../../../data/test_docs/sv_test_data.csv" ) GAMP_TEST_DATA = os.path.join( - os.path.dirname(__file__), "test_docs/gamp_test_data.gamp" + os.path.dirname(__file__), "../../../data/test_docs/gamp_test_data.gamp" ) EVIL_TEST_DATA = os.path.join( - os.path.dirname(__file__), "test_docs/kv_test_data.txt" + os.path.dirname(__file__), "../../../data/test_docs/kv_test_data.txt" ) @pytest.fixture( @@ -103,7 +103,7 @@ def test_get_plugin_reader_returns_reader(setup_plugin_object): """ assert isinstance( setup_plugin_object[0].get_plugin_reader(setup_plugin_object[1]), - interface_templates.ReaderInterfaceTemplate + internals.Reader ) @@ -114,5 +114,5 @@ def test_get_plugin_writer_returns_writer(setup_plugin_object): """ assert isinstance( setup_plugin_object[0].get_plugin_writer(TEMP_WRITE_LOCATION), - interface_templates.WriterInterfaceTemplate + internals.Writer ) diff --git a/tests/builtin_plugins/data/builtin/test_gamp_plugin.py b/tests/builtin_plugins/data/builtin/test_gamp_plugin.py index 2cf9f206..81355aae 100644 --- a/tests/builtin_plugins/data/builtin/test_gamp_plugin.py +++ b/tests/builtin_plugins/data/builtin/test_gamp_plugin.py @@ -9,15 +9,15 @@ from PyPWA.builtin_plugins.data.builtin.gamp import g_read_tests CSV_TEST_DATA = os.path.join( - os.path.dirname(__file__), "test_docs/sv_test_data.csv" + os.path.dirname(__file__), "../../../data/test_docs/sv_test_data.csv" ) GAMP_TEST_DATA = os.path.join( - os.path.dirname(__file__), "test_docs/gamp_test_data.gamp" + os.path.dirname(__file__), "../../../data/test_docs/gamp_test_data.gamp" ) TEMP_WRITE_LOCATION = os.path.join( - os.path.dirname(__file__), "test_docs/temporary_write_data" + os.path.dirname(__file__), "../../../data/test_docs/temporary_write_data" ) @@ -70,10 +70,3 @@ def test_GAMPMemory_LoopingKnownData_DataMatches(): def test_GAMPReader_ResetReader_NoFail(): reader = g_iterator.GampReader(GAMP_TEST_DATA) reader.reset() - - -def test_GAMPReader_PreviousEvent_MatchesNext(): - reader = g_iterator.GampReader(GAMP_TEST_DATA) - old = reader.next_event - - numpy.testing.assert_array_equal(old, reader.previous_event) \ No newline at end of file diff --git a/tests/builtin_plugins/data/builtin/test_kv_plugin.py b/tests/builtin_plugins/data/builtin/test_kv_plugin.py index 5ab5bd57..9b438fc9 100644 --- a/tests/builtin_plugins/data/builtin/test_kv_plugin.py +++ b/tests/builtin_plugins/data/builtin/test_kv_plugin.py @@ -41,27 +41,28 @@ # the information needed to test the data loader and writer. KV_TEST_DATA = os.path.join( - os.path.dirname(__file__), "test_docs/kv_test_data.txt" + os.path.dirname(__file__), "../../../data/test_docs/kv_test_data.txt" ) KV_FLOAT_DATA = os.path.join( - os.path.dirname(__file__), "test_docs/kv_floats_test_data.txt" + os.path.dirname(__file__), + "../../../data/test_docs/kv_floats_test_data.txt" ) KV_BOOL_DATA = os.path.join( - os.path.dirname(__file__), "test_docs/kv_bool_test_data.txt" + os.path.dirname(__file__), "../../../data/test_docs/kv_bool_test_data.txt" ) KV_WRITE_DATA = os.path.join( - os.path.dirname(__file__), "test_docs/kv_write_test.txt" + os.path.dirname(__file__), "../../../data/test_docs/kv_write_test.txt" ) CSV_TEST_DATA = os.path.join( - os.path.dirname(__file__), "test_docs/sv_test_data.csv" + os.path.dirname(__file__), "../../../data/test_docs/sv_test_data.csv" ) TEMP_WRITE_LOCATION = os.path.join( - os.path.dirname(__file__), "test_docs/temporary_write_data" + os.path.dirname(__file__), "../../../data/test_docs/temporary_write_data" ) diff --git a/tests/builtin_plugins/data/cache/test_basic_info.py b/tests/builtin_plugins/data/cache/test_basic_info.py index 933ccee2..c72aa047 100644 --- a/tests/builtin_plugins/data/cache/test_basic_info.py +++ b/tests/builtin_plugins/data/cache/test_basic_info.py @@ -20,7 +20,7 @@ DATA = os.path.join( - os.path.dirname(__file__), "../builtin/test_docs/sv_test_data.csv" + os.path.dirname(__file__), "../../../data/test_docs/sv_test_data.csv" ) SIMPLE_STRING = "1234567890aoeuidhtns-" @@ -30,22 +30,22 @@ @pytest.fixture def mock_hash(monkeypatch): - def returns_string(throw, stream): + def returns_string(file_name): return SIMPLE_STRING monkeypatch.setattr( - "PyPWA.core.tools.FileHashString.get_sha512_hash", + "PyPWA.core.shared.generate_hash.get_sha512_hash", returns_string ) @pytest.fixture def mock_cache_uri(monkeypatch): - def returns_string(throw): + def returns_string(): return FAKE_LOCATION monkeypatch.setattr( - "PyPWA.core.tools.DataLocation.get_cache_uri", + "PyPWA.core.shared.data_locator.get_cache_uri", returns_string ) @@ -60,11 +60,6 @@ def standard_basic_info(): return _basic_info.FindBasicInfo(DATA) -@pytest.fixture -def basic_info_interface(): - return _basic_info.BasicInfoInterface() - - def test_basic_info_hash_is_string(standard_basic_info): assert isinstance(standard_basic_info.file_hash, str) @@ -80,12 +75,3 @@ def test_mock_basic_info_equals_simple_string(mocked_basic_info): def test_mock_basic_info_equals_fake_location(mocked_basic_info): assert mocked_basic_info.cache_location \ == FAKE_LOCATION + "/sv_test_data.pickle" - -def test_interface_file_hash_raises_error(basic_info_interface): - with pytest.raises(NotImplementedError): - basic_info_interface.file_hash - - -def test_interface_cache_location_raises_error(basic_info_interface): - with pytest.raises(NotImplementedError): - basic_info_interface.cache_location diff --git a/tests/builtin_plugins/data/cache/test_builder.py b/tests/builtin_plugins/data/cache/test_builder.py index 2f52dfb0..750d1b3d 100644 --- a/tests/builtin_plugins/data/cache/test_builder.py +++ b/tests/builtin_plugins/data/cache/test_builder.py @@ -230,7 +230,7 @@ def test_read_cache(param_wrapper): def test_cache_is_valid(param_wrapper): with pytest.raises(param_wrapper[1]["valid"]): - param_wrapper[0].is_valid + param_wrapper[0].is_valid() @pytest.fixture @@ -244,4 +244,4 @@ def cache_with_no_file( def test_cache_is_not_valid_when_no_file(cache_with_no_file): with pytest.raises(DidNotRead): - cache_with_no_file.is_valid + cache_with_no_file.is_valid() diff --git a/tests/builtin_plugins/data/cache/test_clear_cache.py b/tests/builtin_plugins/data/cache/test_clear_cache.py index 73ec416f..195fe6d6 100644 --- a/tests/builtin_plugins/data/cache/test_clear_cache.py +++ b/tests/builtin_plugins/data/cache/test_clear_cache.py @@ -20,7 +20,11 @@ from PyPWA.builtin_plugins.data import exceptions -class BasicTestInfo(_basic_info.BasicInfoInterface): +class BasicTestInfo(_basic_info.FindBasicInfo): + + def __init__(self): + # We don't actually want to run the init + pass @property def file_hash(self): @@ -69,7 +73,7 @@ def clear_cache_without_success(setup_test_info, mock_os_remove_no_file): def test_is_valid_is_false(clear_cache_with_success): - assert not clear_cache_with_success.is_valid + assert not clear_cache_with_success.is_valid() def test_get_cache_raises_error(clear_cache_without_success): diff --git a/tests/builtin_plugins/data/cache/test_no_cache.py b/tests/builtin_plugins/data/cache/test_no_cache.py index ca835b2e..89870f9b 100644 --- a/tests/builtin_plugins/data/cache/test_no_cache.py +++ b/tests/builtin_plugins/data/cache/test_no_cache.py @@ -34,7 +34,7 @@ def test_writer_doesnt_fail(NoWrite): def test_reader_isnt_valid(NoRead): - assert not NoRead.is_valid + assert not NoRead.is_valid() def test_reader_get_cache(NoRead): diff --git a/tests/builtin_plugins/data/cache/test_standard_cache.py b/tests/builtin_plugins/data/cache/test_standard_cache.py index 1a71f5dd..e99683ad 100644 --- a/tests/builtin_plugins/data/cache/test_standard_cache.py +++ b/tests/builtin_plugins/data/cache/test_standard_cache.py @@ -29,13 +29,18 @@ TEMP_WRITE_LOCATION = os.path.join( - os.path.dirname(__file__), "../builtin/test_docs/temporary_write_data" + os.path.dirname(__file__), + "../../../data/test_docs/temporary_write_data" ) DATA = ";qjkxbmwvzpyfgcrl" -class InfoA(_basic_info.BasicInfoInterface): +class InfoA(_basic_info.FindBasicInfo): + + def __init__(self): + # We don't actually want to run the init + pass @property def file_hash(self): @@ -46,7 +51,12 @@ def cache_location(self): return TEMP_WRITE_LOCATION -class InfoB(_basic_info.BasicInfoInterface): +class InfoB(_basic_info.FindBasicInfo): + + def __init__(self): + # We don't actually want to run the init + pass + @property def file_hash(self): return "1234567890aoeuidhtns" @@ -107,7 +117,7 @@ def induced_pickle_error(write_a, basic_info_a): def test_read_is_valid_true(wrapping_pass_read): - assert wrapping_pass_read.is_valid is True + assert wrapping_pass_read.is_valid() is True def test_get_cache_matches_read(wrapping_pass_read): @@ -115,7 +125,7 @@ def test_get_cache_matches_read(wrapping_pass_read): def test_read_is_valid_false(wrapping_fail_read): - assert not wrapping_fail_read.is_valid + assert not wrapping_fail_read.is_valid() def test_get_cache_raises_error(wrapping_fail_read): @@ -124,7 +134,7 @@ def test_get_cache_raises_error(wrapping_fail_read): def test_read_is_valid_false_with_bad_pickle(induced_pickle_error): - assert not induced_pickle_error.is_valid + assert not induced_pickle_error.is_valid() def test_get_cache_raises_error_with_bad_pickle(induced_pickle_error): @@ -133,7 +143,7 @@ def test_get_cache_raises_error_with_bad_pickle(induced_pickle_error): def test_read_is_valid_false_with_no_cache(read_b): - assert not read_b.is_valid + assert not read_b.is_valid() def test_get_cache_raises_error_with_no_cache(read_b): diff --git a/tests/builtin_plugins/data/cache/test_template.py b/tests/builtin_plugins/data/cache/test_template.py index 71123c8f..f0c94ceb 100644 --- a/tests/builtin_plugins/data/cache/test_template.py +++ b/tests/builtin_plugins/data/cache/test_template.py @@ -35,7 +35,7 @@ def test_write_interface_write_cache(writer): def test_read_interface_is_valid(reader): with pytest.raises(NotImplementedError): - reader.is_valid + reader.is_valid() def test_read_interface_get_cache(reader): diff --git a/tests/builtin_plugins/data/test_iterator.py b/tests/builtin_plugins/data/test_iterator.py index 2c84ddc7..10eaad2f 100644 --- a/tests/builtin_plugins/data/test_iterator.py +++ b/tests/builtin_plugins/data/test_iterator.py @@ -7,15 +7,15 @@ from PyPWA.builtin_plugins.data import iterator CSV_TEST_DATA = os.path.join( - os.path.dirname(__file__), "builtin/test_docs/sv_test_data.csv" + os.path.dirname(__file__), "../../data/test_docs/sv_test_data.csv" ) GAMP_TEST_DATA = os.path.join( - os.path.dirname(__file__), "builtin/test_docs/gamp_test_data.gamp" + os.path.dirname(__file__), "../../data/test_docs/gamp_test_data.gamp" ) TEMP_WRITE_LOCATION = os.path.join( - os.path.dirname(__file__), "builtin/test_docs/temporary_write_data" + os.path.dirname(__file__), "../../data/test_docs/temporary_write_data" ) diff --git a/tests/builtin_plugins/data/test_memory.py b/tests/builtin_plugins/data/test_memory.py index 0031b287..0b25b112 100644 --- a/tests/builtin_plugins/data/test_memory.py +++ b/tests/builtin_plugins/data/test_memory.py @@ -6,11 +6,11 @@ from PyPWA.builtin_plugins.data import memory CSV_TEST_DATA = os.path.join( - os.path.dirname(__file__), "builtin/test_docs/sv_test_data.csv" + os.path.dirname(__file__), "../../data/test_docs/sv_test_data.csv" ) TEMP_WRITE_LOCATION = os.path.join( - os.path.dirname(__file__), "builtin/test_docs/temporary_write_data" + os.path.dirname(__file__), "../../data/test_docs/temporary_write_data" ) @@ -19,8 +19,8 @@ def parser_with_cache(): def raise_error(file_location): raise RuntimeError("Cache was not loaded!") - mem = memory.Memory(options={"enable cache": True}) - mem._read_data = raise_error + mem = memory.Memory(enable_cache=True) + mem.__read_data = raise_error return mem diff --git a/tests/builtin_plugins/data/test_plugin_finder.py b/tests/builtin_plugins/data/test_plugin_finder.py index a3f4c480..d62cc3cb 100644 --- a/tests/builtin_plugins/data/test_plugin_finder.py +++ b/tests/builtin_plugins/data/test_plugin_finder.py @@ -24,19 +24,19 @@ from PyPWA.builtin_plugins.data.builtin import sv, gamp CSV_TEST_DATA = os.path.join( - os.path.dirname(__file__), "builtin/test_docs/sv_test_data.csv" + os.path.dirname(__file__), "../../data/test_docs/sv_test_data.csv" ) GAMP_TEST_DATA = os.path.join( - os.path.dirname(__file__), "builtin/test_docs/gamp_test_data.gamp" + os.path.dirname(__file__), "../../data/test_docs/gamp_test_data.gamp" ) TEMP_WRITE_LOCATION = os.path.join( - os.path.dirname(__file__), "builtin/test_docs/temporary_write_data" + os.path.dirname(__file__), "../../data/test_docs/temporary_write_data" ) NOISE_LOCATION = os.path.join( - os.path.dirname(__file__), "builtin/test_docs/noise_test_data" + os.path.dirname(__file__), "../../data/test_docs/noise_test_data" ) diff --git a/tests/builtin_plugins/data/test_setups.py b/tests/builtin_plugins/data/test_setups.py new file mode 100644 index 00000000..906a751d --- /dev/null +++ b/tests/builtin_plugins/data/test_setups.py @@ -0,0 +1,46 @@ +import os + +import pytest + +from PyPWA.builtin_plugins import data +from PyPWA.core.configurator import option_tools + + +EXAMPLE_DATA = os.path.join( + os.path.dirname(__file__), "../../data/test_docs/sv_test_data.tsv" +) + + +@pytest.fixture() +def parser(): + template = data.DataParser.default_options + options = {"enable cache": False} + command = option_tools.CommandOptions(template, options) + setup = data.DataParser.setup(command) + return setup.return_interface() + + +@pytest.fixture() +def iterator(): + template = data.DataIterator.default_options + options = {"fail": True} + command = option_tools.CommandOptions(template, options) + setup = data.DataIterator.setup(command) + return setup.return_interface() + + +def test_parser_reads_example(parser): + data = parser.parse(EXAMPLE_DATA) + assert data["ctAD"][2] == -0.265433 + + +def test_iterator_reads_example(iterator): + reader = iterator.return_reader(EXAMPLE_DATA) + event1 = reader.next() + event2 = reader.next() + event3 = reader.next() + reader.close() + + assert event1["ctAD"] == -0.265433 + assert event2["phiAD"] == 0.675771 + assert event3["QFactor"] == 0.888493 diff --git a/tests/builtin_plugins/nestle/test_nestle.py b/tests/builtin_plugins/nestle/test_nestle.py new file mode 100644 index 00000000..2c012263 --- /dev/null +++ b/tests/builtin_plugins/nestle/test_nestle.py @@ -0,0 +1,42 @@ +import os + +import pytest + +from PyPWA.builtin_plugins import nestle +from PyPWA.core.configurator import option_tools + +SIMPLE_PRIOR = os.path.join( + os.path.dirname(__file__), "../../data/source_files/simple_prior.py" +) + + +def simple_function(x): + return 0.0 + + +@pytest.fixture() +def nested(): + template = nestle.NestleOptions.default_options + options = { + "prior location": SIMPLE_PRIOR, + "prior name": "prior", + "method": "classic", + "npoints": 4 + } + command = option_tools.CommandOptions(template, options) + setup = nestle.NestleOptions.setup(command) + return setup.return_interface() + + +@pytest.fixture() +def nested_save_data(nested): + yield nested + nested.save_extra("extra_data") + os.remove("extra_data.npy") + os.remove("extra_data.txt") + + +def test_nested_with_save(nested_save_data): + logl = lambda x: 0.0 + nested_save_data.main_options(logl) + nested_save_data.start() diff --git a/tests/builtin_plugins/process/test_forman.py b/tests/builtin_plugins/process/test_forman.py index 725a0283..98dcbf5d 100644 --- a/tests/builtin_plugins/process/test_forman.py +++ b/tests/builtin_plugins/process/test_forman.py @@ -2,9 +2,14 @@ import numpy import pytest +import logging from PyPWA.builtin_plugins.process import foreman, _communication -from PyPWA.core.templates import interface_templates +from PyPWA.core.shared.interfaces import internals +from PyPWA.core.shared import initial_logging + + +initial_logging.InternalLogger.set_level_to_global() def test_DuplexProcess_SumOfIntegers_Return50(): @@ -16,12 +21,13 @@ def test_DuplexProcess_SumOfIntegers_Return50(): test_data = {"the_data": numpy.ones(50)} # Create a test process kernel - class TestKernel(interface_templates.AbstractKernel): + class TestKernel(internals.Kernel): + __logger = logging.getLogger("TEST") the_data = False # type: numpy.ndarray def setup(self): - pass + self.__logger.debug("Test setup called!") def process(self, data=False): if data[0] == "go": # data is a tuple. @@ -33,8 +39,8 @@ def process(self, data=False): return "NO GO" # Create a test interface - class TestInterface(interface_templates.AbstractInterface): - is_duplex = True + class TestInterface(internals.KernelInterface): + IS_DUPLEX = True def run(self, communicator, arguments): for the_communicator in communicator: @@ -73,7 +79,7 @@ def test_SimplexProcess_SumIntegers_Return50(): test_data = {"the_data": numpy.ones(50)} # Create Kernel - class TestKernel(interface_templates.AbstractKernel): + class TestKernel(internals.Kernel): the_data = False # type: numpy.ndarray def setup(self): @@ -83,8 +89,8 @@ def process(self, data=False): return numpy.sum(self.the_data) # Create Interface - class TestInterface(interface_templates.AbstractInterface): - is_duplex = False + class TestInterface(internals.KernelInterface): + IS_DUPLEX = False def run(self, communicator, args): value = numpy.zeros(len(communicator)) @@ -112,8 +118,8 @@ def test_Kernels_WillFail_RaiseNotImplemented(): Check that Kernels will raise NotImplementedError if they are not overridden. """ - kernel = interface_templates.AbstractKernel() - interface = interface_templates.AbstractInterface() + kernel = internals.Kernel() + interface = internals.KernelInterface() with pytest.raises(NotImplementedError): kernel.process() diff --git a/tests/builtin_plugins/test_option_objects.py b/tests/builtin_plugins/test_option_objects.py new file mode 100644 index 00000000..342b1f3f --- /dev/null +++ b/tests/builtin_plugins/test_option_objects.py @@ -0,0 +1,53 @@ +import pytest +from PyPWA.core.configurator import options +from PyPWA.core.shared import plugin_loader +from PyPWA import builtin_plugins +from PyPWA.core import configurator + + +def load_plugins(): + loader = plugin_loader.PluginLoader() + loader.add_plugin_location([builtin_plugins, configurator]) + return loader.get_by_class(options.Plugin) + + +@pytest.fixture(params=load_plugins()) +def iterate_over_plugins(request): + return request.param() + + +def check_dict(the_dict): + assert isinstance(the_dict, dict) + + +def check_str(string): + assert isinstance(string, str) + assert string is not "" + + +def test_plugin_name(iterate_over_plugins): + check_str(iterate_over_plugins.plugin_name) + + +def test_default_options(iterate_over_plugins): + check_dict(iterate_over_plugins.option_difficulties) + + +def test_option_types(iterate_over_plugins): + check_dict(iterate_over_plugins.option_types) + + +def test_module_comment(iterate_over_plugins): + check_str(iterate_over_plugins.module_comment) + + +def test_option_comments(iterate_over_plugins): + check_dict(iterate_over_plugins.option_comments) + + +def test_setup(iterate_over_plugins): + assert issubclass(iterate_over_plugins.setup, options.Setup) + + +def test_provides(iterate_over_plugins): + assert iterate_over_plugins.provides in options.Types \ No newline at end of file diff --git a/tests/builtin_plugins/test_plugin_data.py b/tests/builtin_plugins/test_plugin_data.py deleted file mode 100644 index 36140918..00000000 --- a/tests/builtin_plugins/test_plugin_data.py +++ /dev/null @@ -1,33 +0,0 @@ -from PyPWA.builtin_plugins import data, process, minuit - - -def check_for_data(data_object): - data_object.request_options("required") - data_object.request_options("optional") - data_object.request_options("advanced") - data_object.request_options("template") - - data_object.request_metadata("name") - data_object.request_metadata("interface") - data_object.request_metadata("provides") - data_object.request_metadata("user functions") - - -def test_CheckDataIterator_OptionPasses(): - options = data.DataIterator() - check_for_data(options) - - -def test_CheckDataParser_OptionPasses(): - options = data.DataParser() - check_for_data(options) - - -def test_CheckProcess_OptionPasses(): - options = process.Processing() - check_for_data(options) - - -def test_CheckMinimizer_OptionPasses(): - options = minuit.MinuitOptions() - check_for_data(options) diff --git a/tests/core/configurator/create_config/test_create_config_builder.py b/tests/core/configurator/create_config/test_create_config_builder.py new file mode 100644 index 00000000..862365b7 --- /dev/null +++ b/tests/core/configurator/create_config/test_create_config_builder.py @@ -0,0 +1,38 @@ +import pytest +from PyPWA.core.configurator.create_config import _builder +from PyPWA.core.configurator.create_config import _metadata +from PyPWA.core.configurator.create_config import _questions +from PyPWA.shell import pysimulate + +PYSIM_CONFIG = { + "main": "shell simulation", + "main name": "Simulator", + "main options": { + "the type": "full", + "max intensity": None + } + } + + +@pytest.fixture() +def plugin_list(): + plugins = _metadata.GetPluginList() + plugins.parse_plugins(pysimulate.ShellSimulation) + return plugins + + +@pytest.fixture() +def levels_question(monkeypatch): + monkeypatch.setattr(_questions.GetPluginLevel, "_answer", "advanced") + return _questions.GetPluginLevel() + + +@pytest.fixture() +def build_config(plugin_list, levels_question): + build = _builder.BuildConfig(None, plugin_list, levels_question) + build.build(PYSIM_CONFIG) + return build + + +def test_builder_returns_dict(build_config): + assert isinstance(build_config.configuration, dict) diff --git a/tests/core/configurator/create_config/test_function_builder.py b/tests/core/configurator/create_config/test_function_builder.py new file mode 100644 index 00000000..2023411e --- /dev/null +++ b/tests/core/configurator/create_config/test_function_builder.py @@ -0,0 +1,25 @@ +import os + +import pytest + +from PyPWA.shell import pysimulate + +from PyPWA.core.configurator.create_config import _function_builder +from PyPWA.core.configurator.create_config import _metadata + + +@pytest.fixture() +def function_handler(): + return _function_builder.FunctionHandler() + + +@pytest.fixture() +def plugin_list(): + plugins = _metadata.GetPluginList() + plugins.parse_plugins(pysimulate.ShellSimulation) + return plugins + + +def test_function_builder(function_handler, plugin_list): + function_handler.output_functions(plugin_list, "test_functions") + os.remove("test_functions.py") diff --git a/tests/core/configurator/create_config/test_level_processing.py b/tests/core/configurator/create_config/test_level_processing.py new file mode 100644 index 00000000..ce8c4cac --- /dev/null +++ b/tests/core/configurator/create_config/test_level_processing.py @@ -0,0 +1,81 @@ +import os +import sys + +import pytest + +from PyPWA.core.configurator import options +from PyPWA.core.configurator.create_config import _level_processing + +sys.path.append(os.path.join( + os.path.dirname(__file__), "../../../data/source_files" +)) + +import simple_option_object + + +@pytest.fixture +def option(): + return simple_option_object.SimpleOptions + + +@pytest.fixture +def full_options(option): + return _level_processing._FullOptions(option) + + +@pytest.fixture(params=full_options(option()).difficulties) +def full_options_difficulties(request): + return request.param + + +def test_full_options_name(full_options): + assert "SimpleOptions" == full_options.name + + +def test_full_option_plugin_options(full_options): + assert "Option1" in full_options.plugin_options[full_options.name] + assert "Option2" in full_options.plugin_options[full_options.name] + assert "Option3" in full_options.plugin_options[full_options.name] + + +def test_full_option_difficulties_keys(full_options_difficulties): + assert isinstance(full_options_difficulties[0], str) + + +def test_full_option_difficulties_values(full_options_difficulties): + assert full_options_difficulties[1] in options.Levels + + +@pytest.fixture +def process_options(): + return _level_processing.ProcessOptions() + + +def test_process_options_required(process_options, option): + processed = process_options.processed_options( + option, options.Levels.REQUIRED + ) + + assert "Option1" in processed[option.plugin_name] + assert "Option2" not in processed[option.plugin_name] + assert "Option3" not in processed[option.plugin_name] + + +def test_process_options_optional(process_options, option): + processed = process_options.processed_options( + option, options.Levels.OPTIONAL + ) + + assert "Option1" in processed[option.plugin_name] + assert "Option2" in processed[option.plugin_name] + assert "Option3" not in processed[option.plugin_name] + + +def test_process_options_advanced(process_options, option): + processed = process_options.processed_options( + option, options.Levels.ADVANCED + ) + + assert "Option1" in processed[option.plugin_name] + assert "Option2" in processed[option.plugin_name] + assert "Option3" in processed[option.plugin_name] diff --git a/tests/core/configurator/create_config/test_metadata.py b/tests/core/configurator/create_config/test_metadata.py new file mode 100644 index 00000000..5f7bccde --- /dev/null +++ b/tests/core/configurator/create_config/test_metadata.py @@ -0,0 +1,51 @@ +import pytest +import sys + +from PyPWA.builtin_plugins import process +from PyPWA.shell import pysimulate, pyfit +from PyPWA.core.configurator import options +from PyPWA.core.configurator.create_config import _metadata + + +@pytest.fixture() +def metadata_storage(): + return _metadata.MetadataStorage() + + +@pytest.fixture() +def plugin_list(): + return _metadata.GetPluginList() + + +@pytest.fixture() +def mock_input_for_nestle(monkeypatch): + if sys.version_info.major == 2: + monkeypatch.setitem(__builtins__, "raw_input", lambda x: "Nestle") + else: + monkeypatch.setitem(__builtins__, "input", lambda x: "Nestle") + + +def test_metadata_storage_finds_builtin_parser(metadata_storage): + object = metadata_storage.search_plugin( + "Builtin Parser", options.Types.DATA_PARSER + ) + assert issubclass(object, options.Plugin) + + +def test_metadata_storage_finds_optimizers(metadata_storage): + object = metadata_storage.request_plugins_by_type( + options.Types.OPTIMIZER + ) + assert len(object) == 2 + + +def test_plugin_list_finds_pysimulate_plugins(plugin_list): + plugin_list.parse_plugins(pysimulate.ShellSimulation) + assert plugin_list.shell == pysimulate.ShellSimulation + assert process.Processing in plugin_list.plugins + + +def test_plugin_list_finds_pyfit_plugins(plugin_list, mock_input_for_nestle): + plugin_list.parse_plugins(pyfit.ShellFitting) + assert plugin_list.shell == pyfit.ShellFitting + assert process.Processing in plugin_list.plugins diff --git a/tests/core/configurator/create_config/test_override.py b/tests/core/configurator/create_config/test_override.py new file mode 100644 index 00000000..00b4f091 --- /dev/null +++ b/tests/core/configurator/create_config/test_override.py @@ -0,0 +1,45 @@ +import pytest + +from PyPWA.core.configurator.create_config import _override + + +def get_config(): + # Prevent bugs from configuration changing between tests. + return { + "shell function name": { + "should not be seen": 1, + "should also not be seen": 2, + "Perfectly Fine": 3 + } + } + +OVERRIDE_WITH_OPTIONS = { + "main": "shell function name", + "main name": "Shell Test", + "main options": { + "should not be seen": 10, + "should also not be seen": 20 + } +} + +OVERRIDE_WITHOUT_OPTIONS = { + "main": "shell function name", + "main name": "Shell Test" +} + + +@pytest.fixture() +def override(): + return _override.Override() + + +def test_override_with_options(override): + override.execute(get_config(), OVERRIDE_WITH_OPTIONS) + assert "should not be seen" not in \ + override.processed_configuration["Shell Test"] + + +def test_override_without_options(override): + override.execute(get_config(), OVERRIDE_WITHOUT_OPTIONS) + assert "should not be seen" in \ + override.processed_configuration["Shell Test"] diff --git a/tests/core/configurator/create_config/test_questions.py b/tests/core/configurator/create_config/test_questions.py new file mode 100644 index 00000000..a1292355 --- /dev/null +++ b/tests/core/configurator/create_config/test_questions.py @@ -0,0 +1,68 @@ +import sys + +import pytest + + +from PyPWA.core.configurator.create_config import _questions +from PyPWA.core.configurator import options + + +@pytest.fixture(params=["required", "optional", "advanced"]) +def input_options(monkeypatch, request): + mocked_input = lambda x: request.param + if sys.version_info.major == 2: + monkeypatch.setitem(__builtins__, "raw_input", mocked_input) + else: + monkeypatch.setitem(__builtins__, "input", mocked_input) + yield request.param + + +@pytest.fixture() +def get_plugin_level(): + return _questions.GetPluginLevel() + + +def test_get_plugin_level(input_options, get_plugin_level): + get_plugin_level.ask_for_plugin_level() + if input_options == "required": + assert get_plugin_level.get_plugin_level() == options.Levels.REQUIRED + elif input_options == "optional": + assert get_plugin_level.get_plugin_level() == options.Levels.OPTIONAL + else: + assert get_plugin_level.get_plugin_level() == options.Levels.ADVANCED + + +@pytest.fixture() +def input_location(monkeypatch): + if sys.version_info.major == 2: + monkeypatch.setitem(__builtins__, "raw_input", lambda x: "xhere") + else: + monkeypatch.setitem(__builtins__, "input", lambda x: "xhere") + + +@pytest.fixture() +def plugin_directory(): + return _questions.GetPluginDirectory() + + +def test_plugin_directory(input_location, plugin_directory): + plugin_directory.ask_for_plugin_directory() + assert plugin_directory.get_plugin_directory() == "xhere" + + +@pytest.fixture() +def save_location(): + return _questions.GetSaveLocation() + + +def test_save_location_from_input(save_location, input_location): + save_location.ask_for_save_location() + assert save_location.get_save_location() == "xhere" + + +def test_save_location_from_override(save_location): + save_location.override_save_location("elsewhere") + assert save_location.get_save_location() == "elsewhere" + + + diff --git a/tests/core/configurator/create_config/test_writer.py b/tests/core/configurator/create_config/test_writer.py new file mode 100644 index 00000000..5dff6456 --- /dev/null +++ b/tests/core/configurator/create_config/test_writer.py @@ -0,0 +1,31 @@ +import os + +import pytest + +from PyPWA.core.configurator.create_config import _writer + + +CONFIGURATION = { + "Shell Options": + { + "Option1": "string", + "Option2": False, + "Option3": 123, + "Option4": [1,2,3] + } +} + + +@pytest.fixture() +def writer(): + return _writer.Write() + + +def test_yml_writer(writer): + writer.write(CONFIGURATION, "test_config.yml") + os.remove("test_config.yml") + + +def test_json_writer(writer): + writer.write(CONFIGURATION, "test_config.json") + os.remove("test_config.json") diff --git a/tests/core/configurator/execute/test_correct_configuration.py b/tests/core/configurator/execute/test_correct_configuration.py new file mode 100644 index 00000000..446eac2d --- /dev/null +++ b/tests/core/configurator/execute/test_correct_configuration.py @@ -0,0 +1,129 @@ +import pytest + +from PyPWA.core.configurator.execute import _correct_configuration + +template_1 = { + "predetermined value": ["this", "that", "other"], + "numbers": int, + "exact value": float, + "is true": bool, + "a list": list +} + +template_2 = { + "general settings": { + "number of threads": int, + "debug": ["info", "debug", "warning"] + }, + "main": { + "settings": set, + "data": str, + "more nests": { + "correct": bool, + "settings": dict, + "extra data": str + } + } +} + +found_1 = { + "predetermin value": "othr", + "numbes": 5.001, + "exactvalue": 2.345, + "iss true": "tRue", + "the list": ["list", "of", "values"] +} + +found_2 = { + "General settigns": { + "nuM of threads": 5.2, + "debg": "inf" + }, + "MAIN": { + "setings": ["limit_A1", "limit_A1"], + "daTa": "/usr/local/this", + "moR nests": { + "extr dat": None, + "CoRRct": "tru", + "settngs": { + "somedata": "That we don't know about for whatever reason." + } + } + } +} + + +def temp1(self): + return template_1 + + +def temp2(self): + return template_2 + + +@pytest.fixture +def settings_aid_1(monkeypatch): + monkeypatch.setattr( + _correct_configuration._storage_data.Templates, + "get_templates", + temp1 + ) + aid = _correct_configuration.SettingsAid() + return aid.correct_settings(found_1) + + +@pytest.fixture +def settings_aid_2(monkeypatch): + monkeypatch.setattr( + _correct_configuration._storage_data.Templates, + "get_templates", + temp2 + ) + aid = _correct_configuration.SettingsAid() + return aid.correct_settings(found_2) + + +def test_1_predetermined_value(settings_aid_1): + assert settings_aid_1["predetermined value"] == "other" + + +def test_1_numbers(settings_aid_1): + assert settings_aid_1["numbers"] == 5 + + +def test_1_exact_value(settings_aid_1): + assert settings_aid_1["exact value"] == 2.345 + + +def test_1_is_true(settings_aid_1): + assert settings_aid_1["is true"] is True + + +def test_1_a_list(settings_aid_1): + assert settings_aid_1["a list"] == ["list", "of", "values"] + + +def test_2_number_of_threads(settings_aid_2): + assert settings_aid_2["general settings"]["number of threads"] == 5 + + +def test_2_debug(settings_aid_2): + assert settings_aid_2["general settings"]["debug"] == "info" + + +def test_2_settings(settings_aid_2): + assert settings_aid_2["main"]["settings"] == {"limit_A1"} + + +def test_2_data(settings_aid_2): + assert settings_aid_2["main"]["data"] == "/usr/local/this" + + +def test_2_more_nests(settings_aid_2): + assert settings_aid_2["main"]["more nests"]["correct"] is True + + +def test_2_extra_data(settings_aid_2): + assert isinstance( + settings_aid_2["main"]["more nests"]["extra data"], type(None) + ) diff --git a/tests/core/configurator/execute/test_plugin_data.py b/tests/core/configurator/execute/test_plugin_data.py new file mode 100644 index 00000000..61ebd373 --- /dev/null +++ b/tests/core/configurator/execute/test_plugin_data.py @@ -0,0 +1,37 @@ +import pytest + +from PyPWA.core.configurator.execute import _plugin_data + + +config = { + "blank shell module": { + "option 1": 123, + "optn 2": "A collection of words", + "Optional 3": "prest 2" + }, + "Builtin Parser": { + "Enable Cache": False + } + +} + + +class FakeSettings(object): + + @property + def loaded_settings(self): + return config + + @property + def plugin_ids(self): + return list(config.keys()) + + +@pytest.fixture +def setup_settings(): + return _plugin_data.SetupProgram(FakeSettings()) + + +def test_full_configurator_execute_with_blank_module(setup_settings): + setup_settings.setup() + setup_settings.execute() diff --git a/tests/core/configurator/execute/test_settings.py b/tests/core/configurator/execute/test_settings.py new file mode 100644 index 00000000..9b2817cf --- /dev/null +++ b/tests/core/configurator/execute/test_settings.py @@ -0,0 +1,85 @@ +import pytest + +import os +from PyPWA.core.configurator.execute import _settings + + +CONFIGURATION_FILE = os.path.join( + os.path.dirname(__file__), "../../../data/test_docs/configuration.yml" +) + +OVERRIDE = { + "main": "shell fitting method", + "main name": "General Fitting", + "main options": {"save name": "output file location"}, + "extras": None + } + + +@pytest.fixture +def setup(): + setup_object = _settings.Setup() + setup_object.load_settings(OVERRIDE, CONFIGURATION_FILE) + return setup_object + + +@pytest.fixture +def ids(setup): + return setup.plugin_ids + + +@pytest.fixture +def settings(setup): + return setup.loaded_settings + + +def test_names_are_in_ids(ids): + names = [ + "Builtin Parser", + "Builtin Multiprocessing", + "Minuit", + "shell fitting method" + ] + + for name in names: + assert name in ids + + +def test_general_fitting_none_settings(settings): + assert isinstance( + settings["shell fitting method"]['generated length'], type(None) + ) + + assert isinstance( + settings["shell fitting method"]['qfactor location'], type(None) + ) + + assert isinstance( + settings["shell fitting method"]['accepted monte carlo location'], + type(None) + ) + + +def test_general_fitting_presets(settings): + assert settings["shell fitting method"]['likelihood type'] == \ + "chi-squared" + + +def test_parser_boolean(settings): + assert isinstance(settings["Builtin Parser"]["enable cache"], bool) + assert settings["Builtin Parser"]["enable cache"] + + +def test_minuit_list(settings): + list_items = ['O1', 'O2', 'O3', 'O4', 'O5'] + for item in list_items: + assert item in settings["Minuit"]["parameters"] + + +def test_minuit_settings(settings): + assert settings["Minuit"]["settings"]['limit_O5'] == [-15., 10.] + + +def test_override_settings(settings): + assert settings["shell fitting method"]["save name"] == \ + "output file location" diff --git a/tests/core/configurator/execute/test_storage_data.py b/tests/core/configurator/execute/test_storage_data.py new file mode 100644 index 00000000..183ab53f --- /dev/null +++ b/tests/core/configurator/execute/test_storage_data.py @@ -0,0 +1,36 @@ +import pytest + +from PyPWA.core.configurator.execute import _storage_data + + +@pytest.fixture() +def module_picking(): + return _storage_data.ModulePicking() + + +@pytest.fixture() +def templates(): + loader = _storage_data.Templates() + return loader.get_templates() + + +def test_module_picking_can_find_builtin_parser(module_picking): + found_plugin = module_picking.request_plugin_by_name("Builtin Parser") + assert found_plugin is not None + + +def test_module_picking_can_find_shell_fitting_method(module_picking): + found_plugin = module_picking.request_main_by_id("shell fitting method") + assert found_plugin is not None + + +def test_template_is_dict(templates): + assert isinstance(templates, dict) + + +def test_global_settings_in_templates(templates): + assert "Global Options" in templates + + +def test_builtin_parser_in_templates(templates): + assert "Builtin Parser" in templates diff --git a/tests/core/configurator/test__tools.py b/tests/core/configurator/test__tools.py deleted file mode 100644 index 664f6346..00000000 --- a/tests/core/configurator/test__tools.py +++ /dev/null @@ -1,76 +0,0 @@ -from PyPWA.core.configurator import _tools - - -def test_SettingsAid_SimpleDict_ValuesCorrected(): - """ - Ensures that the right values are returned for a simple dictionary - """ - aid = _tools.SettingsAid() - - temp_dict = { - "predetermined value": ["this", "that", "other"], - "numbers": int, - "exact value": float, - "is true": bool, - "a list": list - } - - found_dict = { - "predetermin value": "othr", - "numbes": 5.001, - "exactvalue": 2.345, - "iss true": "tRue", - "the list": ["list", "of", "values"] - } - - correct = aid.correct_settings(found_dict, temp_dict) - - assert correct["predetermined value"] == "other" - assert correct["numbers"] == 5 - assert correct["exact value"] == 2.345 - assert correct["is true"] is True - assert correct["a list"] == ["list", "of", "values"] - - -def test_SettingsAid_NestedDict_ValuesCorrected(): - """ - Ensures that the right values are returned for multiple nested - dictionaries. - """ - aid = _tools.SettingsAid() - - temp_dict = { - "general settings": { - "number of threads": int, - "debug": ["info", "debug", "warning"] - }, - "main": { - "settings": set, - "data": str, - "more nests": { - "correct": bool - } - } - } - - found_dict = { - "General settigns": { - "nuM of threads": 5.2, - "debg": "inf" - }, - "MAIN": { - "setings": ["limit_A1", "limit_A1"], - "daTa": "/usr/local/this", - "moR nests": { - "CoRRct": "tru" - } - } - } - - correct = aid.correct_settings(found_dict, temp_dict) - - assert correct["general settings"]["number of threads"] == 5 - assert correct["general settings"]["debug"] == "info" - assert correct["main"]["settings"] == {"limit_A1"} - assert correct["main"]["data"] == "/usr/local/this" - assert correct["main"]["more nests"]["correct"] is True diff --git a/tests/core/configurator/test_configurator.py b/tests/core/configurator/test_configurator.py deleted file mode 100644 index cef9a308..00000000 --- a/tests/core/configurator/test_configurator.py +++ /dev/null @@ -1,30 +0,0 @@ -# PyPWA, a scientific analysis toolkit. -# Copyright (C) 2016 JLab -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -""" -Simple Tests for Configurator - -See Also: - PyPWA.configurator.configurator -""" - -__author__ = ["Mark Jones"] -__credits__ = ["Mark Jones"] -__maintainer__ = ["Mark Jones"] -__email__ = "maj@jlab.org" - - - diff --git a/tests/core/configurator/test_option_tools.py b/tests/core/configurator/test_option_tools.py new file mode 100644 index 00000000..be450f96 --- /dev/null +++ b/tests/core/configurator/test_option_tools.py @@ -0,0 +1,68 @@ +import pytest + +from PyPWA.core.configurator import options +from PyPWA.core.configurator import option_tools + + +configuration = { + "Option 1": 123, + "Option 2": "A collection of words", + "Option 3": ["Preset 2"], + "Option 4": "ABC" +} + +NO_OPTIONS = option_tools.CommandOptions(configuration, {}) +MIN_OPTIONS = option_tools.CommandOptions(configuration, {"Option 1": 231}) +FULL_OPTIONS = option_tools.CommandOptions( + configuration, + { + "Option 1": 321, + "Option 2": "words", + "Option 3": ["Preset 1"], + "Option 4": None + } +) + + +@pytest.fixture +def plugin_name_conversion(): + return option_tools.PluginNameConversion() + + +def test_conversion_can_get_enum(plugin_name_conversion): + plugin_type = plugin_name_conversion.external_to_internal("Data Parsing") + assert plugin_type == options.Types.DATA_PARSER + + +def test_conversion_can_get_name(plugin_name_conversion): + plugin_name = plugin_name_conversion.internal_to_external( + options.Types.KERNEL_PROCESSING + ) + + assert plugin_name == "Kernel Processor" + + +def test_command_default_options_set(): + assert NO_OPTIONS.option_1 == 123 + assert NO_OPTIONS.option_2 == "A collection of words" + assert NO_OPTIONS.option_3 == ["Preset 2"] + assert NO_OPTIONS.option_4 == "ABC" + + +def test_command_min_options_set(): + assert MIN_OPTIONS.option_1 == 231 + assert MIN_OPTIONS.option_2 == "A collection of words" + assert MIN_OPTIONS.option_3 == ["Preset 2"] + assert MIN_OPTIONS.option_4 == "ABC" + + +def test_command_full_options_set(): + assert FULL_OPTIONS.option_1 == 321 + assert FULL_OPTIONS.option_2 == "words" + assert FULL_OPTIONS.option_3 == ["Preset 1"] + assert isinstance(FULL_OPTIONS.option_4, type(None)) + + +def test_command_fails_correctly_with_attribute_error(): + with pytest.raises(AttributeError): + FULL_OPTIONS.option_5 \ No newline at end of file diff --git a/tests/core/configurator/test_options.py b/tests/core/configurator/test_options.py new file mode 100644 index 00000000..0db1db3e --- /dev/null +++ b/tests/core/configurator/test_options.py @@ -0,0 +1,22 @@ +import pytest +import enum + +from PyPWA.core.configurator import options + + +@pytest.fixture +def setup(): + return options.Setup() + + +def test_types_is_enum(): + assert issubclass(options.Types, enum.Enum) + + +def test_levels_is_enum(): + assert issubclass(options.Levels, enum.Enum) + + +def test_setup_return_interface_not_implemented(setup): + with pytest.raises(NotImplementedError): + setup.return_interface() diff --git a/tests/core/configurator/test_storage.py b/tests/core/configurator/test_storage.py index bfc41889..dab34cc0 100644 --- a/tests/core/configurator/test_storage.py +++ b/tests/core/configurator/test_storage.py @@ -1,24 +1,21 @@ -import PyPWA.builtin_plugins -from PyPWA.core import plugin_loader -from PyPWA.core.configurator import _storage -from PyPWA.core.templates import option_templates +import pytest +from PyPWA.core.configurator import storage +from PyPWA.shell import pyfit -def test_PluginStorage_RenderTemplate_IsDict(): - storage = _storage.PluginStorage() - assert isinstance(storage.templates_config, dict) +@pytest.fixture() +def module_storage(): + return storage.Storage() -def test_MetadataStorage_LoadPluginsRandomPlugins_PluginsSorted(): - loader = plugin_loader.PluginLoading( - option_templates.PluginsOptionsTemplate - ) - plugin_list = loader.fetch_plugin([PyPWA.builtin_plugins]) +def test_module_finds_shells(module_storage): + assert len(module_storage._get_shells()) != 0 - metadata_storage = _storage.MetadataStorage() - metadata_storage.add_plugins(plugin_list) - assert len(metadata_storage.data_parser) == 1 - assert len(metadata_storage.data_reader) == 1 - assert len(metadata_storage.kernel_processing) == 1 +def test_module_finds_fitter(module_storage): + assert pyfit.ShellFitting in module_storage._get_shells() + + +def test_module_finds_options(module_storage): + assert len(module_storage._get_plugins()) != 0 diff --git a/PyPWA/core/templates/__init__.py b/tests/core/shared/example_python_sheet.py similarity index 70% rename from PyPWA/core/templates/__init__.py rename to tests/core/shared/example_python_sheet.py index e5939ec5..b9b4b6bb 100644 --- a/PyPWA/core/templates/__init__.py +++ b/tests/core/shared/example_python_sheet.py @@ -14,11 +14,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -""" - -""" - from PyPWA import VERSION, LICENSE, STATUS +from PyPWA.core.configurator import options __author__ = ["Mark Jones"] __credits__ = ["Mark Jones"] @@ -27,3 +24,20 @@ __status__ = STATUS __license__ = LICENSE __version__ = VERSION + + +def the_meaning_of_life(): + return 42 + + +class OptionsTest(options.Plugin): + + plugin_name = "Does not exist" + default_options = {} + option_difficulties = {} + option_types = {} + module_comment = "I think, therefore I am." + option_comments = {} + defined_function = None + setup = None + provides = options.Types.KERNEL_PROCESSING diff --git a/tests/core/shared/interfaces/test_internals.py b/tests/core/shared/interfaces/test_internals.py new file mode 100644 index 00000000..e16afce4 --- /dev/null +++ b/tests/core/shared/interfaces/test_internals.py @@ -0,0 +1,108 @@ +import pytest + +from PyPWA.core.shared.interfaces import internals + + +@pytest.fixture +def reader(): + return internals.Reader() + + +@pytest.fixture +def writer(): + return internals.Writer() + + +@pytest.fixture(params=[internals.Reader, internals.Writer]) +def writer_and_reader(request): + return request.param + + +@pytest.fixture +def kernel(): + return internals.Kernel() + + +@pytest.fixture +def kernel_interface(): + return internals.KernelInterface() + + +@pytest.fixture +def minimization_option_parser(): + return internals.OptimizerOptionParser() + + +@pytest.fixture +def process_interface(): + return internals.ProcessInterface() + + +def test_reader_can_iterate(reader): + with pytest.raises(NotImplementedError): + for event in reader: + pass + + +def test_standard_reader_close(reader): + with pytest.raises(NotImplementedError): + reader.close() + + +def test_standard_writer_close(writer): + with pytest.raises(NotImplementedError): + writer.close() + + +def test_can_enter(writer_and_reader): + with pytest.raises(NotImplementedError): + with writer_and_reader(): + pass + + +def test_process_interface_run(process_interface): + with pytest.raises(NotImplementedError): + process_interface.run() + + +def test_process_interface_previous_value(process_interface): + with pytest.raises(NotImplementedError): + process_interface.previous_value + + +def test_process_interface_stop(process_interface): + with pytest.raises(NotImplementedError): + process_interface.stop() + + +def test_process_interface_is_alive(process_interface): + with pytest.raises(NotImplementedError): + process_interface.is_alive + + +def test_kernel_process_id(kernel): + assert kernel.PROCESS_ID is None + + +def test_kernel_setup(kernel): + with pytest.raises(NotImplementedError): + kernel.setup() + + +def test_kernel_process(kernel): + with pytest.raises(NotImplementedError): + kernel.process() + + +def test_kernel_interface_is_duplex(kernel_interface): + assert isinstance(kernel_interface.IS_DUPLEX, bool) + + +def test_kernel_interface_run(kernel_interface): + with pytest.raises(NotImplementedError): + kernel_interface.run("Send", [1, 2]) + + +def test_option_parser_convert_not_implemented(minimization_option_parser): + with pytest.raises(NotImplementedError): + minimization_option_parser.convert([1, 2, 3]) diff --git a/tests/core/shared/interfaces/test_plugins.py b/tests/core/shared/interfaces/test_plugins.py new file mode 100644 index 00000000..b4da7f43 --- /dev/null +++ b/tests/core/shared/interfaces/test_plugins.py @@ -0,0 +1,83 @@ +import pytest + +from PyPWA.core.shared.interfaces import plugins + + +@pytest.fixture +def minimizer(): + return plugins.Optimizer() + + +@pytest.fixture +def kernel_processing(): + return plugins.KernelProcessing() + + +@pytest.fixture +def data_parser(): + return plugins.DataParser() + + +@pytest.fixture +def data_iterator(): + return plugins.DataIterator() + + +@pytest.fixture +def main(): + return plugins.Main() + + +def test_minimizer_main_options_raise_not_implemented(minimizer): + with pytest.raises(NotImplementedError): + minimizer.main_options("Function Here", "ChiSquared") + + +def test_minimizer_start_raise_not_implemented(minimizer): + with pytest.raises(NotImplementedError): + minimizer.start() + + +def test_minimizer_return_parser_raise_not_implemented(minimizer): + with pytest.raises(NotImplementedError): + minimizer.return_parser() + + +def test_minimizer_save_extra_raise_not_implemented(minimizer): + with pytest.raises(NotImplementedError): + minimizer.save_extra("ChiSquared") + + +def test_kernel_proc_main_options_raise_not_implemented(kernel_processing): + with pytest.raises(NotImplementedError): + kernel_processing.main_options("Data", "Template", "Another Temp") + + +def test_kernel_proc_fetch_interface_raise_not_implemented(kernel_processing): + with pytest.raises(NotImplementedError): + kernel_processing.fetch_interface() + + +def test_data_parser_parse_raise_not_implemented(data_parser): + with pytest.raises(NotImplementedError): + data_parser.parse("file") + + +def test_data_parser_write_raise_not_implemented(data_parser): + with pytest.raises(NotImplementedError): + data_parser.write("file", "data") + + +def test_data_iterator_return_reader_raise_not_implemented(data_iterator): + with pytest.raises(NotImplementedError): + data_iterator.return_reader("File") + + +def test_data_iterator_return_writer_raise_not_implemented(data_iterator): + with pytest.raises(NotImplementedError): + data_iterator.return_writer("File", "shape") + + +def test_main_start_raises_not_implemented(main): + with pytest.raises(NotImplementedError): + main.start() diff --git a/tests/core/shared/test_data_locator.py b/tests/core/shared/test_data_locator.py new file mode 100644 index 00000000..41bbaab1 --- /dev/null +++ b/tests/core/shared/test_data_locator.py @@ -0,0 +1,35 @@ +import os + +from PyPWA.core.shared import data_locator + + +def DataLocation_TestHelper(location): + """ + Simple wrapper around tests for DataLocation. + Checks if the path to the returned file exists. + + Args: + location (str): The path to file. + """ + new_location = os.path.split(location) + assert os.path.exists(new_location[0]) + + +def test_DataLocation_FindCache_DirectoryReturned(): + location = data_locator.get_cache_uri() + DataLocation_TestHelper(location) + + +def test_DataLocation_FindData_DirectoryReturned(): + location = data_locator.get_data_uri() + DataLocation_TestHelper(location) + + +def test_DataLocation_FindLog_DirectoryReturned(): + location = data_locator.get_log_uri() + DataLocation_TestHelper(location) + + +def test_DataLocation_FindConfig_DirectoryReturned(): + location = data_locator.get_config_uri() + DataLocation_TestHelper(location) diff --git a/tests/core/shared/test_generate_hash.py b/tests/core/shared/test_generate_hash.py new file mode 100644 index 00000000..1fb8317c --- /dev/null +++ b/tests/core/shared/test_generate_hash.py @@ -0,0 +1,43 @@ +import os + +from PyPWA.core.shared import generate_hash + +FILE_LOCATION = os.path.join( + os.path.dirname(__file__), + "../../data/test_docs/sv_test_data.tsv" +) + + +def test_FileHash_md5_StringReturned(): + the_hash = generate_hash.get_md5_hash(FILE_LOCATION) + check_hash(the_hash) + + +def test_FileHash_sha1_StringReturned(): + the_hash = generate_hash.get_sha1_hash(FILE_LOCATION) + check_hash(the_hash) + + +def test_FileHash_sha224_StringReturned(): + the_hash = generate_hash.get_sha224_hash(FILE_LOCATION) + check_hash(the_hash) + + +def test_FileHash_sha256_StringReturned(): + the_hash = generate_hash.get_sha256_hash(FILE_LOCATION) + check_hash(the_hash) + + +def test_FileHash_sha384_StringReturned(): + the_hash = generate_hash.get_sha384_hash(FILE_LOCATION) + check_hash(the_hash) + + +def test_FileHash_sha512_StringReturned(): + the_hash = generate_hash.get_sha512_hash(FILE_LOCATION) + check_hash(the_hash) + + +def check_hash(the_hash): + assert isinstance(the_hash, str) + assert len(the_hash) > 5 diff --git a/tests/core/shared/test_intial_logging.py b/tests/core/shared/test_intial_logging.py new file mode 100644 index 00000000..f01079ac --- /dev/null +++ b/tests/core/shared/test_intial_logging.py @@ -0,0 +1,7 @@ +import logging + +from PyPWA.core.shared import initial_logging + + +def test_initial_logging_takes_a_logging_level(): + initial_logging.InternalLogger.configure_root_logger(logging.DEBUG) diff --git a/tests/core/shared/test_plugin_loader.py b/tests/core/shared/test_plugin_loader.py new file mode 100644 index 00000000..dc876262 --- /dev/null +++ b/tests/core/shared/test_plugin_loader.py @@ -0,0 +1,84 @@ +import os + +import example_python_sheet +import pytest + +from PyPWA import builtin_plugins +from PyPWA.builtin_plugins import data, process, minuit, nestle +from PyPWA.core.shared import plugin_loader +from PyPWA.core.configurator import options + +EXAMPLE_SHEET = os.path.join( + os.path.dirname(__file__), "example_python_sheet.py" +) + +DOES_NOT_EXIST = os.path.join( + os.path.dirname(__file__), "awfulness.py" +) + + +@pytest.fixture(scope="module") +def plugin_loader_with_plugins(): + loader = plugin_loader.PluginLoader() + loader.add_plugin_location([builtin_plugins, None]) + return loader.get_by_class(options.Plugin) + + +def test_plugin_loader_with_sets(): + loader = plugin_loader.PluginLoader() + loader.add_plugin_location({builtin_plugins}) + + +def test_data_iterator_is_found(plugin_loader_with_plugins): + assert data.DataIterator in plugin_loader_with_plugins + + +def test_data_parser_is_found(plugin_loader_with_plugins): + assert data.DataParser in plugin_loader_with_plugins + + +def test_processing_is_found(plugin_loader_with_plugins): + assert process.Processing in plugin_loader_with_plugins + + +def test_minuit_is_found(plugin_loader_with_plugins): + assert minuit.MinuitOptions in plugin_loader_with_plugins + + +def test_nestle_is_found(plugin_loader_with_plugins): + assert nestle.NestleOptions in plugin_loader_with_plugins + + +@pytest.mark.xfail( + reason="File isn't included in search path, no support for non modules", +) +def test_options_test_is_found(plugin_loader_with_plugins): + assert example_python_sheet.OptionsTest in plugin_loader_with_plugins + + +@pytest.fixture(scope="module") +def python_sheet_loader(): + loader = plugin_loader.PluginLoader() + loader.add_plugin_location(EXAMPLE_SHEET) + return loader + + +def test_finds_meaning(python_sheet_loader): + fun = python_sheet_loader.get_by_name("the_meaning_of_life") + assert fun() == 42 + + +def test_cant_find_nothing(python_sheet_loader): + with pytest.raises(ImportError): + fun = python_sheet_loader.get_by_name("nothing", True) + + +def test_returns_empty(python_sheet_loader): + fun = python_sheet_loader.get_by_name("nothing", False) + assert isinstance(fun(), type(None)) + + +def test_can_load_non_existant_file(): + with pytest.raises(ImportError): + loader = plugin_loader.PluginLoader() + loader.add_plugin_location(DOES_NOT_EXIST) diff --git a/tests/core/templates/test_configurator_templates.py b/tests/core/templates/test_configurator_templates.py deleted file mode 100644 index d9f23cab..00000000 --- a/tests/core/templates/test_configurator_templates.py +++ /dev/null @@ -1,13 +0,0 @@ -from PyPWA.core.templates import configurator_templates - -import pytest - - -def test_ShellCoreTemplate_MethodValues_RaiseNotImplementedError(): - test_shell = configurator_templates.ShellCoreTemplate() - - with pytest.raises(NotImplementedError): - test_shell.make_config("this", "that") - - with pytest.raises(NotImplementedError): - test_shell.run("this", "that") diff --git a/tests/core/templates/test_interface_templates.py b/tests/core/templates/test_interface_templates.py deleted file mode 100644 index 855b5722..00000000 --- a/tests/core/templates/test_interface_templates.py +++ /dev/null @@ -1,55 +0,0 @@ -import pytest - -from PyPWA.core.templates import interface_templates - - -def test_AllObjects_CallAbstractMethod_RaiseNotImplementedError(): - """ - Ensures that the objects will raise a NotImplementedError when called. - """ - writer = interface_templates.WriterInterfaceTemplate("Something") - with pytest.raises(NotImplementedError): - writer.write(12) - - with pytest.raises(NotImplementedError): - writer.close() - - with pytest.raises(NotImplementedError): - with interface_templates.WriterInterfaceTemplate("Something") as \ - stream: - stream.write("else") - - reader = interface_templates.ReaderInterfaceTemplate("Something") - with pytest.raises(NotImplementedError): - reader.next_event - - with pytest.raises(NotImplementedError): - reader.previous_event - - with pytest.raises(NotImplementedError): - with interface_templates.ReaderInterfaceTemplate("Something") as \ - stream: - stream.reset() - - with pytest.raises(NotImplementedError): - for event in reader: - pass - - with pytest.raises(NotImplementedError): - reader.reset() - - with pytest.raises(NotImplementedError): - reader.close() - - interface = interface_templates.InterfaceTemplate() - with pytest.raises(NotImplementedError): - interface.run() - - with pytest.raises(NotImplementedError): - interface.previous_value - - with pytest.raises(NotImplementedError): - interface.stop() - - with pytest.raises(NotImplementedError): - interface.is_alive diff --git a/tests/core/templates/test_option_templates.py b/tests/core/templates/test_option_templates.py deleted file mode 100644 index b5fe562d..00000000 --- a/tests/core/templates/test_option_templates.py +++ /dev/null @@ -1,169 +0,0 @@ -import pytest - -from PyPWA.core.templates import option_templates - - -def test_AllObjects_CallAbstractMethod_RaiseNotImplementedError(): - """ - Ensures that the objects will raise a NotImplementedError when called. - """ - with pytest.raises(NotImplementedError): - options = option_templates.PluginsOptionsTemplate() - options.request_metadata("name") - - with pytest.raises(NotImplementedError): - options = option_templates.MainOptionsTemplate() - options.request_metadata("id") - - -def test_PluginOptionsTemplate_CreateMetaObject_HoldData(): - """ - Tests that the template object renders out its data correctly when - supplied with usable information. - """ - - class TestObject(option_templates.PluginsOptionsTemplate): - def _plugin_name(self): - return "test" - - def _plugin_interface(self): - return "nothing" - - def _plugin_type(self): - return self._data_parser - - def _plugin_requires(self): - - function = """\ -def function(this, that) - return this * that""" - - return self._build_function("numpy", function) - - def _user_defined_function(self): - return None - - def _default_options(self): - return { - "this": 1, - "that": 2, - "other": 3 - } - - def _option_levels(self): - return { - "this": self._required, - "that": self._optional, - "other": self._advanced - } - - def _option_types(self): - return { - "this": bool, - "that": int, - "other": int - } - - def _module_comment(self): - return "test comment" - - def _option_comments(self): - return { - "this": "this", - "that": "that", - "other": "or other" - } - - options = TestObject() - assert options.request_metadata("name") == "test" - assert options.request_metadata("interface") == "nothing" - assert options.request_metadata("provides") == "data parser" - assert options.request_options("required")["test"]["this"] == 1 - assert options.request_options("optional")["test"]["this"] == 1 - assert options.request_options("optional")["test"]["that"] == 2 - assert options.request_options("advanced")["test"]["other"] == 3 - assert options.request_options("advanced")["test"]["this"] == 1 - assert options.request_options("advanced")["test"]["that"] == 2 - - with pytest.raises(KeyError): - options.request_options("required")["test"]["other"] == 3 - - -def test_MainOptionsTemplate_CreateMetaObject_HoldData(): - """ - Tests that the template object renders out its data correctly when - supplied with usable information. - """ - - class TestObject(option_templates.MainOptionsTemplate): - def _shell_id(self): - return "test" - - def _main_type(self): - return self._shell_main - - def _main_requires(self): - return self._data_parser - - def _interface_object(self): - return None - - def _requires_data_parser(self): - return False - - def _requires_data_reader(self): - return False - - def _requires_kernel_processing(self): - return False - - def _requires_minimization(self): - return False - - def _user_defined_function(self): - return False - - def _default_options(self): - return { - "this": 1, - "that": 2, - "other": 3 - } - - def _option_levels(self): - return { - "this": self._required, - "that": self._optional, - "other": self._advanced - } - - def _option_types(self): - return { - "this": bool, - "that": int, - "other": int - } - - def _module_comment(self): - return "test comment" - - def _option_comments(self): - return { - "this": "this", - "that": "that", - "other": "or other" - } - - options = TestObject() - assert options.request_metadata("id") == "test" - assert options.request_metadata("ui") == "main shell" - assert not options.requires("data parser") - assert options.request_options("required")["test"]["this"] == 1 - assert options.request_options("optional")["test"]["this"] == 1 - assert options.request_options("optional")["test"]["that"] == 2 - assert options.request_options("advanced")["test"]["other"] == 3 - assert options.request_options("advanced")["test"]["this"] == 1 - assert options.request_options("advanced")["test"]["that"] == 2 - - with pytest.raises(KeyError): - options.request_options("required")["test"]["other"] == 3 diff --git a/tests/core/templates/test_plugin_templates.py b/tests/core/templates/test_plugin_templates.py deleted file mode 100644 index eaa2fc06..00000000 --- a/tests/core/templates/test_plugin_templates.py +++ /dev/null @@ -1,40 +0,0 @@ -import pytest - -from PyPWA.core.templates import plugin_templates - - -def test_AllObjects_CallAbstractMethod_RaiseNotImplementedError(): - """ - Ensures that the objects will raise a NotImplementedError when called. - """ - - minimizer = plugin_templates.MinimizerTemplate({"this": "that"}) - with pytest.raises(NotImplementedError): - minimizer.main_options("function") - - with pytest.raises(NotImplementedError): - minimizer.start() - - processing = plugin_templates.KernelProcessingTemplate( - {"this": "that"} - ) - - with pytest.raises(NotImplementedError): - processing.main_options("more", "less", "something") - - with pytest.raises(NotImplementedError): - processing.fetch_interface() - - data_reader = plugin_templates.DataReaderTemplate({"this": "that"}) - with pytest.raises(NotImplementedError): - data_reader.return_reader("the file") - - with pytest.raises(NotImplementedError): - data_reader.return_writer("the file", 1) - - data_parser = plugin_templates.DataParserTemplate({"this": "that"}) - with pytest.raises(NotImplementedError): - data_parser.parse("the file") - - with pytest.raises(NotImplementedError): - data_parser.write("the data", "the file") diff --git a/tests/core/test_intial_logging.py b/tests/core/test_intial_logging.py deleted file mode 100644 index b92b5514..00000000 --- a/tests/core/test_intial_logging.py +++ /dev/null @@ -1,10 +0,0 @@ -import logging - -import PyPWA.core.initial_logging - - -def test_InitialLogging_SetDebug(): - """ - Extremely simple test for the initial logging - """ - PyPWA.core.initial_logging.define_logger(logging.DEBUG) diff --git a/tests/core/test_plugin_loader.py b/tests/core/test_plugin_loader.py deleted file mode 100644 index dc47c1c0..00000000 --- a/tests/core/test_plugin_loader.py +++ /dev/null @@ -1,22 +0,0 @@ -from PyPWA import builtin_plugins -from PyPWA.builtin_plugins import data, process, minuit -from PyPWA.core import plugin_loader -from PyPWA.core.templates import option_templates - - -def test_PluginLoading_ImportsPlugins_FindsAllLibs(): - """ - Ensures that the PluginLoader finds all the plugins when supplied - with a module and nothing more. - """ - loader = plugin_loader.PluginLoading( - option_templates.PluginsOptionsTemplate - ) - plugins = loader.fetch_plugin([builtin_plugins]) - - assert data.DataIterator in plugins - assert data.DataParser in plugins - assert process.Processing in plugins - assert minuit.MinuitOptions in plugins - - assert len(plugins) == 4 or len(plugins) == 5 diff --git a/tests/core/test_tools.py b/tests/core/test_tools.py deleted file mode 100644 index 72337bf3..00000000 --- a/tests/core/test_tools.py +++ /dev/null @@ -1,88 +0,0 @@ -import io - -import os - -from PyPWA.core import tools - -FILE_LOCATION = os.path.join( - os.path.dirname(__file__), - "../builtin_plugins/data/builtin/test_docs/sv_test_data.tsv" -) - -data_loc = tools.DataLocation() -test_file = io.open(FILE_LOCATION, "br") -hashing = tools.FileHashString() - - -def DataLocation_TestHelper(location): - """ - Simple wrapper around tests for DataLocation. - Checks if the path to the returned file exists. - - Args: - location (str): The path to file. - """ - new_location = os.path.split(location) - assert os.path.exists(new_location[0]) - - -def test_DataLocation_FindCache_DirectoryReturned(): - location = data_loc.get_cache_uri() - DataLocation_TestHelper(location) - - -def test_DataLocation_FindData_DirectoryReturned(): - location = data_loc.get_data_uri() - DataLocation_TestHelper(location) - - -def test_DataLocation_FindLog_DirectoryReturned(): - location = data_loc.get_log_uri() - DataLocation_TestHelper(location) - - -def test_DataLocation_FindConfig_DirectoryReturned(): - location = data_loc.get_config_uri() - DataLocation_TestHelper(location) - - -def test_FileHash_md5_StringReturned(): - the_hash = hashing.get_md5_hash(test_file) - - assert isinstance(the_hash, str) - assert len(the_hash) > 5 - - -def test_FileHash_sha1_StringReturned(): - the_hash = hashing.get_sha1_hash(test_file) - - assert isinstance(the_hash, str) - assert len(the_hash) > 5 - - -def test_FileHash_sha224_StringReturned(): - the_hash = hashing.get_sha224_hash(test_file) - - assert isinstance(the_hash, str) - assert len(the_hash) > 5 - - -def test_FileHash_sha256_StringReturned(): - the_hash = hashing.get_sha256_hash(test_file) - - assert isinstance(the_hash, str) - assert len(the_hash) > 5 - - -def test_FileHash_sha384_StringReturned(): - the_hash = hashing.get_sha384_hash(test_file) - - assert isinstance(the_hash, str) - assert len(the_hash) > 5 - - -def test_FileHash_sha512_StringReturned(): - the_hash = hashing.get_sha512_hash(test_file) - - assert isinstance(the_hash, str) - assert len(the_hash) > 5 diff --git a/tests/data/pyfit/data/data.csv b/tests/data/pyfit/data/data.csv new file mode 100644 index 00000000..5098a061 --- /dev/null +++ b/tests/data/pyfit/data/data.csv @@ -0,0 +1,21 @@ +v,w,x,y,z,qfactor,BinN +0.95640452907820617,0.21553526105646836,0.16407093023482777,0.12917578294625076,0.3277699191994905,0.28041932989857055,0.84998371921222848 +0.80598402056754426,0.38728379815484604,0.29578880746974667,0.53141542336721759,0.10895804013846477,0.64469559045314351,0.32189726311280187 +0.25283927365157555,0.37968555334144727,0.24670113813959382,0.51082329073127553,0.38610236024870437,0.071017165260841009,0.36260228126169958 +0.19246017603470056,0.33124506762492678,0.033570479121473595,0.96636350804057547,0.10966705191766124,0.68702340852520594,0.44159486213574817 +0.440289547555061,0.79627591145624876,0.30641909772021036,0.55645226129198189,0.23347743001004262,0.45175139403431597,0.11418383151963885 +0.10349442409841814,0.61344808072453805,0.34948450916011553,0.27957796915269062,0.15791979718640503,0.4742566290970277,0.5564488507687253 +0.90655146797831399,0.52387637563707123,0.66503387391341984,0.18102447250586695,0.39525276251408548,0.8351333522172194,0.080595762290830208 +0.60164049233224648,0.39796362513843486,0.68099246663658508,0.92522704746829409,0.14223355424444406,0.60312693237607806,0.66682065619078379 +0.23145590491001633,0.48753505150594745,0.6062693680852772,0.95783647687862528,0.31142773877116825,0.71495123814156181,0.68137501593732963 +0.70909873558506664,0.0014399776344070636,0.95768870177463405,0.079711361062450026,0.61673380795627764,0.35358705139883939,0.28909350776671894 +0.37859768930387649,0.94000852328470819,0.29733708728340769,0.1720713596772826,0.82677440074274677,0.54359816175375386,0.81891869463421207 +0.092150346723865129,0.92996491914382096,0.44493318493816336,0.25508004443981924,0.56481936085781259,0.89014586030965659,0.35751493885459895 +0.68062419292472742,0.38258910949052405,0.17578187173963111,0.54623635142157501,0.1288308243892432,0.087735681032279356,0.91079604716055795 +0.16220121650292763,0.96143417684021693,0.46822657124104206,0.69765434288806405,0.86287516134800446,0.28982648084247509,0.5434155113307314 +0.99327247900951221,0.13455516749270524,0.55807967673977599,0.67394545233920167,0.10369212636070346,0.25544970675990053,0.78552319219947342 +0.18824029656456109,0.81097494247815727,0.23640988643794969,0.68319512597674426,0.85599773909458476,0.32010307399624627,0.27486748791132287 +0.50389447756107197,0.82886466041265872,0.66047118242838943,0.9467308377162118,0.32181678197407759,0.66895566225084491,0.088571782579902614 +0.32021511880146525,0.25275217822756602,0.89386692895300679,0.19849312430727384,0.42953146752536897,0.09595619764479224,0.97295600769318324 +0.60570990636006095,0.94679372733035638,0.90467686311465767,0.42592955818049039,0.11716346715227333,0.62557490316340258,0.95976656086260048 +0.54318149251464309,0.47126421542167096,0.26874315308424745,0.022952542723720382,0.2018792323214349,0.26071271018522868,0.62922192919775599 \ No newline at end of file diff --git a/tests/data/pyfit/data/internal_names.csv b/tests/data/pyfit/data/internal_names.csv new file mode 100644 index 00000000..398a729c --- /dev/null +++ b/tests/data/pyfit/data/internal_names.csv @@ -0,0 +1,11 @@ +x,y,qf,bn,exp,err +0.22103004237267732,0.19963131489364483,0.1931923516437426,0.9138648807444445,0.74691968932464348,0.034934761040754325 +0.48643269532046229,0.02354315487698766,0.76136937293783036,0.58808363992955881,0.92977055626776883,0.19704036050381257 +0.82899457747428951,0.72303121933782333,0.096044095978928601,0.10498435784555171,0.86245668108739393,0.32963709491544158 +0.4717218456158726,0.75158736586676,0.13927900997841769,0.14072262275954006,0.41567564307425919,0.78418342753457071 +0.32245112927429009,0.781271184992266,0.14433401005211699,0.70645993497548398,0.35783843756383882,0.6637430475944136 +0.62815607633523463,0.97297295994112554,0.021080057853820056,0.19570370519755564,0.47015088854402676,0.16456571327243275 +0.58907790600068721,0.89503984669988401,0.42530528529592515,0.69540027713580266,0.49486282083939248,0.50132492278719898 +0.87054542167089011,0.10172287480074105,0.96362223573227956,0.14893951298039099,0.68350586386298684,0.32909323307219196 +0.1467500782594281,0.99823349465040179,0.94504909714417895,0.33753358747662177,0.020305677100872277,0.581386624438051 +0.26222556363577543,0.15475972852863307,0.63345058323478443,0.91125627399455189,0.69156329957950213,0.6997932362475997 diff --git a/tests/data/pyfit/data/monte_carlo.csv b/tests/data/pyfit/data/monte_carlo.csv new file mode 100644 index 00000000..988b9c8b --- /dev/null +++ b/tests/data/pyfit/data/monte_carlo.csv @@ -0,0 +1,21 @@ +v,w,x,y,z +0.047160308400970408,0.71517976270039296,0.65294419519521496,0.74245531017027699,0.79282027558702328 +0.23767253289263301,0.54925237360659507,0.88412446578222414,0.77076894239994664,0.48482401350281878 +0.88344853738381934,0.76417951095295789,0.61128553092684967,0.66257529144051019,0.26807470599629868 +0.35381424103133985,0.53762824811116616,0.088993310269751102,0.46596680592249395,0.28426659402006516 +0.46628769212947174,0.034875663810313595,0.99298928095414118,0.46013565119956734,0.25937649730195378 +0.7652716419579737,0.087930206453984971,0.20883163843615349,0.32243271424955944,0.60277048838974645 +0.75702650630520085,0.63682620975804061,0.52497498635704853,0.64469233599164177,0.67675399024867622 +0.30506068570757439,0.52906317173342698,0.14955112111667745,0.88513588174166558,0.84507553236368638 +0.73519512717957325,0.6737064246345339,0.48279544112646389,0.06924134559269679,0.6009917025389484 +0.78350803907744748,0.95168511098257236,0.94457581241492961,0.49321388614855133,0.4665842652194867 +0.025473481408703869,0.98412558149380835,0.30188206106240201,0.43911561982934033,0.64924551066281244 +0.018207132121802916,0.67998582354990256,0.66093797226057105,0.50003874811834437,0.36167395357898369 +0.31753226950226177,0.077170569206215012,0.36072221530905402,0.73904865379442508,0.40685211609198879 +0.8592771198287118,0.96695213090337151,0.40232316630925358,0.17622491689356501,0.78231681939914177 +0.57809595470620367,0.81525685075844767,0.11833606369487537,0.77588522876158872,0.42296248649310964 +0.84297786877708003,0.5549619273334363,0.19926241037039327,0.76608521602669133,0.57553869348020725 +0.58572313694012157,0.51518005930214117,0.75546494074295789,0.84765842886732889,0.56913108623614284 +0.8412773347966721,0.76291045577846095,0.7330905761300075,0.14858317832809931,0.15496574234745863 +0.21666570998815826,0.16002896890891871,0.81529620694859217,0.23989462812561024,0.65669536395122174 +0.24061902160471482,0.6761525383726178,0.056091881245030617,0.979183210980205,0.79299760774319705 diff --git a/tests/data/pyfit/data/qfactor.txt b/tests/data/pyfit/data/qfactor.txt new file mode 100644 index 00000000..8015a9f7 --- /dev/null +++ b/tests/data/pyfit/data/qfactor.txt @@ -0,0 +1,20 @@ +0.87621533489525172 +0.85928937552977247 +0.71297409400025213 +0.76479424656200823 +0.22815998399355497 +0.066430853969000614 +0.87906172616923861 +0.076794351265381589 +0.63643570165221197 +0.61120065681082614 +0.71742672473533997 +0.065797210543766749 +0.72079349991285424 +0.47687137144262959 +0.29073031552893747 +0.45023203912688536 +0.41298455996334615 +0.90510661038206386 +0.72824489258438263 +0.31514546276911348 diff --git a/tests/data/pyfit/rho/RHOfit b/tests/data/pyfit/rho/RHOfit new file mode 100644 index 00000000..ff32bdfc --- /dev/null +++ b/tests/data/pyfit/rho/RHOfit @@ -0,0 +1,22 @@ +Builtin Multiprocessing: + number of processes: 2 +Minuit: + number of calls: 1 + strategy: 0 + parameters: + - A1 + - A2 + settings: + A1: 200. + limit_A1: [0.,10000.] + A2: 0.8 + limit_A2: [0.2,1.0] +Builtin Parser: + enable cache: false +General Fitting: + function's location: tests/data/pyfit/rho/testRHO.py + save name: outputRHOFIT + setup name: setup_function + processing name: processing_function + data location: tests/data/pyfit/rho/RHOw.csv + likelihood type: likelihood diff --git a/tests/data/pyfit/rho/RHOsim b/tests/data/pyfit/rho/RHOsim new file mode 100644 index 00000000..18c0de7e --- /dev/null +++ b/tests/data/pyfit/rho/RHOsim @@ -0,0 +1,13 @@ +Builtin Multiprocessing: + number of processes: 2 +Builtin Parser: + enable cache: false +Simulator: + function's location: tests/data/pyfit/rho/testRHO.py + parameters: + A1: 100. + A2: 0.4 + setup name: setup_function + data location: tests/data/pyfit/rho/flat_data.csv + processing name: processing_function + save name: outputRHO diff --git a/tests/data/pyfit/rho/RHOw.csv b/tests/data/pyfit/rho/RHOw.csv new file mode 100644 index 00000000..c067f405 --- /dev/null +++ b/tests/data/pyfit/rho/RHOw.csv @@ -0,0 +1,2500 @@ +ctheta,phi,tM,psi +-0.489528,1.8686,-0.0165796,-0.94242001 +-0.081775397,1.04243,-0.085151903,-0.498631 +0.086265698,-2.12901,-0.33881599,1.42967 +0.20925599,-2.29234,-0.021633601,-2.6809199 +-0.758632,2.0834501,-0.150694,-2.99859 +0.345146,-2.6042199,-0.0131897,-0.58135498 +0.084627897,-1.8206199,-0.22193401,-0.37336999 +-0.602916,-2.2683599,-0.170937,-2.0648301 +0.82501298,1.03643,-0.0322088,-1.9564199 +-0.065588303,-2.90838,-0.0220422,-2.9762499 +0.075411901,2.1601601,-0.15467501,-1.49427 +-0.37213701,-1.82561,-0.248803,1.73086 +-0.080330297,-0.210572,-0.0177917,-2.7151401 +-0.89193702,-2.8283701,-0.00628709,-2.14326 +-0.81662703,0.27601999,-0.00867307,-0.228736 +-0.79393601,0.71052498,-0.082652502,1.50089 +-0.90569001,-3.12866,-0.124602,0.47066399 +-0.462396,-0.88036102,-0.0085196001,2.04931 +0.39173701,0.88477701,-0.120858,2.64346 +-0.26192701,0.57046902,-0.060985301,-2.3445301 +-0.93761498,2.3937199,-0.093873098,0.220057 +-0.00053999602,0.33556801,-0.137297,0.338222 +0.91477001,2.3505399,-0.0552705,-2.6221399 +0.14539699,-0.138565,-0.066939101,-2.5120499 +0.67297798,-2.98089,-0.100951,2.9528601 +-0.26041499,-2.7597101,-0.083587699,2.9321001 +0.21487699,0.46320799,-0.087503202,1.01358 +-0.34383401,-2.8491001,-0.250462,2.27335 +0.153162,2.8696101,-0.109939,-2.6780701 +0.807347,2.3380499,-0.056233902,-2.9423101 +-0.47594199,-2.3243201,-0.229735,0.83604002 +0.122114,-2.08547,-0.043747399,0.193177 +0.0854408,2.5796499,-0.00308839,0.61235797 +-0.70835501,0.70165098,-0.0061375001,-2.6969199 +0.27444899,2.6614599,-0.0289372,-2.9781001 +0.33451799,-2.44557,-0.086146504,2.1028099 +0.65730298,-2.59114,-0.0289611,1.14527 +-0.26831701,2.83374,-0.154608,1.92865 +-0.646927,-1.59474,-0.30564401,-0.392214 +0.45174,0.092398703,-0.105508,0.62286198 +0.31084901,1.84922,-0.018578,-2.30825 +0.071979702,-0.62607402,-0.066854097,-0.16235299 +0.12472,-0.52407998,-0.0619669,0.0065621301 +0.095270902,-0.42244801,-0.058347199,-2.6045899 +0.52205402,-1.32084,-0.034010299,-1.127 +-0.29513499,-1.02145,-0.20548201,-0.97189403 +0.41516599,2.6103599,-0.00510818,-2.9513199 +0.603297,0.319637,-0.0155436,0.311198 +0.22923499,-3.1104,-0.156726,2.1579299 +-0.98055601,1.42111,-0.091028199,-2.1421299 +0.190689,-2.5032599,-0.107889,0.37455699 +0.81558698,-0.36282,-0.231388,-1.75789 +0.88528103,-2.3762901,-0.0828133,-0.077233203 +-0.243876,-1.01475,-0.00240648,0.723575 +0.68416399,2.8475599,-0.15990099,2.3012199 +0.61805499,-0.29942599,-0.014519,0.45922899 +-0.590716,0.51035303,-0.053105202,0.27238801 +-0.161566,1.78018,-0.106234,1.82155 +-0.90465897,-2.5516701,-0.102096,-2.57199 +0.54905999,2.1979101,-0.153973,-0.18708301 +-0.79537302,-1.85671,-0.0647199,1.0735199 +-0.0507509,0.34977299,-0.065035,-0.37893799 +-0.21565101,0.147503,-0.066876002,1.5948499 +0.095911399,-2.9194901,-0.0150224,-2.0502501 +-0.50538099,0.18947101,-0.034317199,2.9426601 +0.29506499,0.439132,-0.070103198,-0.026979299 +0.179317,1.59399,-0.041446801,2.93696 +-0.57986701,0.93543202,-0.37547901,-0.0093112299 +0.58475602,2.41098,-0.0108354,0.25011101 +0.174715,-2.87907,-0.038697999,0.69301701 +0.100314,-2.68891,-0.132149,1.26212 +0.73617798,0.151979,-0.0942396,-0.162774 +0.0220083,-1.6982599,-0.0136226,3.0211301 +-0.084969603,2.87185,-0.237702,0.210787 +-0.261565,-1.42484,-0.0127735,-1.3279999 +-0.56768101,2.05615,-0.033468299,-0.42110601 +-0.87440199,1.25841,-0.0083939303,-0.97645903 +-0.23350599,2.42981,-0.089813299,0.76279002 +0.56808197,2.9707601,-0.130762,0.19545101 +-0.0251984,-1.9921,-0.15107299,2.4683299 +0.125912,0.83588898,-0.0145581,-2.8431699 +0.13266,2.0571001,-0.031766899,-0.72362101 +0.31317601,2.14679,-0.048679698,-2.1097901 +0.12541699,-2.10676,-0.050965302,-0.0229293 +-0.101686,-1.96031,-0.0273553,0.98854601 +-0.39637199,2.4649799,-0.0153768,-1.06397 +0.295863,-0.44780999,-0.00724302,-0.42426899 +0.90386802,-1.01946,-0.0266048,-2.78843 +0.24219701,0.57141799,-0.155265,-1.55015 +0.95442498,2.6774399,-0.169264,0.25816199 +-0.444224,1.90256,-0.0045032101,0.630494 +0.114033,-0.058579098,-0.034286302,-1.55179 +0.88527298,-3.1361101,-0.019806501,-2.17015 +0.42741099,-2.44839,-0.0386509,-2.7249601 +0.13759799,1.3414299,-0.025119999,0.57175398 +-0.067927398,2.6080101,-0.093646899,-2.7583499 +-0.27219501,-2.84812,-0.0025172301,1.11955 +0.54793298,0.115707,-0.0103564,-0.97092599 +0.095757499,-1.89379,-0.39701799,0.837789 +-0.31837401,2.87165,-0.053704798,-0.80436999 +-0.46685699,-2.7416301,-0.048143402,3.0022399 +0.63371998,1.41096,-0.25861999,-1.67959 +0.67340201,2.70772,-0.034162901,1.77843 +0.356015,0.58133399,-0.0310545,-1.42538 +0.53469998,-2.86691,-0.025542499,0.699085 +-0.29176101,1.16734,-0.0472361,-0.55126899 +-0.57109702,-1.19195,-0.13757899,-0.26391301 +0.52265102,-2.2552299,-0.0227479,-2.6810801 +-0.0796564,0.63966298,-0.059197601,0.68155903 +0.122772,1.82601,-0.0546063,-0.083301798 +-0.035091098,-1.85115,-0.0271235,1.03583 +-0.32125801,-1.4165699,-0.042546399,-2.9029601 +0.77114302,-0.53010601,-0.0072657401,-1.2695 +0.092407897,-2.2843699,-0.073515996,-2.53245 +-0.40367699,0.47602201,-0.065624103,2.8473201 +-0.37390599,-2.8731599,-0.113961,1.27046 +0.81890601,-1.6819299,-0.0370115,1.0874799 +0.26920801,2.3295801,-0.0052347798,-0.067587599 +-0.074752301,0.300825,-0.016481699,1.75983 +0.050988499,-0.41822299,-0.0548159,-2.3155 +-0.171388,-2.3199401,-0.0264566,1.0062799 +0.270524,-3.0508299,-0.0664832,2.1343901 +0.50028199,-1.28374,-0.053991798,-2.15171 +0.0110042,-2.28549,-0.202042,1.24975 +-0.32161999,-0.31782901,-0.116526,-0.33525601 +-0.086331397,0.481273,-0.0235999,2.33565 +0.58026099,0.99728298,-0.099930599,0.85685599 +-0.85266501,1.13148,-0.071566097,2.0924499 +-0.715119,-1.8178,-0.162811,-0.52838898 +0.719868,-0.60418802,-0.046484198,0.58819598 +-0.0172674,1.3878,-0.035071399,1.99413 +-0.39234501,-1.94635,-0.120484,1.10515 +-0.078924298,-2.65083,-0.0067668902,-0.69737601 +0.76737499,0.97799599,-0.052933499,1.3040299 +-0.42853701,-1.80295,-0.31853601,3.0678501 +-0.42467001,0.867015,-0.336788,-2.03076 +0.33093899,-1.53653,-0.24078999,-2.52074 +-0.385984,-0.76778501,-0.14654399,-2.8023901 +0.164597,-0.26499501,-0.121003,3.0228701 +0.205761,2.00034,-0.092340402,-1.14275 +-0.33161101,-0.70393699,-0.073265001,2.7725899 +-0.52945399,1.96859,-0.112012,-2.9130099 +0.158191,0.39929599,-0.22868501,-2.5796599 +-0.20118099,-3.08531,-0.041783798,-0.141625 +0.385921,-1.15262,-0.0068533402,-0.59644198 +0.60369599,-1.8217,-0.00749315,0.84759301 +-0.112071,-0.51389199,-0.110146,0.682468 +-0.040994801,1.30567,-0.052847501,1.9701101 +-0.833776,-2.88219,-0.51213098,-2.9015601 +-0.74111998,3.0806501,-0.088018,0.24741501 +-0.184329,-0.059563901,-0.037997201,-2.2430201 +-0.56490302,-0.68900198,-0.0046071298,2.55283 +-0.17650899,-0.464003,-0.31753901,1.18002 +0.218777,1.5189,-0.078970999,-0.38360301 +-0.180758,2.0442801,-0.083486803,-2.5011699 +0.407208,1.74842,-0.023282399,0.98303199 +-0.369311,3.0743899,-0.113301,-2.24194 +-0.51375997,3.10835,-0.1187,0.55541199 +0.42497101,-0.61092001,-0.014311,-0.32001299 +0.553262,1.41442,-0.169599,-0.15548301 +0.84752297,-1.45171,-0.086119004,0.117296 +-0.70205897,1.35622,-0.20237499,-2.76947 +0.59786499,-1.1241699,-0.0445293,0.31333101 +-0.57918203,1.59605,-0.028623801,0.54110003 +-0.206122,2.5097799,-0.044423599,2.7011499 +0.21333501,2.80393,-0.14584,1.78611 +0.29658899,-1.06643,-0.118305,-0.32815501 +-0.475786,-1.04618,-0.071616396,0.27299899 +0.449251,2.87198,-0.0834141,2.5518301 +0.40848601,-3.0160899,-0.0119532,0.93687999 +-0.199938,1.33698,-0.0100201,-0.99920702 +-0.099752299,1.10874,-0.126287,-1.14464 +0.16397201,-2.5650499,-0.166647,0.29195401 +-0.100127,0.13012899,-0.193499,2.3352599 +-0.638816,-1.98966,-0.140662,-2.61956 +-0.63583499,-0.128406,-0.0080768,1.86484 +0.0396295,-3.0067,-0.076022297,2.40517 +0.48653099,-0.99239802,-0.089063197,1.0463001 +-0.0186339,-0.95574999,-0.0086626196,-0.873182 +-0.64939702,0.364759,-0.047783099,-0.437819 +0.78814602,2.5307701,-0.0040427102,-2.74597 +0.216315,0.0539575,-0.114129,1.28667 +-0.120729,-1.45269,-0.041191399,-0.098082803 +-0.27480701,2.1340499,-0.39713299,-3.07951 +-0.80975699,-2.9690199,-0.0124818,1.3006999 +0.086852796,-2.0100701,-0.37489799,-0.087694101 +-0.23942,3.1379099,-0.0112652,2.8847799 +0.61652398,0.198478,-0.0321346,-1.13589 +0.082162701,0.95812702,-0.027765701,3.0875001 +-0.24456701,-0.58286202,-0.083439097,-0.340902 +-0.573017,0.66165501,-0.26061499,-0.80508697 +0.38738301,-3.11026,-0.0886757,0.57072699 +-0.756064,3.1131401,-0.018307799,0.0113634 +-0.75054097,2.4310999,-0.043676499,2.60939 +-0.668935,-0.47921401,-0.0081045497,-1.14236 +0.42501599,1.21472,-0.0103518,-3.04141 +0.26185101,-0.99704403,-0.0643356,2.9623001 +-0.043186899,1.83012,-0.068660401,0.207081 +-0.45383099,-3.0754001,-0.041039199,-3.1076701 +-0.47064599,2.2042201,-0.198733,-1.02031 +-0.324462,-1.49053,-0.117124,-1.3405 +0.0112885,1.68628,-0.084216997,2.41325 +0.36177501,0.383724,-0.19488101,-1.76841 +0.38062,-1.41366,-0.290921,-2.7125499 +-0.53353101,-0.93661201,-0.069025204,1.52407 +-0.61327797,0.88103998,-0.0130193,-1.49835 +-0.74378902,3.07201,-0.059558101,-0.00674647 +0.82197702,-2.87797,-0.265706,-0.390791 +0.017995199,2.5637901,-0.084168799,-2.6763799 +-0.090329699,-0.25887901,-0.103096,0.037963498 +-0.41832599,0.61594701,-0.089860603,0.55710799 +0.043543499,-1.54696,-0.00819219,0.43434101 +0.42359099,-2.7579,-0.37299201,-0.52203703 +-0.32995999,-1.74268,-0.20378999,0.24581701 +0.19301701,-0.55190402,-0.152677,2.8836999 +0.136306,-1.0829999,-0.068314202,-1.37051 +0.56702,-2.4542601,-0.107983,-1.82679 +0.29036501,1.90341,-0.063463099,1.35006 +-0.134213,-0.78597802,-0.141032,2.9739499 +-0.200482,-2.62919,-0.0077187498,-2.2097099 +0.419173,1.1253099,-0.010037,-2.9188001 +-0.440312,-0.85155398,-0.0282108,-0.34803799 +0.112136,0.887146,-0.048497502,-2.4662299 +-0.0402078,-1.8136801,-0.129025,2.08641 +0.64205301,-0.97860199,-0.183852,-1.81609 +0.116584,2.16097,-0.189392,-1.49617 +-0.060325298,-1.65289,-0.0117333,2.9584799 +0.70750999,0.27227801,-0.057871599,-0.74072701 +-0.39674899,-1.56154,-0.15239599,-0.164662 +-0.51435202,-1.42089,-0.0092787603,-1.2276 +0.29753801,3.10325,-0.080858096,0.61163998 +0.28648201,2.1043999,-0.0029380999,1.64011 +-0.18475699,-2.91063,-0.164336,2.7896099 +-0.111088,0.127726,-0.0985163,0.075042203 +0.28662899,0.867154,-0.0198112,-0.99018902 +-0.437832,2.9619501,-0.042770699,0.87875003 +-0.14479101,0.99894798,-0.0375361,1.0878299 +-0.42727199,-1.7234,-0.47969699,-0.37312299 +-0.79132903,0.40008101,-0.043126699,-2.6206601 +-0.40258601,-1.9129699,-0.076572798,-2.0325699 +0.1191,-0.69003898,-0.097819299,1.38833 +-0.0073638302,-0.33930901,-0.0105626,-1.9996099 +-0.55292898,0.497924,-0.047331199,0.422115 +0.0274795,-1.5804501,-0.0254739,-0.204533 +0.41272101,2.16324,-0.034076702,0.993572 +0.46632001,2.2458,-0.023007,-0.243948 +-0.552531,0.68374902,-0.18655699,-1.97232 +0.044105999,-3.1071899,-0.107028,2.63412 +-0.69884503,1.78829,-0.0121013,-1.9797601 +0.73826802,-0.92340702,-0.11188,3.13781 +-0.157717,0.18262701,-0.181169,-2.96826 +0.747235,-1.89959,-0.103162,-2.4397099 +-0.73218697,2.0880201,-0.094130203,-2.1658001 +0.048716601,1.49717,-0.21469399,1.19796 +0.064341702,1.72802,-0.139999,1.64899 +-0.26012599,2.7771399,-0.227227,-2.27724 +0.15468501,1.7715,-0.0081058703,2.8123801 +-0.69320601,0.80673403,-0.094394699,-0.150668 +-0.087224901,-0.101209,-0.0246963,2.4686 +0.063017197,-0.369277,-0.13868999,-1.08302 +-0.252462,1.36055,-0.29947501,-2.7011001 +0.0695161,1.83403,-0.044172201,0.197703 +-0.096504599,-1.56214,-0.0144898,-1.39571 +0.224693,2.0223501,-0.25518101,-1.49212 +0.0885491,1.36369,-0.011228,0.46228001 +0.73580903,-1.40413,-0.095177598,0.549088 +-0.0260597,-2.0775599,-0.118993,1.80765 +-0.67272002,1.2955,-0.031722799,0.97388202 +0.30001801,-0.0213899,-0.0119916,-1.12405 +0.16796499,1.87588,-0.0096098697,2.50934 +0.528925,-1.64004,-0.11647,-2.2076001 +-0.52235299,0.16574401,-0.049747199,-2.7527399 +-0.92207599,0.893821,-0.216645,2.1392 +0.240238,-3.11411,-0.143356,-1.18274 +0.78695703,2.11552,-0.066675298,-0.59486097 +0.161503,0.38570201,-0.121597,-0.18015701 +0.075229801,1.07026,-0.083795302,-0.142923 +-0.52690703,-0.067889199,-0.200609,3.00367 +0.34579101,-1.63089,-0.17833801,-2.6508901 +-0.26125801,0.83303797,-0.079287998,2.9830101 +-0.186822,2.6140599,-0.172951,2.7902901 +-0.71191502,2.69735,-0.23905399,-0.89274102 +-0.65606099,-1.72139,-0.248587,-1.59594 +0.268536,-1.53403,-0.25903401,-2.9710701 +0.29611599,-2.9635,-0.111801,-1.13041 +0.40670201,2.85883,-0.096009597,0.0145144 +-0.299099,-2.30632,-0.028413599,2.60939 +0.23483101,-0.0113406,-0.25388601,-1.9207 +0.31041399,0.92730099,-0.0084634796,0.25158 +0.58343101,2.7391701,-0.092079297,-2.1572199 +-0.46942401,2.8911099,-0.0693933,-0.63516998 +0.79333502,1.53509,-0.0112931,-2.8875201 +-0.39967,1.98164,-0.0083430698,0.76952899 +-0.19995201,-3.0699699,-0.111086,0.171405 +-0.69465101,-2.3190899,-0.106124,-1.55551 +0.23431399,-0.408117,-0.032785501,-1.25696 +-0.47372901,0.071074203,-0.086220801,-2.2713499 +-0.36037201,-2.46489,-0.112908,0.35486901 +-0.64152902,-2.01478,-0.0126589,-1.5992399 +0.0170663,3.0434101,-0.077453703,-1.54037 +-0.32440901,3.01882,-0.107031,2.0353501 +0.043573,0.0131124,-0.0226113,-2.7472999 +-0.376205,-1.76402,-0.095450997,-0.67740798 +-0.54509503,-0.12867001,-0.140239,2.74102 +-0.69569498,-1.13632,-0.138989,-2.1254699 +0.27819201,1.88237,-0.082008801,0.181713 +-0.25225201,-2.7771699,-0.034000002,2.7588999 +0.40404999,-0.95918298,-0.089648403,-2.0239301 +-0.697079,-2.1200399,-0.221725,1.07863 +-0.0299688,1.1391,-0.058147602,2.9847 +0.24586201,1.7665499,-0.059701301,-0.88368201 +-0.158407,0.83759701,-0.0263262,3.00616 +0.0165914,1.09956,-0.034473501,1.90149 +-0.595182,-2.34676,-0.0141593,-0.273056 +0.44234401,0.63850498,-0.034019601,0.29329601 +0.491714,1.25348,-0.13079,-2.16342 +-0.27340001,3.0806899,-0.0497307,1.30814 +0.50296801,-0.37395701,-0.00296286,-0.116284 +-0.16157199,-1.19793,-0.037695698,0.93955499 +-0.093369603,2.6347201,-0.15165301,0.78333002 +-0.65999401,-1.94663,-0.060453199,0.0420168 +-0.37502,2.8158901,-0.157258,-2.1907201 +-0.56457001,-1.2552201,-0.45991299,-2.78743 +0.23406599,0.554151,-0.33794501,0.45879301 +0.105056,-2.52777,-0.085504599,2.91273 +0.36615101,-2.4730201,-0.124694,-2.5136499 +0.184817,0.747428,-0.041061599,3.0746901 +0.34673899,1.72404,-0.123893,-2.65312 +0.52259499,-2.03952,-0.0536368,2.6910501 +-0.48884299,-1.31776,-0.0226488,-0.72431803 +0.248375,-1.7338901,-0.125166,-2.7665701 +0.44126499,1.14178,-0.029012,0.49485201 +-0.0387525,0.27910399,-0.0457309,2.2070401 +0.67973101,0.89576799,-0.0076268599,-0.27774599 +0.37530801,0.273056,-0.0323033,0.74158198 +0.0103629,2.4470899,-0.032567099,0.861193 +0.068875499,1.03798,-0.168303,-1.47225 +-0.74329603,0.41662499,-0.017042501,-2.1663401 +0.074675001,2.54176,-0.00324262,1.31933 +0.396166,-2.17132,-0.172048,-2.59869 +0.82536799,1.54355,-0.105165,-2.6740601 +0.58247602,1.24572,-0.14582901,2.5211201 +0.064547598,-2.97732,-0.044364098,2.8361299 +0.283319,-2.6062901,-0.18522,2.60693 +-0.77326798,-1.9808199,-0.027769299,-1.33016 +-0.0264643,1.22182,-0.085128397,-2.3424301 +-0.90185499,-0.83275598,-0.024569299,-0.93535298 +0.294606,-1.5544,-0.113442,-2.9612601 +-0.065783501,1.71711,-0.0163843,-3.03461 +0.036502901,0.67535198,-0.0169007,-2.5415699 +0.59589499,2.7355299,-0.245263,-0.147238 +-0.189142,2.9955399,-0.35638201,1.72786 +0.60206401,-1.7136,-0.043086398,-2.5097201 +0.36991701,0.094306,-0.0308713,1.24832 +0.433898,0.40384999,-0.067418501,-2.9521599 +-0.24955,1.96882,-0.079514503,-2.72686 +0.38659301,-2.2536099,-0.0220985,-2.4830101 +-0.112891,0.85084802,-0.14940099,-1.45568 +0.32438901,-0.349309,-0.121377,-0.78825498 +0.36234701,-0.275341,-0.139336,-2.8067801 +0.32021099,1.19752,-0.146268,0.430224 +0.60023099,-2.25895,-0.0094379,-3.0062599 +-0.586779,-0.0111213,-0.048441,-0.405099 +-0.226319,0.33063099,-0.065572597,1.6452399 +0.53267503,0.78877902,-0.094652101,0.88920802 +-0.109719,-2.51302,-0.0118013,-2.3876801 +-0.19745301,2.98844,-0.077836998,3.0025599 +-0.248319,1.53029,-0.113431,-0.99117303 +-0.87760597,0.31884199,-0.073745497,-0.67219299 +-0.41984701,-2.7553899,-0.330127,-2.33845 +0.363114,2.7318399,-0.0036476301,-3.0650301 +0.075880997,2.54722,-0.023367699,2.7625101 +0.22858401,1.80193,-0.0205821,-0.64425701 +-0.429041,0.73745197,-0.17970499,-0.28007901 +0.42125499,0.35293499,-0.0374997,2.59497 +-0.396826,2.1271,-0.118737,2.3498299 +-0.15979899,1.37857,-0.017676899,2.1612501 +0.12529799,-1.75122,-0.031520698,-1.50674 +0.13464899,2.4462199,-0.0086252596,2.6040101 +0.56200999,-1.0639,-0.00742108,0.58227003 +0.13725901,1.81359,-0.072154596,-2.1021299 +-0.218325,-0.46641099,-0.092278101,-2.9806399 +0.61470002,2.6404901,-0.020197,-2.0576301 +0.27375099,2.5827999,-0.020932199,0.237297 +-0.425749,1.58476,-0.067124799,-2.00264 +-0.057650398,-2.05845,-0.016775399,0.906075 +-0.20976,0.56149101,-0.036570098,-3.1407199 +0.000203016,3.13183,-0.084755898,-3.0892501 +0.455522,-1.3220299,-0.057328202,-0.65409398 +-0.49220899,0.856848,-0.115859,0.355064 +-0.0069315801,2.7244301,-0.132146,-2.7291 +0.35133001,2.6239901,-0.151695,1.61183 +0.36964801,0.039413799,-0.0171238,-0.20826 +0.205467,-1.66679,-0.13619199,-0.27932 +0.0060926899,2.33318,-0.0303318,-1.17041 +-0.718485,-0.497343,-0.14707001,1.12947 +-0.62733197,2.5868199,-0.050940301,0.47499299 +-0.19383401,-1.22172,-0.088435903,1.37589 +0.144228,2.8764901,-0.68324703,0.67590898 +-0.25461501,2.33553,-0.319763,-1.58664 +-0.57283998,0.39136499,-0.00297776,0.59719199 +-0.66160399,1.0427099,-0.229435,-3.1204 +0.28050101,-2.72051,-0.0522709,1.37888 +0.12644701,1.60124,-0.00345163,0.72631198 +0.20991801,2.87608,-0.202718,-2.7743599 +-0.435776,-2.2235501,-0.0128309,1.89566 +0.77465701,-1.5689,-0.040783901,-0.108154 +-0.13547599,1.24817,-0.146965,-1.96937 +0.40472099,-1.9485199,-0.213745,-0.913427 +0.76093799,2.98893,-0.042083301,0.045012198 +-0.77384001,2.4007399,-0.0044549,0.056810401 +0.26113501,2.8123901,-0.0381984,2.0445399 +-0.371243,2.7951901,-0.060819902,2.2839899 +0.347662,-1.23165,-0.0120067,2.9430699 +-0.066298299,2.2040999,-0.107671,-1.2398601 +0.27422199,1.99719,-0.0280829,-0.26622 +0.049509998,-0.67125899,-0.174944,1.39934 +0.51072401,2.6549799,-0.14756399,-2.9063699 +-0.696823,-1.17829,-0.0285875,-0.78438199 +-0.153497,2.4533,-0.0601211,0.222504 +-0.71687597,0.116504,-0.051107101,1.49001 +-0.10768,-3.09779,-0.027716501,2.78704 +-0.00374787,2.55513,-0.151096,0.7022 +0.16060901,2.56898,-0.062821403,0.50384098 +0.72403097,-1.32348,-0.086306401,2.83461 +-0.161323,1.4731899,-0.0220495,-2.83847 +0.41253999,0.89417797,-0.0684141,2.45962 +-0.59616703,1.09033,-0.131901,-2.3045599 +-0.50180602,0.199727,-0.13682801,0.38337901 +0.030610699,0.74524599,-0.115968,2.4544101 +-0.35639599,1.88334,-0.108343,-2.1057601 +0.070595101,0.087743796,-0.022886701,0.94517702 +0.311537,2.8369,-0.064970903,2.5403399 +-0.212042,-0.35092801,-0.261392,2.42699 +-0.76140201,0.0176118,-0.017125599,-0.25400901 +0.31837401,0.30008999,-0.126312,1.07618 +0.226467,-0.37610999,-0.069227502,-2.84215 +-0.306032,2.77965,-0.111448,-0.41195199 +-0.43816099,-0.51159197,-0.106719,0.74167699 +0.47551599,-1.59723,-0.088514201,2.89274 +0.47284701,1.45206,-0.34638199,0.46851799 +0.48996601,2.4739101,-0.136112,0.70731699 +-0.35598201,-2.58444,-0.012255,0.17591999 +-0.584203,-1.36323,-0.035755899,2.55513 +-0.31323001,1.70656,-0.044941101,0.89319301 +-0.21799099,-0.41261801,-0.040510401,-2.7993801 +0.51850998,0.85437298,-0.060548201,2.37309 +0.46293399,-0.364409,-0.098559298,-2.00719 +0.27056399,0.70448798,-0.097438499,-0.60683101 +-0.81484199,1.2868,-0.048059098,1.51627 +-0.109879,2.60816,-0.144293,1.10461 +-0.476275,-2.7290499,-0.0203178,2.90429 +-0.57857698,-1.89264,-0.021769799,0.94279802 +-0.54226202,-1.25248,-0.20938,0.63311899 +0.495141,-1.2177401,-0.28221601,0.59105802 +-0.38235399,-1.55559,-0.036714401,-0.53766203 +0.119334,0.47134399,-0.26575801,-2.9713099 +0.82534701,-2.17875,-0.157626,-0.0257542 +0.492706,0.46044999,-0.083189301,2.54214 +0.088191003,0.123535,-0.0187348,1.58538 +0.46415201,-0.404596,-0.0129809,0.90491301 +-0.832816,1.75506,-0.35147601,-0.67901099 +0.0189075,1.77686,-0.043238498,2.48052 +0.151797,-1.94864,-0.0128584,0.725353 +-0.38166299,-2.7612901,-0.107471,-1.8433 +-0.37232199,3.0332501,-0.062703297,2.4321499 +0.13184801,-2.79685,-0.074645303,1.42531 +0.53934002,-1.48464,-0.041047402,-1.34778 +-0.210756,-0.66776699,-0.0292737,-0.212589 +-0.157948,-1.6316,-0.0450541,2.1560099 +0.58454001,0.093162701,-0.089288697,0.043821201 +0.41389,1.9383,-0.132732,-0.54196501 +-0.063907497,-0.151871,-0.0281894,-1.5687701 +-0.321522,-2.3592501,-0.0049540801,-2.9531 +-0.11174,-2.8815899,-0.171519,-2.9159701 +0.72475398,2.4216299,-0.079989403,2.0144899 +0.204955,0.71508801,-0.097824499,2.83127 +-0.32526001,-2.9463301,-0.100106,0.98713601 +0.16628399,-2.4531801,-0.250741,-2.2293401 +0.044366099,2.4969499,-0.028025299,-0.45067099 +-0.055750702,2.00985,-0.059980899,1.80056 +0.29816499,2.52492,-0.104725,-1.57568 +-0.28035501,0.56345099,-0.122127,-2.36518 +0.41939899,0.838094,-0.124689,2.67554 +0.053745501,0.38928199,-0.095968001,0.19233 +-0.48275799,0.092389703,-0.030760299,-0.59193403 +-0.58725899,2.3027101,-0.0902991,0.120997 +0.61848998,-2.2093301,-0.083509304,-0.92762297 +-0.045469798,-2.9064,-0.110985,1.70841 +-0.64839298,-2.2901499,-0.0170072,-2.9405301 +-0.78132999,-2.1856301,-0.17771199,0.38344401 +-0.57385302,2.5792899,-0.0084049599,2.9877999 +-0.81843698,0.23913699,-0.186763,-0.393424 +-0.39333799,0.64393502,-0.0155013,-1.3222899 +-0.80028498,-1.22746,-0.0069100498,-2.23806 +0.30141401,2.76454,-0.0093163,1.18174 +0.36746299,1.9220901,-0.00516142,-1.07726 +-0.346306,2.6544199,-0.016512601,-2.93647 +-0.405884,-0.61765099,-0.0134903,-2.6322801 +0.14562701,-2.6294999,-0.085023701,-0.99025899 +0.76848501,-0.452811,-0.0055215298,-2.2031 +0.42138401,-0.79336298,-0.0086763604,2.1411901 +-0.54525399,0.657812,-0.037853401,0.77338099 +0.077518798,1.5396,-0.221083,-2.44171 +-0.090525903,-2.9435599,-0.083301,2.54724 +0.27517501,0.55782098,-0.0765604,1.98797 +0.49315599,0.218456,-0.0637298,0.31514701 +0.228366,2.3457799,-0.175879,-2.33371 +0.106373,-2.11448,-0.0278011,-1.69857 +-0.22383299,2.3352699,-0.079993598,0.68986899 +-0.080438502,2.3319499,-0.022661701,-3.04321 +0.52500999,2.69453,-0.0146172,-1.8264199 +0.404607,-0.753272,-0.051165599,-2.0489399 +-0.13122199,0.52603698,-0.0374921,0.55627698 +0.61499399,-3.06024,-0.087773897,3.0451701 +-0.35476899,1.67922,-0.122258,0.87107301 +-0.609954,-2.94889,-0.166061,2.75664 +0.13380601,-1.5984401,-0.040451299,2.3473599 +0.27717599,-0.937181,-0.0827014,-0.19920599 +-0.199323,1.93173,-0.13901,-1.66976 +-0.74305499,-0.61585802,-0.13481501,0.656115 +0.339627,-2.30018,-0.030601,-1.0968 +-0.10899,-2.6216099,-0.0046473402,3.0775299 +0.20232201,2.0968101,-0.171404,0.34533501 +0.28603801,0.062803,-0.18568499,1.81372 +0.686575,-0.92251801,-0.0208205,-3.1408701 +0.354377,-1.86146,-0.053681102,3.06867 +0.57420599,-0.62446702,-0.169935,2.3443201 +0.554326,0.34597701,-0.29163501,-0.068237796 +0.55866301,-2.5673699,-0.0258459,-2.5943999 +0.181005,1.59693,-0.026473301,-3.1296201 +0.0780394,0.73698401,-0.032909501,-2.33692 +0.55831301,0.65158701,-0.086304799,-1.15581 +0.62280703,-2.46668,-0.0077179698,0.81734502 +-0.0128846,-1.30814,-0.042338599,0.69458902 +-0.46163499,-1.84629,-0.154318,-0.176875 +0.074066199,0.98718202,-0.0587635,0.77849001 +-0.68435502,0.0406061,-0.0180861,0.64056098 +-0.63609701,1.58755,-0.00547102,2.1199801 +-0.686333,0.66030598,-0.182074,0.53193003 +0.286226,-1.33447,-0.192996,-2.80142 +-0.19845299,2.7827301,-0.111045,-0.40862399 +-0.30705801,-1.40712,-0.107193,1.82344 +0.83803302,-0.74067599,-0.216379,-3.09199 +0.021561701,0.96195602,-0.092007898,-1.87247 +0.150076,-0.72835201,-0.020020399,0.0180769 +0.56562001,2.53953,-0.0144355,-2.07039 +-0.0148982,0.428195,-0.157242,-1.11572 +-0.0256347,0.88608801,-0.033721201,1.92336 +0.32262999,-0.38898399,-0.14485601,1.36401 +0.64347303,0.35351101,-0.34540799,1.90976 +0.162312,-1.1844,-0.123222,-3.03637 +-0.80445898,-1.79176,-0.018774001,-1.0403 +-0.135452,0.87743902,-0.0159918,2.02772 +0.177635,-2.8412299,-0.0146764,0.084858596 +0.53919101,-1.58259,-0.103061,-1.00876 +-0.44058901,0.57834798,-0.111898,-1.7631201 +-0.46830699,1.94524,-0.081186399,-2.5074799 +0.165787,0.77376699,-0.0065693501,0.96870703 +-0.205708,0.58201402,-0.059357401,-0.64304698 +-0.63377601,-0.45260701,-0.0030332699,-1.55918 +-0.54905599,3.01508,-0.0129362,-0.052656598 +-0.105857,2.60831,-0.28057301,0.350146 +0.017208399,-0.125232,-0.032590799,-0.086546302 +-0.12932,-2.28772,-0.0036076801,0.61375803 +-0.00919744,1.46881,-0.210309,-0.87409401 +-0.510162,2.90604,-0.230882,0.49953401 +0.78098798,-0.67632997,-0.028791299,2.2834599 +0.046148099,0.12503999,-0.063760102,2.5915201 +-0.421691,-0.044934101,-0.038631499,0.93075198 +-0.33683401,-2.69151,-0.201259,0.38433799 +0.82089102,-1.4643,-0.0037809401,2.89376 +0.38408399,1.72569,-0.0722517,3.0027201 +0.207093,3.1073599,-0.067890003,-1.63336 +-0.58268797,2.5269899,-0.0140968,-1.38791 +0.0172041,-2.75861,-0.074976601,1.53624 +-0.38608599,-0.68376398,-0.0069083199,0.72116601 +-0.85510403,2.26228,-0.26651701,0.00372702 +-0.41926199,-1.33397,-0.0070285401,1.25527 +-0.38893101,2.2225101,-0.245876,1.44525 +-0.48087201,2.46245,-0.0132983,2.6314399 +-0.428417,-2.1059401,-0.032704301,-2.46065 +0.0527661,2.54985,-0.036598399,2.22542 +0.0083825802,-0.25165999,-0.0492591,2.9641199 +0.0814448,-1.08516,-0.0424507,-3.0878301 +0.83983201,1.09443,-0.083728403,0.069653399 +0.108327,2.6296401,-0.0127162,1.1538301 +-0.75352401,0.89142299,-0.241331,0.39951599 +-0.150527,-0.67349303,-0.117468,2.4084499 +-0.242203,1.47859,-0.050842501,-2.49436 +0.129702,-0.74735498,-0.106381,-2.06989 +-0.70902199,-1.1047601,-0.016269,-0.44325 +-0.23558,0.65101999,-0.028314799,0.13338301 +0.75334102,-2.85063,-0.037213299,0.59059399 +-0.074637003,-1.71874,-0.016176799,-0.981655 +0.84793103,-0.23910999,-0.059290301,-0.26919499 +-0.112495,-2.4846101,-0.23371799,-2.4616101 +0.430794,-1.02948,-0.049169101,3.1008899 +-0.87495899,0.181416,-0.0246417,2.5747499 +-0.635813,-2.2425699,-0.0138162,1.98853 +0.27632701,3.0548201,-0.00245194,-1.72277 +0.322292,0.46188301,-0.0109982,-1.69558 +-0.32319,2.8849001,-0.039093498,1.46306 +0.27964899,-1.17163,-0.157416,-0.99904501 +-0.63743198,-0.94763201,-0.0365921,-2.1100099 +-0.63437003,2.4962399,-0.0074101598,1.68056 +0.548329,0.084907398,-0.0574928,-0.25878799 +0.62849897,1.27343,-0.066274703,-2.5943301 +-0.34651101,0.78776598,-0.062208999,-1.3776799 +-0.14257801,3.1353199,-0.039424401,2.5805199 +-0.712677,-2.19999,-0.33174101,1.92835 +0.965738,-1.6349,-0.20706099,1.11973 +0.39131999,0.35173899,-0.046908401,-2.28548 +0.74902099,0.76959503,-0.132425,2.57423 +0.34289101,0.101966,-0.106202,0.81862098 +-0.717565,-1.48437,-0.103096,1.05075 +-0.176258,-2.99891,-0.039985299,0.22351199 +0.35476801,-2.3404601,-0.077814601,0.602862 +-0.77285802,-1.5637701,-0.0849315,0.92596102 +0.220165,-2.0021601,-0.177145,3.1404099 +0.164369,-2.1286399,-0.129886,1.9618599 +-0.655963,-2.99279,-0.139506,2.6490901 +-0.51395601,0.63293302,-0.125398,-2.4523301 +0.115674,-2.2242701,-0.058527499,-0.98528099 +-0.50856102,0.59245902,-0.044231299,-1.4076101 +-0.37073201,0.97156799,-0.00694237,0.27313799 +0.35803699,-0.67125601,-0.0049234,0.98528099 +-0.24829599,1.81062,-0.00793711,-2.8074 +0.234359,-0.37914899,-0.115116,-1.16574 +0.56582099,1.83729,-0.12933201,2.10744 +0.50180203,-0.059633501,-0.031383999,0.14401101 +-0.26229,-3.0972199,-0.094809599,-2.46878 +0.122868,-2.2641201,-0.0223397,-1.54229 +-0.848791,-1.08314,-0.0169624,-0.40970501 +0.49368501,-2.5174899,-0.11177,-3.05007 +0.46465501,0.75060397,-0.066098697,2.4883599 +-0.50350398,2.11497,-0.23187,2.45011 +-0.40024999,-0.196161,-0.28327501,-3.09217 +0.41969299,-0.37383601,-0.207174,2.6075699 +-0.0147452,-1.60506,-0.026695,-2.5074401 +-0.750081,0.71126902,-0.16776399,2.3834 +0.62635201,0.428018,-0.085670397,-2.3011401 +0.81096703,-0.96264601,-0.0266505,1.288 +0.48375699,0.433449,-0.0544325,-1.19657 +-0.69928598,-0.062646598,-0.0218587,3.0197999 +0.70529801,-2.4135201,-0.077946998,0.076662898 +0.102396,0.495756,-0.127029,2.4084699 +0.63662601,0.84359598,-0.033765499,-2.2371299 +0.21586999,0.47156501,-0.0381485,1.07533 +-0.51587999,-1.24814,-0.0388554,2.0015099 +-0.28624499,-2.16185,-0.042503301,-1.1275899 +0.52836502,1.32274,-0.032016501,-3.11378 +0.48754299,-2.7674301,-0.158676,2.2341101 +0.44830099,-1.78269,-0.0128677,-3.1247499 +-0.26668799,-1.04796,-0.0078442004,-1.83965 +0.54607499,-0.669779,-0.171831,-2.57599 +0.487479,2.0264101,-0.051583599,-0.64837998 +0.79873002,1.89372,-0.022663999,-2.5213001 +0.91671097,0.28431499,-0.47036999,0.67284501 +0.69817501,1.60811,-0.0115742,-2.9563401 +-0.458846,-0.81978601,-0.0363621,-0.52064002 +-0.783077,2.2941799,-0.076470703,2.3694501 +0.71701598,-0.34502399,-0.035131801,2.65993 +0.25260401,-1.33759,-0.088426799,-2.6036699 +0.72302699,1.5406801,-0.167346,-0.0118051 +0.085266203,0.92963499,-0.047751501,2.50562 +-0.83962399,-1.09622,-0.023152299,1.56612 +0.658315,1.71646,-0.013154,1.55178 +-0.77614802,-0.055059701,-0.0298445,-0.39242601 +-0.224612,-1.1428699,-0.079022802,2.8582201 +0.72370899,1.34009,-0.0161583,2.3071301 +0.36808601,-2.9168899,-0.201141,3.0801001 +0.426366,-3.1157801,-0.00959899,0.89872998 +0.59985203,2.5239501,-0.0123947,1.17834 +0.339636,-0.58204699,-0.068006597,-0.60883898 +0.21705,1.1275899,-0.129933,-0.65919298 +0.030071599,0.56773102,-0.0045855101,-0.788306 +-0.390641,0.50779498,-0.0294124,-0.68216199 +0.92560101,0.039310198,-0.0499584,2.6451099 +0.27085099,-0.0101997,-0.14216299,-2.47627 +-0.48491201,-2.99564,-0.00450435,2.1447301 +0.111539,-2.40835,-0.103961,-2.2736599 +0.338081,-0.48655301,-0.051300101,0.23932099 +0.48235101,-2.81125,-0.0200096,-2.8936901 +0.14022,2.46364,-0.019794701,1.8704 +0.56958002,-2.0532,-0.038380601,2.9709301 +-0.31264701,1.02162,-0.0476969,-2.79283 +0.25503799,2.4356799,-0.0113782,-1.0765899 +0.104507,-1.61271,-0.0018302,-0.84795803 +0.021714101,2.95386,-0.0687581,-2.1245899 +-0.290501,1.7618099,-0.069787301,2.7325201 +0.395064,0.666969,-0.106714,3.13377 +0.48014501,-3.0938799,-0.0403606,-2.98842 +0.80805999,1.87388,-0.0090080202,1.9878401 +0.231953,1.89141,-0.184108,-0.27333501 +-0.0138118,2.81125,-0.087690197,-2.4316001 +-0.57887602,-3.1266699,-0.023455299,2.95081 +0.235148,-0.26090401,-0.0288911,-2.4293301 +0.23258799,-3.02564,-0.0408131,-0.55620497 +-0.0531477,3.0867701,-0.0426271,-0.52346802 +0.53506899,2.5557599,-0.019594699,-2.5910499 +0.20946001,2.74439,-0.040695202,-2.86497 +-0.29534799,-2.73927,-0.023595599,-0.25292701 +0.57950699,-2.55861,-0.124622,-1.1060801 +0.094092198,1.94889,-0.0238207,-1.36067 +-0.049462199,0.58124799,-0.138771,-0.40969801 +-0.84939498,1.61955,-0.0266988,-3.03021 +0.385546,-3.0827899,-0.14119899,2.89379 +0.33215001,2.0691199,-0.043878399,1.2112499 +-0.80076998,-1.51929,-0.0168919,1.82486 +0.62345499,3.0336299,-0.028413899,1.26512 +-0.15042201,-1.404,-0.0040746802,-0.37626901 +-0.81386,0.801184,-0.037001599,-0.51836097 +-0.257433,1.47829,-0.0431576,0.743209 +-0.19163799,0.062592201,-0.070846602,2.9379499 +-0.135703,-1.11128,-0.035368498,0.57265502 +-0.336844,-0.0901777,-0.073929302,0.37163201 +0.90596998,-1.43574,-0.0349949,0.52177501 +0.60221499,-2.1712101,-0.0458274,2.21945 +0.35519999,-1.54062,-0.17855801,1.96535 +-0.91197902,0.174127,-0.057661999,-2.14416 +-0.68789297,2.17542,-0.102696,3.0189099 +-0.31556499,1.14732,-0.149379,2.4128001 +-0.840442,-1.50667,-0.031571198,0.117255 +0.180158,-0.49877399,-0.112627,-2.7869699 +-0.48803899,1.34053,-0.0173182,2.8152499 +0.53091401,-0.54209602,-0.027385799,0.230746 +0.31879899,-0.244707,-0.139211,2.8326001 +0.42243201,-2.0787301,-0.159474,0.53965002 +0.277459,-1.2536401,-0.098613001,2.2346499 +-0.21716499,-2.56321,-0.019878799,-1.06557 +0.36693701,-1.20625,-0.028265599,1.68434 +0.208561,1.17456,-0.097666703,-2.6928201 +-0.58258802,-2.49944,-0.115459,2.03316 +-0.0412337,-1.61665,-0.123374,-2.24509 +-0.171949,1.71199,-0.063542902,2.13693 +-0.55856502,-1.8812,-0.058046799,0.59346902 +-0.64271897,2.83571,-0.139906,-1.19163 +0.192269,2.7168701,-0.162203,2.70204 +-0.73311698,-1.78894,-0.036143601,1.91469 +-0.57336998,-1.53553,-0.0091891401,2.68455 +-0.406295,-0.94621098,-0.031987298,0.92505598 +-0.37142199,2.6457,-0.297106,0.0862059 +-0.24929599,0.556162,-0.0127189,-0.483661 +0.253649,0.94408798,-0.14510401,-2.5752101 +-0.393013,-2.9263301,-0.019950701,2.6796 +-0.57584798,-1.7852401,-0.086948201,3.02036 +0.449294,2.12744,-0.0091108,-1.2559 +0.120557,2.5518799,-0.060892001,-0.85530198 +0.198616,0.91298699,-0.291114,0.25745699 +0.29411301,1.3905801,-0.036724001,1.75745 +-0.142518,-2.83672,-0.18699101,2.09391 +-0.34777299,-2.6013999,-0.135765,0.158133 +-0.013909,0.81505001,-0.152612,3.0737801 +-0.439812,-2.69034,-0.030876501,-0.330006 +0.216139,0.39150199,-0.067762703,-1.49695 +-0.046601601,-2.94013,-0.0609533,2.9511399 +0.379464,1.91555,-0.159576,-2.0459099 +0.62585199,0.057560999,-0.0129297,-2.52999 +0.65998799,1.0999,-0.053593401,-0.600447 +0.27325401,0.91843301,-0.160229,2.6901801 +0.195544,1.32275,-0.039495699,-2.9108801 +0.108896,2.59481,-0.0065105599,2.5977199 +-0.535532,-2.5795701,-0.0236232,0.22036099 +0.235585,2.6953499,-0.039210599,0.28036499 +-0.064121097,0.25781399,-0.0091373902,-0.87465501 +-0.34739801,-1.8842601,-0.247849,0.50998199 +-0.040190399,1.29142,-0.078553103,0.30077499 +0.38962999,0.68825501,-0.222192,2.9603701 +-0.29719001,2.0204699,-0.121975,0.79510099 +-0.045423001,-1.86572,-0.0216389,-0.074881099 +0.209941,1.15356,-0.0160852,2.92173 +-0.226327,-1.5784,-0.30130801,1.8141299 +0.41985101,0.58266002,-0.129272,2.0690601 +0.0997077,-0.033042099,-0.0066490201,-0.636298 +-0.345893,-2.3749599,-0.073315501,-2.2980399 +0.707829,1.3824,-0.107086,-0.395349 +-0.135786,-2.15622,-0.30068499,-0.70689499 +0.17919201,-2.5566499,-0.0129749,-0.60189998 +0.54108602,0.676377,-0.100532,-1.57382 +0.217693,-1.92018,-0.0152572,-1.44647 +0.052161299,-0.24453899,-0.240527,1.16722 +0.91435999,0.71040601,-0.070661202,0.56730801 +-0.134325,-1.78192,-0.040484201,-0.74201399 +-0.37533799,0.27806199,-0.053621501,-0.37303901 +0.36458799,-1.27246,-0.032237999,-0.74985898 +-0.69429803,0.123133,-0.031971201,2.40925 +-0.248109,2.1445799,-0.027327601,-3.0079701 +-0.164529,0.55614603,-0.0218013,-2.4170201 +-0.66643,-2.1056001,-0.0233157,-1.10269 +-0.158796,2.81849,-0.0276087,2.2527201 +0.538149,-1.90407,-0.063433699,-0.61038202 +0.62401402,0.31344301,-0.110121,-3.0664401 +-0.69711399,0.242571,-0.057117399,3.07289 +-0.48466301,-2.6532099,-0.0015585,1.39931 +-0.51896101,2.6454,-0.024634499,2.41804 +0.27014101,1.3486,-0.0508141,-1.03211 +-0.0057964302,-1.38852,-0.229534,-2.07233 +0.44644299,-3.0332699,-0.267019,-1.16899 +-0.297905,2.89114,-0.072690003,0.95400298 +0.577461,-2.5350699,-0.0848943,0.89853197 +0.21702699,2.2355101,-0.052182499,0.76239401 +0.457977,1.44718,-0.074092403,0.918284 +0.278667,-2.86815,-0.027089899,-2.9818001 +-0.85033399,-1.63878,-0.054873101,-2.21597 +-0.199461,-2.3245101,-0.228778,0.097713999 +0.61425197,-0.80281401,-0.41979,3.0825 +0.24550501,-1.93607,-0.21152399,0.032719299 +-0.0048408601,2.36292,-0.0484103,-2.69628 +-0.47769299,1.94146,-0.019095501,-0.50902301 +-0.158721,-2.7130101,-0.0088400701,1.39791 +-0.57462001,1.00626,-0.120287,2.7127299 +0.76622802,-1.82987,-0.203371,2.6528599 +-0.160163,-1.1605999,-0.19869401,1.43721 +-0.0048892298,-1.45358,-0.019177999,-2.4096401 +0.28488401,-0.94869,-0.060546398,-0.606332 +-0.28793699,-2.0622101,-0.065036401,0.41802001 +0.215241,0.52452898,-0.098985001,2.4071801 +0.39923999,-1.7392401,-0.100064,-0.75489801 +0.81262797,0.59561098,-0.246878,-0.18785401 +-0.0071474402,2.2598901,-0.19225501,-0.44156 +-0.172703,-3.0886099,-0.0109035,-2.34653 +0.504448,-0.00167862,-0.085780703,-0.0710003 +-0.0392146,0.900051,-0.073698997,-2.9775701 +-0.81244701,-0.505144,-0.033656798,-0.241558 +-0.42183799,-0.107318,-0.039506599,2.3900399 +0.307679,-0.389523,-0.058613501,-2.1152599 +-0.187691,-1.09885,-0.0151141,-0.37702399 +-0.546893,0.25532201,-0.102579,-2.53265 +-0.192077,-2.58547,-0.057875998,-1.29397 +-0.52880102,-1.0000401,-0.28051901,2.2651501 +-0.313591,-2.4974699,-0.19154499,1.49985 +-0.103349,0.42353299,-0.032356799,-0.274984 +0.54004198,0.49075401,-0.0316258,-2.9367001 +-0.35302299,1.6629699,-0.085537396,0.839589 +-0.80025798,1.2501,-0.027026201,0.142462 +0.32408401,0.71813101,-0.25581601,-0.027624501 +0.88989401,0.73348099,-0.121587,2.3187399 +-0.17903,-1.91029,-0.150692,-1.05257 +-0.45731601,1.44742,-0.0905395,0.40066299 +0.057518099,1.3190399,-0.035688002,-2.84428 +-0.62408203,-1.9455,-0.125513,2.9189999 +-0.78190303,1.30188,-0.090381399,0.33933201 +-0.73104602,0.89138001,-0.035436701,0.93317598 +-0.203353,2.55532,-0.026884601,0.089813903 +-0.436331,-1.74164,-0.112183,2.3770199 +0.34722501,1.1319799,-0.059983399,-1.5194401 +-0.358349,1.03929,-0.077203304,2.3119299 +0.0052536,-1.20145,-0.0135471,-3.01862 +-0.75107998,2.92431,-0.0509791,-0.82012397 +-0.19189499,2.16137,-0.0109183,-1.35656 +-0.083801299,3.08903,-0.0086732199,2.5852001 +0.40934801,2.73048,-0.0227166,-2.1022301 +0.70998597,-2.5533299,-0.065677099,2.97646 +0.431784,1.95848,-0.0424641,0.924945 +0.67493498,2.24312,-0.241487,-2.4521301 +0.38350299,-0.594423,-0.104644,0.089927301 +-0.38977799,-2.4470501,-0.14316601,2.27019 +0.74645501,-2.5575099,-0.148545,-0.30956301 +-0.38784599,-1.14358,-0.0082964897,0.061193701 +0.217751,-2.8785601,-0.078751802,1.8514301 +0.19140901,-0.742773,-0.0229389,-3.0794301 +-0.45846301,1.1210001,-0.050793801,-0.80882198 +-0.076538898,-1.55439,-0.108265,0.044040602 +0.29032999,-0.754085,-0.0499634,-0.971371 +0.61595601,3.0794599,-0.15345301,-2.4226799 +0.033080801,-0.58587402,-0.100906,0.033661999 +0.67151898,2.51563,-0.037874602,0.74067301 +0.82019401,-3.0228601,-0.106916,1.69181 +0.40370101,2.3283601,-0.041873202,-2.3178201 +0.46086699,-2.1136301,-0.015416,-0.41797301 +-0.25019801,-2.1783299,-0.0147034,-2.83654 +0.47970799,-1.5282,-0.016106701,-0.67621899 +-0.100405,-2.6168301,-0.045462001,-2.78565 +0.28641501,-0.66645497,-0.069409899,-0.218142 +0.00275077,0.18299399,-0.186212,2.06181 +-0.112142,1.50804,-0.044130798,1.70349 +-0.54351199,-0.803617,-0.164912,-3.1360099 +-0.41902399,0.30970401,-0.32491899,-1.11895 +-0.90807599,-1.31638,-0.062236901,2.4976699 +-0.64973402,-0.151391,-0.101695,2.40521 +0.61433798,2.8127601,-0.11761,-1.02507 +0.079448797,0.49287999,-0.084993199,-0.0976649 +0.48483899,2.2702401,-0.24883801,1.0597399 +-0.329606,-0.125494,-0.18638,1.8133399 +-0.66913098,-0.049658801,-0.034286901,2.3760099 +0.053428799,-0.80456698,-0.026286,-1.1957999 +-0.53039998,2.79056,-0.097416602,-2.2389801 +-0.50214201,0.148259,-0.00321717,-2.5158 +0.39722401,1.00117,-0.0054760901,0.69713801 +-0.29709801,0.93639398,-0.030639401,-2.83252 +-0.51660299,-1.66435,-0.047812399,-2.5346899 +-0.50206202,0.96694601,-0.3319,0.40547001 +-0.62394297,-1.67144,-0.050066002,2.06285 +0.069681302,-0.443746,-0.254278,-0.52320302 +-0.57644498,-1.24663,-0.143428,2.7151401 +0.11214,-0.456799,-0.065205202,-1.8995399 +-0.126173,2.25946,-0.080583699,2.83043 +-0.12739,0.76602,-0.068955101,0.62294799 +0.71439499,-0.104369,-0.30783799,0.53815699 +0.46476799,-1.09995,-0.0179481,2.8903699 +0.131368,-2.98366,-0.026191199,2.9314101 +-0.212878,-1.34886,-0.12939601,-2.90291 +0.41123801,1.35377,-0.20479301,-0.51590401 +0.058408201,0.70020998,-0.071186297,2.0954399 +0.69821799,1.8611799,-0.068228498,-2.96717 +-0.069076501,-2.8989699,-0.017434699,-2.9315801 +-0.0403325,1.0841,-0.046966199,-2.2130201 +0.205185,-1.0778199,-0.021949099,-2.6740501 +-0.63310403,2.7838199,-0.038965002,-1.02457 +-0.171436,-0.45045,-0.091025099,-1.71592 +-0.85895002,1.36305,-0.20367099,-1.3048 +-0.82841903,-1.96912,-0.022001499,-2.1452 +0.2281,-2.80338,-0.119628,1.08287 +-0.58152699,-1.5209399,-0.0116689,2.23282 +0.277731,0.359945,-0.084540099,-1.29076 +-0.54156101,2.0581701,-0.0082055302,-0.0126621 +-0.572954,-2.40466,-0.096335799,2.2849801 +-0.38568601,0.274057,-0.025924001,1.92249 +0.22631399,2.5380001,-0.0897009,0.39286 +-0.42807099,2.1851699,-0.0812812,-0.079569697 +-0.79824299,-2.57284,-0.0594666,0.28619701 +0.60073102,1.94212,-0.086539797,-1.74606 +-0.55368,2.3592601,-0.212384,0.36377501 +-0.39993301,-2.33792,-0.207142,0.76589298 +0.079408601,2.3469701,-0.0415022,1.99225 +-0.52577901,-1.29326,-0.0350076,-1.09884 +-0.32489601,0.253456,-0.0443497,-0.154026 +0.036993399,2.7897799,-0.117799,0.106992 +-0.51665503,-1.83284,-0.083091401,-2.9121001 +-0.351841,0.68716502,-0.068487398,2.4874301 +-0.27930501,-1.1023,-0.034700301,2.4985299 +-0.662817,1.15992,-0.104371,-2.99066 +0.271056,3.0046699,-0.031323601,-1.22726 +-0.53751397,0.049890399,-0.0041954499,0.60864598 +-0.24410801,2.45208,-0.00983747,0.28777 +-0.37509501,-0.75098199,-0.0109407,-2.73808 +-0.39599401,-1.5292701,-0.11148,1.66912 +0.367327,2.26564,-0.022686901,-3.0453801 +-0.081081197,1.02702,-0.042461999,-0.264081 +0.34773001,2.33565,-0.063442402,0.65553898 +-0.24736799,1.20049,-0.0629704,-0.551763 +-0.70677698,0.66918099,-0.057225499,2.4365799 +0.1936,1.67272,-0.034346201,0.22446799 +-0.82983899,2.0441899,-0.114624,-1.5225 +0.85525399,1.7321399,-0.075714998,1.82877 +-0.26809499,-0.85215503,-0.057173099,0.83642697 +0.83682501,1.9529999,-0.047330599,-1.07515 +-0.36373699,2.4461701,-0.030058799,-0.97894102 +-0.76640803,-2.5841,-0.0594685,2.7272799 +-0.57209897,2.7187901,-0.13722201,-3.1190801 +0.143264,0.177057,-0.0113173,0.147361 +-0.86873698,0.373757,-0.0024814699,-0.51573902 +0.113321,1.35943,-0.059438702,-0.93795198 +-0.426366,0.99958497,-0.0293527,1.78646 +-0.48166999,-2.8111501,-0.16258299,0.091502801 +0.0243249,-1.02262,-0.064981803,0.54276901 +-0.78008503,2.8578,-0.20166799,1.83655 +0.025517,2.97893,-0.117079,1.75212 +-0.41839299,-1.19575,-0.060371801,-1.5505199 +0.95511597,-2.8176501,-0.0033062301,-1.20171 +-0.73815,1.9504499,-0.0123968,3.0966001 +0.218931,-2.24544,-0.065801397,-0.058518101 +0.27811101,-2.16802,-0.28083801,2.3233299 +-0.0702741,0.90542001,-0.107897,0.57471597 +-0.261841,-0.33108899,-0.117004,-2.80809 +-0.54808599,-0.98673999,-0.173954,0.94773197 +-0.221525,-1.81699,-0.080634199,1.57489 +-0.64705199,1.29822,-0.034203298,-3.1089499 +-0.0107409,1.3647,-0.031091301,2.52194 +0.32858601,-1.24393,-0.159898,0.066616103 +0.061970901,-2.36254,-0.087519802,0.35997999 +-0.075478099,2.95965,-0.14526901,-0.64194202 +-0.064071499,-0.333648,-0.030438401,-2.21311 +-0.117071,-1.1229399,-0.170096,0.24440999 +-0.202039,2.0920401,-0.033413298,2.7018001 +-0.67418498,-0.46590501,-0.0303014,-0.36958501 +-0.035103802,2.5231299,-0.017304,2.87765 +-0.142193,-0.76649398,-0.213579,-1.35256 +-0.550273,-0.121845,-0.072810099,1.88993 +-0.034561701,-0.34318301,-0.016045401,2.70223 +0.224573,-1.39081,-0.00770164,-0.048010301 +-0.53446102,0.89235997,-0.020083399,1.77899 +0.582941,2.92645,-0.034860499,2.81619 +-0.29595399,-0.123255,-0.27810699,2.9456401 +0.080767997,-1.76963,-0.0380284,-1.4436001 +0.055237401,0.99073398,-0.0447338,-0.180751 +-0.0908411,-2.7242801,-0.063050903,-2.9834499 +0.26763701,-1.5296,-0.031359799,1.36466 +0.15465499,0.56725401,-0.0150944,-1.78908 +-0.602359,2.8057001,-0.085779697,-0.74908 +-0.18279301,-2.92168,-0.039421201,0.338478 +0.441852,0.64320898,-0.028049899,-0.00061140902 +-0.179803,0.65728498,-0.020982901,-0.43792501 +-0.479671,0.95906597,-0.016635699,-2.6849999 +-0.132883,-2.5130799,-0.11833,0.202824 +0.51159,-2.66169,-0.39165401,0.500229 +-0.087693498,-1.2297601,-0.022411101,-0.103419 +-0.28007099,0.036034301,-0.318198,0.64727199 +0.22460701,2.61496,-0.0083905496,0.51808602 +-0.25270501,-0.058840301,-0.0036564399,-0.29141599 +-0.042922501,1.23066,-0.031110801,-2.7444999 +0.168385,0.88109899,-0.053541601,-3.02267 +-0.056853801,-2.4216599,-0.068718202,0.19383299 +0.075639799,0.75271398,-0.112431,2.7396901 +-0.67820197,0.62062597,-0.102926,-0.44131199 +0.118684,2.19274,-0.00465672,-0.0688188 +-0.67345202,0.46291301,-0.0011442,1.60075 +0.85975301,-2.4991,-0.0072462298,-0.179214 +-0.57428497,0.572124,-0.053335998,-0.77875501 +-0.095294997,-1.32875,-0.021845801,2.7679 +-0.35361701,-2.0741799,-0.12299,-1.77414 +0.375622,-0.075941503,-0.165604,-0.205465 +0.54991299,-0.143435,-0.0175792,-2.04285 +-0.48473501,-2.16412,-0.0448852,-2.4483299 +-0.34196499,-1.99026,-0.168221,2.75983 +-0.421617,0.57708597,-0.0263483,-2.18032 +-0.37200701,2.49456,-0.0095892297,2.48822 +0.64385402,3.0516801,-0.079510197,1.045 +0.595155,-0.024415901,-0.163956,1.19753 +0.15621001,0.345761,-0.0827308,0.59859902 +-0.18481401,1.34199,-0.137354,-2.3339601 +0.61070102,1.3796,-0.084153399,-1.1849101 +-0.50171298,1.78504,-0.053337201,-1.0664001 +0.32369599,-1.7187999,-0.052098799,-1.77219 +0.27729601,-0.52801198,-0.0091157798,-2.0729499 +0.135409,-1.87082,-0.0214497,2.8296101 +-0.00120221,-2.3758199,-0.122886,0.615973 +0.272282,0.35122001,-0.237955,-2.2509301 +0.045404099,-2.2394099,-0.088460699,-0.049844999 +-0.398289,-0.70120603,-0.079056501,-2.9854901 +-0.58291,1.62784,-0.052234799,2.6997299 +-0.051299501,1.6921099,-0.0141934,3.1124599 +-0.018055899,-0.84072101,-0.163545,2.3947101 +0.185298,-1.7100101,-0.0181746,0.35911101 +-0.0465964,-0.3628,-0.107865,2.8831401 +-0.679335,-0.55305201,-0.0294067,-2.97627 +0.127085,-2.3535399,-0.0299793,-2.8501 +0.016486,1.7720701,-0.0068499101,-2.34776 +0.41798401,-2.04793,-0.0760644,0.43366501 +-0.65937603,-2.77865,-0.0106429,0.16555101 +-0.82813197,0.83362597,-0.199936,-0.332257 +0.197228,2.36078,-0.017246,-1.25184 +0.21344399,-1.9943399,-0.073415898,1.71856 +0.74586898,1.9819601,-0.24916901,0.55114001 +-0.40814599,-2.1289101,-0.032219399,0.80607098 +-0.59821898,2.78844,-0.121874,2.5275199 +-0.28457999,0.86626899,-0.040412001,0.40862599 +-0.56741101,-0.622823,-0.053255301,0.64524001 +-0.51465702,-1.2046601,-0.048304401,-2.335 +0.56959897,-1.6917,-0.103768,-0.88207799 +-0.72077399,-2.9145701,-0.083955303,0.52635598 +-0.033678502,1.00381,-0.085029401,-0.67625803 +0.73713702,-2.69661,-0.090484098,2.0229101 +-0.16547801,1.0589499,-0.118519,-0.28555599 +0.72942299,0.38944501,-0.048392899,-1.02184 +0.22629,-0.24723899,-0.0365186,-2.5860901 +-0.54282302,1.07207,-0.0083256699,-0.240458 +-0.59368199,2.3740599,-0.0240751,0.463204 +-0.57336402,1.18907,-0.14673699,2.9345 +-0.30699399,-0.353405,-0.0832894,1.08866 +0.400116,1.78862,-0.117689,-2.4926801 +-0.87549001,-2.86308,-0.052174799,-1.78355 +0.124573,2.72649,-0.24619,0.73198199 +-0.113048,0.081983797,-0.00545554,2.52211 +0.31281799,0.61418903,-0.042877398,0.44512701 +-0.33069301,-0.39926499,-0.118705,2.3366699 +0.54303801,1.87076,-0.036063701,-1.57051 +0.36208001,1.08794,-0.088987298,2.9298699 +-0.169949,2.4681201,-0.28816101,0.220212 +-0.69016999,-2.1277699,-0.00278159,1.88219 +-0.70467103,-0.98994398,-0.0619861,0.019682899 +-0.208912,2.3585501,-0.091322303,-0.43859199 +0.57339299,-2.96929,-0.20349599,2.2497201 +-0.102414,-1.60221,-0.054711599,0.45945701 +-0.429382,3.09813,-0.126908,-0.90903997 +0.145364,2.4410501,-0.0534533,-3.0090401 +-0.40515399,0.177113,-0.032985002,0.70024699 +0.302329,-2.2027299,-0.0190184,-0.69791198 +-0.23905,-2.2021,-0.073808096,-0.304728 +-0.242245,0.53987902,-0.0050401101,-1.7171 +-0.25803101,0.647829,-0.28819099,2.02391 +-0.093278803,1.66329,-0.0283006,-2.54878 +0.16707499,-0.080853902,-0.027032999,1.15279 +0.96350998,0.56711298,-0.12573899,1.74933 +-0.65522701,0.021025799,-0.0079811504,-3.0181401 +0.27307001,0.96266901,-0.0845083,-1.62843 +0.084694803,-2.08446,-0.106352,-0.42809099 +0.016604399,-2.9650099,-0.065653801,2.86606 +0.38060501,-2.9416101,-0.113232,2.62731 +-0.43431199,2.88851,-0.0371891,1.21535 +-0.171928,-2.0007601,-0.031887699,1.55082 +0.49511001,-2.0748601,-0.23386499,1.2096 +0.77951401,-1.78618,-0.121897,0.24403 +-0.64519101,-0.56232101,-0.060983099,2.3405399 +-0.37123501,-0.482454,-0.210453,0.19145399 +-0.37816501,-0.25252399,-0.0149161,1.97702 +-0.97281998,2.77911,-0.12662099,-0.14676701 +0.30542099,-2.1489501,-0.0143556,2.5422499 +-0.155083,-1.72047,-0.038406,0.43222499 +0.33601999,0.49543601,-0.025981,-2.53093 +0.692972,-1.11685,-0.0659547,2.6707001 +-0.131216,2.1666601,-0.00237887,0.037982199 +-0.63127398,-0.95441699,-0.00073705998,-1.94805 +-0.04228,0.201098,-0.188778,-0.47749501 +-0.40176699,1.96604,-0.0361472,1.3552001 +-0.25542101,0.211309,-0.43892199,-2.05005 +0.051104899,1.55237,-0.26226401,0.82569498 +-0.460812,-1.07085,-0.0088509098,-1.73848 +-0.44645101,-2.3387001,-0.067902699,2.53879 +0.364205,-1.80024,-0.0076017799,-0.048957899 +-0.0101547,0.351006,-0.0486595,-2.37889 +-0.57820201,-2.33711,-0.0233195,-0.273238 +-0.55147898,-2.3848701,-0.0097562997,0.261363 +-0.345882,-2.66853,-0.101012,1.40376 +-0.58454502,2.2295301,-0.00117792,0.893767 +0.63133299,0.033282802,-0.106211,2.8663399 +0.067442603,-0.90973002,-0.031493701,0.63319498 +0.483307,1.59638,-0.27849001,2.5018101 +-0.50305003,-2.0090899,-0.194304,-1.44844 +0.097563997,-1.52863,-0.0269327,2.5664101 +-0.194704,1.77163,-0.099255301,2.79321 +-0.262501,1.14331,-0.088715598,2.4640999 +-0.83676702,-0.98762298,-0.0112051,-1.5581 +0.419341,-0.278216,-0.0176498,-2.0278001 +0.258425,-2.6182899,-0.036728799,2.92945 +0.49246901,0.27362701,-0.179113,0.88621801 +-0.092418097,-0.182218,-0.120466,2.3954899 +-0.592655,-1.80518,-0.108591,-0.96683198 +0.211843,2.8889799,-0.027498599,3.0415001 +0.10725,-3.06213,-0.0258621,-0.43243799 +-0.436488,-2.3552699,-0.28093699,-2.3143899 +-0.33013299,0.064096302,-0.041696299,2.7000599 +0.67752302,-0.13196801,-0.0425389,-2.4296999 +-0.31045201,-0.306216,-0.102332,-0.91751999 +0.26998499,2.3002901,-0.0031906599,-0.48137099 +0.58097601,-0.553936,-0.068641603,2.59951 +-0.70441002,-2.37449,-0.022352099,-0.20928501 +0.235202,-2.9915299,-0.22213601,2.3336 +-0.58572203,-2.05567,-0.00131681,0.98515302 +-0.096623503,2.10922,-0.019410901,-2.81669 +0.076279297,2.8140399,-0.073353298,-2.8879001 +-0.28662401,-0.107786,-0.00897389,-2.50244 +0.66464502,1.21688,-0.109823,-2.2067201 +-0.353726,-1.50256,-0.233887,2.2356 +0.050829299,-2.7698901,-0.048797201,0.67183203 +0.26449901,2.72682,-0.159566,3.01559 +-0.45278901,0.45250499,-0.50384301,-2.1254699 +0.69528598,3.0838499,-0.244188,2.6147799 +-0.344161,-0.87000197,-0.0379669,0.86312401 +0.42716599,1.701,-0.030764099,1.58841 +0.67417502,-0.0077131698,-0.102625,1.42708 +-0.21312299,-2.91958,-0.16403,-2.6328101 +0.30893299,-2.2802601,-0.0067636301,-2.92959 +0.111196,0.76313102,-0.034877401,-2.57547 +0.46155599,1.60847,-0.0050698002,0.76291001 +0.35402799,-2.4154899,-0.084700398,-1.79703 +-0.648857,2.08442,-0.0291174,0.55207098 +0.33893999,2.4293699,-0.043030102,-0.0014478 +-0.49293101,-3.0838201,-0.0141302,2.36291 +0.547499,0.470211,-0.0095590502,-2.12904 +-0.053410299,0.55892301,-0.080568202,1.61509 +-0.58385402,-2.39382,-0.052945599,-1.16861 +0.240877,-1.71793,-0.052149002,-0.95802402 +-0.089625999,2.23492,-0.053007901,0.73466802 +-0.038907401,2.6756799,-0.0291951,1.67777 +0.34831801,-2.14393,-0.069971703,-0.95868897 +-0.047672,-0.32863,-0.0134798,3.0271001 +0.14673901,1.5569,-0.144154,2.66535 +0.46160299,1.18209,-0.040167902,-2.5317299 +0.082207099,2.6574199,-0.0288355,0.83280998 +-0.28655699,-1.72349,-0.15898401,1.14404 +-0.411062,0.89598203,-0.0063835401,2.2441101 +0.37449199,1.46533,-0.0052672699,2.09656 +-0.217003,-0.75197798,-0.0060224598,-2.0445099 +0.039741602,1.47711,-0.047172401,-1.85186 +-0.054512002,-2.9263101,-0.169147,-2.63135 +-0.80477899,-0.017558699,-0.00618851,-2.6770799 +-0.098714799,-1.63728,-0.23577499,-1.4091901 +0.27965301,-1.79898,-0.25900301,-0.61619598 +-0.79193097,-0.70390302,-0.072089903,-2.0193801 +0.52820098,1.46053,-0.151691,-0.28792301 +-0.39930901,-0.073106699,-0.164721,-0.99403 +0.60821801,0.18575799,-0.384756,-3.0288799 +-0.54730397,-0.65455699,-0.136595,-1.89563 +0.63149899,-0.74588197,-0.105931,1.1023099 +0.366418,0.066312701,-0.076815903,-0.128471 +-0.63652998,-0.83526897,-0.036568601,-2.9623201 +0.49625999,-2.98734,-0.0104508,-2.9912601 +0.56875497,0.992365,-0.047301199,2.9998901 +-0.44346899,-0.972633,-0.134892,2.85923 +0.447258,-1.93213,-0.081165701,2.5648401 +-0.57591999,-2.07149,-0.178609,-2.78385 +-0.18703499,1.86651,-0.102172,2.7760501 +-0.52892601,1.43549,-0.415268,2.55862 +0.193792,2.0757401,-0.016756199,-1.11781 +-0.31968799,1.68774,-0.0364617,2.4609599 +-0.0038354199,3.0919099,-0.0057603898,0.156627 +-0.20660201,-2.4558699,-0.16050901,-0.99369001 +-0.53734899,-1.96527,-0.24711201,0.66367 +-0.32875001,0.65833199,-0.067203604,-2.65856 +0.81786698,2.67535,-0.220011,-0.49522299 +0.061521702,-2.2833099,-0.0111983,-1.03479 +-0.107727,-2.21561,-0.148531,-2.07096 +-0.073678099,-0.101688,-0.160587,2.9143901 +-0.51753098,2.06547,-0.060853899,-2.5887101 +0.65507901,1.41636,-0.083010897,0.230676 +0.680884,1.28442,-0.053502999,0.72317702 +-0.302102,2.9238701,-0.101637,0.77829802 +-0.35978499,2.7569301,-0.20218401,1.3116699 +0.43532699,-0.0098184096,-0.0728046,1.04014 +0.211068,-0.55085701,-0.0073072002,-1.42656 +0.72802299,-2.4877601,-0.087516703,-2.7895999 +0.0128154,-3.0387001,-0.035911199,-1.88904 +0.84612203,-3.02121,-0.043749198,-2.45292 +0.434349,-1.2912199,-0.213392,-2.3100801 +0.105068,1.67881,-0.0816027,-0.21866 +0.91762501,1.78627,-0.0739282,1.04063 +-0.49470499,2.9716301,-0.287404,1.14837 +0.13372201,3.1412899,-0.071851701,-1.32539 +0.42155299,1.88015,-0.0488525,-2.67694 +-0.0240029,2.0218599,-0.071818702,2.6008699 +-0.087062702,-2.6091199,-0.20543,0.041244701 +-0.42220399,-2.4990001,-0.0189505,2.0424099 +0.23027,-0.60459501,-0.041200701,-1.53412 +0.43450099,2.5603001,-0.115572,-0.58198899 +-0.554676,-1.9938,-0.163118,-2.2720201 +-0.232342,-0.29771399,-0.0087292101,-2.2990601 +-0.357669,-1.90045,-0.256271,-0.37986001 +-0.365596,1.72188,-0.0407326,0.65682101 +-0.121462,1.86098,-0.0233938,2.7072001 +-0.77183998,-3.02969,-0.063526303,1.1371 +0.89721602,-2.2416999,-0.036135498,-1.31962 +-0.243917,1.72963,-0.094724797,-2.6218801 +0.094311297,1.05432,-0.14779399,-0.91794401 +0.023079,-1.02948,-0.035653599,-0.49451599 +-0.36744899,-0.552275,-0.152619,1.25556 +-0.18782599,1.16831,-0.173761,-3.05391 +-0.41863599,0.52034402,-0.098800898,-1.8161 +0.62466103,-1.0226001,-0.0200595,1.40132 +0.0870004,-2.06356,-0.037010301,-2.54828 +-0.336909,-2.84237,-0.040895399,3.0684299 +-0.65350002,1.34515,-0.0079743201,-0.59107101 +-0.74019301,-0.45277601,-0.064794898,-1.80492 +-0.262447,-2.7307601,-0.0146707,-0.67745799 +-0.069163598,0.72990203,-0.013173,-2.8480201 +-0.29079801,2.7304699,-0.18401401,2.11801 +-0.0907299,2.34219,-0.14198799,3.06917 +0.199947,0.92375702,-0.0431173,1.57354 +-0.496719,0.80390501,-0.057538599,-0.654311 +-0.55740398,-1.13544,-0.033917699,-0.204127 +-0.091871902,3.07305,-0.30468601,2.4458201 +-0.48848599,-0.90415001,-0.0400813,-2.8285899 +-0.33454999,-1.85191,-0.117412,2.7741899 +0.0085081197,1.0704499,-0.19517501,-1.52346 +-0.360129,1.43426,-0.079101898,1.51938 +0.509498,-1.15386,-0.089207701,-0.88486099 +-0.022192501,-0.57252997,-0.056682099,2.4600599 +0.50775099,2.0253601,-0.047254201,-0.121612 +0.65333003,1.19867,-0.207681,-1.03073 +0.39345199,-2.96645,-0.178064,-0.48890001 +-0.048202399,0.307587,-0.26522401,2.77935 +0.26603401,-2.2132101,-0.0434522,1.9331 +0.36201,-1.79966,-0.058364999,-0.65185499 +0.619596,-0.120595,-0.25731999,-0.59713501 +-0.14781,1.43204,-0.017375801,0.30741099 +0.072859198,-0.47537899,-0.124092,2.0899401 +0.77310801,2.8116801,-0.174932,1.47604 +-0.497554,1.25126,-0.057236299,3.09445 +0.223453,2.8594799,-0.043152001,0.590536 +0.51132101,2.2469499,-0.060832001,2.4648499 +0.26698399,-2.4168601,-0.0606432,0.69392502 +-0.498992,0.81811303,-0.083899498,0.680758 +0.30526501,0.78694099,-0.00392851,2.74506 +-0.38918701,-2.3461101,-0.0193375,3.03212 +0.49611199,2.82248,-0.049284801,1.30305 +-0.52685702,-1.8884701,-0.116296,1.33603 +0.110914,-2.47756,-0.175905,0.697155 +0.63738,0.43221101,-0.14614201,0.17882 +0.74488902,-1.4096,-0.027337899,1.53049 +-0.46989,2.2083499,-0.263439,-1.59618 +-0.228669,2.9217801,-0.059090801,2.8147299 +0.135811,1.16583,-0.0081832903,-0.40977499 +-0.505261,2.84956,-0.0098782796,1.75702 +0.444217,3.0085599,-0.030160099,0.84209198 +0.106083,1.14235,-0.0190244,2.5046899 +0.82316703,-0.67678899,-0.075636096,0.323883 +-0.86572099,-1.01933,-0.043166898,0.65909803 +-0.075590998,-0.99011397,-0.0063764299,-2.3443301 +0.436261,-1.24986,-0.174997,2.9951 +0.150961,-0.366539,-0.0484966,2.4145701 +0.67511898,-1.49935,-0.0143777,-2.5866899 +0.182335,1.9866101,-0.026579799,2.80127 +-0.020925101,3.0002699,-0.22474401,2.6083601 +-0.042655502,-1.75309,-0.0306524,3.11779 +0.26359501,-0.089537598,-0.098645598,-1.4918 +0.182969,2.3182299,-0.112813,-0.56619698 +-0.106702,1.92959,-0.030512,-0.62163901 +-0.382083,0.27807501,-0.0057575102,-2.42974 +-0.89449698,-3.06359,-0.028033299,-0.469513 +0.37893799,2.6703,-0.010376,0.63841701 +0.35747501,-0.42766401,-0.0143315,3.0227001 +0.11412,-0.083140999,-0.0344221,2.9433899 +-0.21276601,0.855968,-0.034481902,0.47392401 +0.42355099,-1.89821,-0.252323,2.8900399 +0.66655302,-2.6868501,-0.051481999,0.77327502 +0.862297,-2.0747001,-0.10972,2.1149299 +-0.133103,-2.5520401,-0.0119165,-0.017592199 +-0.103447,-0.6383,-0.023148401,-2.36867 +-0.20196,2.49825,-0.047802899,-2.9377 +0.34561601,0.94778901,-0.030894799,2.9508801 +-0.082424901,0.23884401,-0.0235944,3.0857201 +0.153127,0.47333899,-0.0076537002,1.0724699 +-0.249824,0.30760899,-0.033134099,-0.0127918 +0.53233302,-0.713135,-0.0264041,2.3564401 +-0.36993501,-2.8975201,-0.0029028601,2.77759 +-0.73646498,0.63476098,-0.146671,0.022958601 +-0.42253399,2.82144,-0.18951599,1.23814 +-0.57924199,-1.87094,-0.0049236501,0.42968199 +-0.375018,-0.787377,-0.0587909,1.93562 +-0.74971902,-3.1288199,-0.105549,-0.66397601 +0.289612,0.704018,-0.113638,1.71447 +-0.12178,-0.322474,-0.0303606,1.35449 +-0.43847501,1.76199,-0.14713199,-2.71069 +0.37074101,-1.63053,-0.108899,-0.81578201 +-0.61387402,-2.4542899,-0.196399,2.7109799 +-0.48827401,-2.28175,-0.0857215,2.39868 +-0.63041502,-1.31466,-0.121237,0.66962099 +-0.57265598,-1.81134,-0.0179908,-2.1724 +-0.661641,1.75275,-0.0183744,-1.18074 +-0.094254598,-1.3939101,-0.0112914,-2.4757299 +0.404008,-1.21258,-0.088553503,0.70715898 +-0.53584898,-2.4755001,-0.055045798,-2.8453 +0.92012298,2.0497301,-0.0086242603,1.0111901 +-0.064223297,-3.138,-0.034364,2.3161099 +-0.060486902,1.2553999,-0.0158963,2.2669599 +0.40610701,-0.84971797,-0.032478198,0.81659299 +-0.0240495,3.0052199,-0.0152446,-0.506616 +-0.305718,1.26806,-0.027181501,1.1992199 +-0.32310399,-0.0334507,-0.018226899,-0.54853302 +0.72783899,-0.67878503,-0.179217,1.33259 +-0.0148012,-0.0304635,-0.063489102,-1.62451 +-0.25522801,2.6296699,-0.088594601,0.16723301 +-0.69176,-3.0354199,-0.179343,0.019366501 +-0.48981199,-0.99169397,-0.145183,-2.3450899 +-0.34356499,-2.5271499,-0.069108702,0.30779099 +-0.39691299,-2.0188601,-0.0573439,0.25483 +-0.10269,-2.1968999,-0.025194701,-0.192729 +-0.160198,1.45915,-0.080641598,-3.1115999 +-0.077418298,2.57476,-0.030414799,-2.8710799 +0.40062401,0.758564,-0.087343603,3.02759 +-0.29006201,0.263064,-0.079592198,-1.48853 +-0.042658702,-0.223629,-0.113046,1.50026 +0.68184799,1.72168,-0.030814899,0.027292101 +-0.26670399,-2.05795,-0.188107,1.78306 +0.63538498,2.82218,-0.16727901,1.78098 +0.28672001,-2.74666,-0.106559,-2.68716 +-0.35246399,-2.9994099,-0.023662001,-1.48369 +0.0271695,0.44730401,-0.12893599,-1.6454901 +-0.29114199,-2.5125799,-0.0113458,1.0739501 +-0.61321503,3.1073799,-0.00740354,0.75643897 +0.25143,1.30802,-0.0078500304,-2.2904999 +-0.51515698,2.53971,-0.118893,-2.7211201 +-0.384938,1.09539,-0.159372,-2.6352799 +-0.82133001,-0.52344501,-0.282327,-1.66483 +0.135837,1.62323,-0.0691723,-2.27051 +-0.49096599,2.0998499,-0.044392198,1.59902 +0.85035598,-2.0561299,-0.0189371,0.108689 +-0.41723499,-0.72006798,-0.0176706,0.0225219 +0.29358801,-2.65204,-0.018076999,2.9403 +-0.31168401,1.2906801,-0.113287,2.83371 +0.62167102,1.6976399,-0.0114321,-0.98275602 +-0.218908,2.26176,-0.066932097,-0.986458 +0.34784999,-1.71262,-0.213953,-2.6775301 +-0.432226,0.77734298,-0.042038999,2.96258 +-0.0113527,2.11607,-0.0793432,-0.72041202 +-0.0615477,2.35794,-0.073266,-2.4969599 +0.20890801,2.3369601,-0.079179302,-2.7195499 +0.0117113,-0.217022,-0.0457507,0.30217299 +0.59113401,-2.221,-0.0143217,-0.39096999 +0.15485001,1.26068,-0.049733002,-2.2665801 +0.320842,2.5685201,-0.103217,-0.350835 +-0.498467,2.52983,-0.144035,2.15224 +-0.36910999,-1.97121,-0.18281101,-0.92113203 +-0.0270273,1.1487,-0.076950498,0.116258 +0.45990399,-1.5967799,-0.0366094,2.4177401 +-0.052878302,-1.24173,-0.129502,-1.0787899 +-0.437902,1.33622,-0.00351503,1.76638 +0.0216437,-2.0899799,-0.035827301,2.62639 +-0.61304897,2.0234001,-0.247844,-2.7298601 +0.263587,2.8044,-0.126109,2.33043 +0.61457902,1.18577,-0.078585699,0.037334099 +-0.37658501,2.45223,-0.108509,0.845191 +0.40861401,2.3150699,-0.0357088,-1.60388 +-0.63449597,-1.55195,-0.079653703,-0.164983 +0.166683,1.9721,-0.136867,-2.01197 +0.39601699,1.65425,-0.061699498,-0.54720497 +-0.29620999,-2.01683,-0.0536847,-0.839396 +0.56571299,-0.60069799,-0.027127899,1.09181 +0.32582301,-1.35308,-0.090584598,0.52385801 +0.204814,-0.85362297,-0.0369468,0.74232697 +0.41075099,-0.27593601,-0.0158825,2.94765 +0.288515,-1.16782,-0.0273709,-0.79412299 +-0.110288,-2.4933,-0.0463573,-1.2595201 +-0.79389298,-2.7479801,-0.13596401,0.304355 +0.295183,-2.0130701,-0.163629,0.172075 +0.187644,2.8397501,-0.162683,-0.53640002 +0.32180399,-1.23422,-0.133972,-1.43652 +-0.53967702,-2.4761901,-0.0116156,1.03846 +-0.69879401,-1.12567,-0.010604,2.8298199 +0.323589,-1.12863,-0.157515,-3.1373 +0.25802001,-2.70086,-0.112316,-0.59049499 +-0.189825,-2.85199,-0.0076415702,-2.4684999 +-0.541394,-0.91024202,-0.032919001,-0.446013 +-0.62312001,1.59645,-0.212685,-0.40642899 +0.25073099,0.40290999,-0.050269298,-0.85153401 +0.184864,1.02798,-0.260784,2.5628901 +0.45358601,2.5295,-0.048226099,0.45164001 +0.0144674,2.28284,-0.049082998,-2.9770999 +-0.735376,0.62411499,-0.092079103,0.856022 +0.31423301,-0.73171502,-0.00777434,1.26577 +0.139825,-2.6492701,-0.049531098,-1.73971 +0.43104899,1.3774,-0.087705798,-3.1223199 +-0.66199797,1.36606,-0.066900201,0.41700199 +0.70126301,3.1401,-0.018244799,-0.329622 +-0.179941,-1.90166,-0.037891001,2.1956699 +-0.49746501,-3.0211301,-0.0145566,-0.64661002 +-0.180007,-0.139615,-0.00378209,0.65575403 +0.23374,-0.193131,-0.0046785302,2.7093699 +0.41793701,-1.02783,-0.060731102,-1.28804 +0.75147998,0.81709802,-0.175703,-3.01987 +0.023961,3.1093299,-0.0164453,-2.89417 +0.034768999,0.33893201,-0.12810799,0.81850201 +-0.72283202,2.3557899,-0.19632199,-3.06112 +-0.40732601,1.87883,-0.049124599,2.70333 +0.264038,-2.7743499,-0.0234752,-2.0377901 +0.033686198,-1.76227,-0.060484201,2.4627399 +-0.0018308799,2.8896401,-0.048015598,2.7844501 +-0.31756899,2.7188399,-0.024270101,-1.1274101 +-0.048520099,0.61934298,-0.099366702,0.48865101 +0.317866,0.73212498,-0.117744,1.93883 +-0.248027,-0.71846998,-0.071269304,3.00509 +-0.31620699,0.50357902,-0.040829699,-0.40006801 +-0.050360899,-2.7421999,-0.066569902,-0.28638601 +0.50247699,-0.227365,-0.028544201,-1.80497 +0.123471,2.6647501,-0.083893098,2.58183 +-0.47823799,1.32629,-0.119697,-0.30224699 +0.404596,2.80756,-0.0041473401,-0.33823499 +-0.46565399,-2.1603301,-0.076480597,0.61875701 +-0.204303,-2.15557,-0.210054,0.18302999 +0.065452702,-0.91395098,-0.151375,-0.363695 +0.33978301,-1.06286,-0.029234599,2.40538 +-0.080509201,-1.40453,-0.0121723,2.84465 +0.38338801,-0.54339498,-0.053077299,-2.2920301 +0.34439299,0.147441,-0.0045463601,3.0574999 +-0.11997,-1.9233201,-0.0309557,-1.08612 +0.71297199,-2.9102099,-0.176687,0.203393 +-0.30089799,-1.5170701,-0.00808156,-0.90819198 +-0.0069559598,2.77284,-0.043050099,0.407242 +-0.38669699,-3.0745499,-0.028305501,0.76600701 +0.078437097,2.19134,-0.0414855,2.8984699 +0.075571701,1.4386801,-0.0131528,1.0535001 +-0.27065599,1.56713,-0.0061097099,1.6348701 +0.25592899,2.0950201,-0.0038520801,1.0093499 +-0.72218001,-0.37932199,-0.156014,2.94291 +0.174329,-2.7599199,-0.030460799,2.4400799 +-0.90679502,1.14047,-0.060133401,2.69104 +-0.190679,1.8396699,-0.110222,2.138 +-0.22644,1.9858299,-0.065786399,2.9260099 +-0.236065,-3.0188,-0.058715101,-0.46461701 +0.625135,2.0345399,-0.112706,-0.73812801 +-0.126029,-1.26807,-0.042297799,-1.2072001 +-0.045088898,2.81847,-0.30794999,-1.63624 +-0.054634798,-0.213798,-0.052076101,-1.3734 +0.61755502,-0.33408901,-0.0257458,2.35637 +0.212561,0.67741197,-0.082826599,2.9098001 +0.25823301,2.68907,-0.041563101,-0.021406399 +-0.103727,-2.39306,-0.0209659,1.27215 +-0.65442097,-1.71085,-0.232342,2.57478 +0.202134,-2.85217,-0.052433401,-0.68711501 +-0.25892001,-0.78062803,-0.041643899,-0.928276 +0.111148,2.6807699,-0.165859,-0.92532998 +0.035955399,0.226565,-0.12894601,-2.2121799 +0.35330999,0.53695601,-0.0096253101,1.45996 +-0.152354,-2.7669799,-0.0304593,0.25176299 +-0.7177,-0.21688899,-0.055100299,-0.069022797 +0.56797397,-1.52878,-0.0156474,1.2069 +0.116332,-0.203096,-0.083619498,-2.96315 +0.42450899,-0.546323,-0.0907894,2.47526 +0.19156601,-2.3536601,-0.087168902,3.01719 +0.22577301,0.68271703,-0.0179442,0.171893 +-0.59247202,-1.27959,-0.039914299,2.3432901 +-0.24263801,1.01557,-0.073377602,0.52391303 +-0.0205786,-0.48770601,-0.029041201,-3.1038401 +-0.42320299,-2.9071,-0.0156136,-0.131979 +-0.277266,0.11807,-0.099819601,-0.186663 +-0.70570701,-1.3945301,-0.061297599,-0.38715899 +-0.049348101,1.32419,-0.0051111202,-2.59517 +0.35693699,1.7405699,-0.34752601,1.10347 +-0.20901801,2.99281,-0.128819,1.6821899 +-0.51082098,1.69015,-0.102772,-1.18451 +-0.601349,0.439771,-0.0078881904,-1.0273 +0.58720398,3.13502,-0.121217,1.49547 +-0.19055501,-1.44165,-0.0133417,-0.95721799 +-0.73793101,-1.78201,-0.0077236402,-0.59530199 +-0.604545,-0.321417,-0.0086900396,-1.8038501 +-0.73273802,-0.67016,-0.071857601,0.34296599 +0.102625,1.27548,-0.065060399,-1.05926 +-0.872612,-2.9398899,-0.0040250299,-1.7887501 +-0.047738001,2.3610599,-0.13065401,1.40479 +-0.12981801,-0.53233498,-0.0191529,2.4865 +0.68215501,0.106828,-0.0319882,-1.25012 +0.631742,1.39767,-0.0569834,-2.40307 +-0.471412,-0.20858499,-0.016156901,-1.5861501 +-0.489187,2.2725301,-0.064660102,-2.6955199 +-0.032563102,-1.49218,-0.207298,1.15582 +-0.76318502,2.26759,-0.076336503,2.93837 +0.741822,-0.88059002,-0.16344699,-0.50064301 +-0.94191098,-0.56988299,-0.40160799,3.12854 +0.119226,-0.224902,-0.117187,0.13359 +0.43747699,-0.54647899,-0.0092284903,2.2551701 +0.29133299,-0.57030499,-0.058090799,0.55695301 +-0.60851997,-1.14782,-0.134353,0.93612897 +0.0166873,0.32650101,-0.059785299,-0.0085521704 +-0.30796501,-2.94399,-0.112858,2.90395 +0.19977599,1.79662,-0.12418,-0.20085201 +0.497621,-1.16409,-0.0122917,1.17811 +-0.274629,-0.086198397,-0.15122201,1.89518 +0.52491403,-2.10149,-0.156068,0.63985503 +0.12903801,-0.66462702,-0.0381498,0.28456801 +-0.25357199,-1.60829,-0.028018299,-2.7957201 +-0.253874,-2.3056901,-0.0184293,-1.08169 +0.094135702,-0.44507799,-0.138336,0.77719802 +0.29638699,1.55362,-0.00383607,1.32871 +0.066264898,0.85816503,-0.060368299,-0.231655 +0.47295201,1.97218,-0.159879,1.95383 +0.307338,-0.56676298,-0.032621302,0.94014102 +0.088297002,-0.49109599,-0.0608918,-2.55196 +0.277679,0.97192901,-0.031659201,-0.91242802 +0.89127201,2.08373,-0.083905101,3.1301401 +0.175869,-2.57324,-0.0066330899,0.27086699 +-0.45725599,1.11263,-0.090696402,1.36575 +0.101548,-2.43838,-0.0146192,0.91111702 +0.55875802,-0.41046399,-0.073037699,1.1285501 +0.116012,0.44838101,-0.049947102,0.57055199 +-0.90371197,-1.7172,-0.0196473,-0.23993801 +0.42883801,-0.97527498,-0.031973701,-2.1187899 +0.15136699,0.578269,-0.063673697,2.5316999 +-0.477496,-0.188923,-0.281872,-1.41017 +-0.050253,2.9161,-0.032426901,2.84376 +-0.29936299,0.71914297,-0.061967,-0.78620398 +0.126168,2.12129,-0.050613001,3.0222199 +0.22228999,1.73499,-0.100056,-0.047143001 +0.88072002,-1.15042,-0.080950297,-0.114409 +-0.39787701,-1.20781,-0.086857699,-2.51068 +-0.456599,-1.12459,-0.080511101,1.26026 +0.11811,1.25482,-0.00460253,0.554169 +-0.0101126,-0.169092,-0.027663801,2.30393 +-0.240004,-0.55812502,-0.053268701,-1.25896 +-0.165691,0.77661598,-0.147835,-0.14601301 +-0.23280799,-2.61922,-0.061574701,-1.41739 +0.26334,-0.99426001,-0.0089512598,2.71611 +-0.298498,2.0760901,-0.17757601,2.1887901 +0.276564,3.0778899,-0.066341497,1.68748 +0.67369699,0.97255498,-0.036551099,-0.149599 +0.069107398,2.3494101,-0.13722201,0.48303801 +-0.45061499,-0.429564,-0.044486899,-0.58115798 +-0.040051099,-2.0854399,-0.140191,-2.94279 +-0.074413799,-1.8606,-0.064082302,-0.97368097 +0.13583399,1.28479,-0.28160399,-2.9735601 +-0.115341,1.22604,-0.117637,-0.27611399 +-0.69670397,0.43745601,-0.019157499,-0.50746799 +0.31146401,-1.5386699,-0.00295921,-0.55222702 +0.57520503,-1.5247101,-0.0194233,-0.25073799 +-0.305852,-0.185654,-0.24144,0.998362 +-0.225991,0.335971,-0.110684,-2.5030301 +0.27020901,-1.90131,-0.28305399,-1.92623 +-0.47543699,0.58025402,-0.039264798,-0.0744939 +0.787202,1.6743701,-0.080096602,3.0111001 +0.28843901,-2.62363,-0.047067001,-0.299119 +-0.0119779,1.56481,-0.24809299,-1.67469 +0.034456301,-0.446464,-0.241164,-2.8841801 +-0.56986302,1.33924,-0.0558713,1.03256 +0.391179,0.031890199,-0.166234,1.28032 +-0.373202,-0.089708202,-0.120646,-2.85551 +-0.180484,2.69786,-0.181935,0.33728799 +-0.26857099,2.1512799,-0.131108,0.83368897 +-0.340433,2.93625,-0.12662099,-0.58254999 +-0.43071601,-1.38096,-0.107589,1.04039 +-0.28652099,2.8706801,-0.042699501,0.481812 +0.39103401,2.0757301,-0.077268101,-1.46613 +-0.521384,2.3996699,-0.042258799,2.92308 +0.071488202,-0.46758801,-0.067046903,-2.8617599 +-0.189107,1.4184999,-0.0486903,2.9981201 +0.39108601,-1.7068,-0.120093,2.9365599 +-0.280132,2.0300701,-0.13158999,1.96066 +0.31026,1.20594,-0.081898697,2.5409701 +0.53833199,0.171387,-0.0052260002,1.47103 +-0.52915102,2.46349,-0.25473601,-0.437345 +0.021138299,1.21264,-0.028743001,-2.8468599 +-0.0220071,1.8634599,-0.0128194,-0.74343002 +0.70444798,-2.25295,-0.0547073,3.11237 +-0.44431201,-2.8576701,-0.087108701,-0.97698897 +0.49926901,1.99795,-0.090877399,-2.83711 +-0.39772999,0.50377703,-0.027481399,2.1310799 +-0.72438598,2.3429201,-0.070904799,0.69084197 +-0.57937098,1.8077199,-0.130808,-2.2750299 +-0.137328,1.3651201,-0.026745999,-2.2423899 +0.62947601,-1.94604,-0.255981,2.27525 +0.22235,2.71702,-0.14741699,0.59542602 +-0.0248028,-2.3608999,-0.12631901,-2.9073901 +-0.39474899,0.74919897,-0.0043894998,0.0097243199 +0.242726,-1.04383,-0.064418003,-1.53777 +0.44098499,1.20594,-0.043737698,3.11694 +0.18334199,1.60421,-0.24316201,-0.088784598 +-0.37518099,1.11198,-0.0021278099,-2.7948101 +-0.170725,-0.51468402,-0.096611701,2.92083 +0.157932,0.25732499,-0.13394199,-3.076 +-0.12940601,-3.09884,-0.12923101,2.27862 +0.49586701,0.518942,-0.057764199,2.7029099 +0.44842499,1.10288,-0.097059898,-2.6082301 +0.85785902,-2.9492199,-0.0108692,-0.73871702 +-0.33190101,-2.4477501,-0.17784201,2.6617999 +0.174969,-2.0455799,-0.075022399,0.29521 +-0.62472302,-0.93066603,-0.407444,2.5897801 +-0.242257,-1.33121,-0.021752199,-2.22295 +-0.352364,-2.2439101,-0.112463,0.55441898 +-0.29228899,3.1140299,-0.34861299,-0.59462303 +-0.075831503,-0.114338,-0.13781001,-2.54458 +-0.347628,-1.26942,-0.14654399,3.08392 +0.35411,-3.03913,-0.0293661,-2.5895801 +-0.158223,-2.7134399,-0.30054101,-2.0253899 +0.55655402,0.326184,-0.062717699,0.66501302 +-0.22406501,0.831792,-0.0439003,-2.63696 +0.36929899,-2.1895101,-0.040797301,2.63343 +-0.022637,-2.1544499,-0.065593697,3.09197 +-0.045167401,-2.95068,-0.43444899,-0.060927302 +0.19994199,2.7360201,-0.055214699,2.7377999 +-0.203788,-2.33356,-0.0181778,-0.34443799 +-0.164894,-2.20208,-0.028766399,1.18045 +-0.40707701,-0.14863101,-0.0080942297,1.88327 +0.098259501,-0.88269401,-0.0149841,-2.95069 +-0.56697202,0.46980399,-0.0059834602,0.39403701 +0.931117,0.68773299,-0.089334801,-0.146782 +-0.48669899,1.80186,-0.219699,-1.67487 +0.32203001,1.35505,-0.052136801,-2.37795 +-0.58930802,2.87023,-0.0297851,0.72135299 +-0.401391,2.59899,-0.19627599,-2.85743 +-0.35333699,3.1175399,-0.035030901,2.9387 +0.0197991,0.51211399,-0.0256992,1.81051 +-0.368718,-1.37836,-0.066512004,-1.0290101 +0.37103,-0.28239501,-0.016458901,-0.459133 +-0.38304999,1.80852,-0.0271575,-1.46587 +-0.54318303,0.277172,-0.121063,2.1293499 +0.682105,-2.8452201,-0.0112878,-2.4977901 +-0.187106,-0.124694,-0.067201696,1.34918 +0.77066398,2.92974,-0.13459399,1.38477 +0.208134,1.73607,-0.0349828,2.3117599 +0.25871301,-1.60567,-0.011236,0.78969598 +-0.709598,2.7260201,-0.00378204,-0.198428 +0.254226,-1.7099299,-0.047537401,-3.0557301 +0.080114797,2.24384,-0.031690098,-2.89991 +-0.22197001,-0.25103199,-0.106635,-0.66938901 +-0.20140401,-2.79794,-0.107223,0.31775099 +0.637339,1.98224,-0.189147,0.120679 +-0.112024,-2.66573,-0.096391998,-2.26914 +0.31867599,0.86166,-0.0076324502,2.61711 +0.77088797,-2.46172,-0.0063987402,-0.44905701 +-0.375119,2.7153201,-0.155387,-0.48111799 +-0.0029372501,-0.34771299,-0.115835,-2.7539501 +0.35650101,-2.73823,-0.0121671,-0.58666998 +0.116937,-2.08813,-0.0579108,0.39607701 +0.74586499,2.5585599,-0.044630799,-1.00515 +0.47255301,3.05193,-0.119002,-0.84583801 +-0.087673701,3.03227,-0.105135,2.6326599 +-0.140504,1.60739,-0.090903498,0.54960698 +-0.038948201,0.69219601,-0.27188101,-3.12413 +-0.39282799,3.0989699,-0.042427398,2.3283999 +0.062571898,-0.85472399,-0.072740301,-2.2409101 +-0.060827199,2.22416,-0.054899901,-2.8424301 +-0.52476102,-1.4854,-0.28707999,-2.4036 +-0.47615701,-2.4719601,-0.085686304,-2.0771401 +-0.21029399,-0.0134952,-0.0422405,-2.6243999 +-0.095236398,1.8680201,-0.046772499,1.18542 +0.26126599,2.4626501,-0.15313201,-0.68964201 +0.74376798,1.3002501,-0.0153482,0.54717702 +0.470557,0.241078,-0.0596723,0.88766801 +-0.45073399,1.84741,-0.122377,-2.1812301 +0.0148247,0.500256,-0.13965,0.56531501 +-0.086115599,3.08816,-0.096567899,0.58074802 +-0.76549202,1.60736,-0.108117,2.1189201 +0.0077467998,3.01282,-0.00414983,2.58231 +0.55584902,2.6360199,-0.068139002,-2.8876901 +0.65244901,-0.252947,-0.058224998,0.68856299 +-0.23360001,2.4584601,-0.020159001,1.26166 +-0.121049,1.25344,-0.091937199,2.7632401 +0.555309,-1.77267,-0.0252862,0.077278599 +-0.15503301,0.102998,-0.34718299,-0.37838 +0.356482,-3.03215,-0.109155,0.077240303 +-0.33411101,2.1564701,-0.078882903,-1.58126 +0.173619,1.14864,-0.028227501,0.041336801 +-0.069513597,-1.08504,-0.067669198,1.25516 +-0.84508198,1.07121,-0.00316573,-2.30285 +0.65675902,-1.62446,-0.0021875601,0.179285 +0.37141499,0.110769,-0.063653499,3.1175101 +0.59704697,-0.211978,-0.034039501,-2.8246 +0.25922799,2.9577999,-0.0854261,-0.0937142 +-0.64797699,2.03302,-0.072801404,-0.177001 +0.108045,-1.20849,-0.042737499,-2.3149199 +-0.43924901,0.040747602,-0.0117396,-1.25675 +-0.75556201,2.35606,-0.033359099,2.88027 +-0.64610201,1.77411,-0.016700899,-3.01597 +0.290342,1.01158,-0.12985,1.27826 +-0.86018199,1.8858,-0.097822703,-0.53202599 +0.34619799,1.43827,-0.0797747,-1.03283 +0.153852,-1.65584,-0.0067522898,0.57519698 +-0.178487,0.86848903,-0.090834297,-0.399663 +-0.119749,2.0446899,-0.044046801,-1.28723 +0.152659,-2.62606,-0.0175386,-0.67457902 +-0.70692903,-3.0039699,-0.083572596,2.8891001 +-0.60979497,-0.31746301,-0.33298001,-0.27780199 +-0.27736399,0.72214901,-0.057940599,-0.84988898 +0.058947202,-2.40692,-0.039269201,-1.52626 +0.91425502,1.88184,-0.041197799,-2.7374899 +0.148488,-2.6008101,-0.0373067,1.88969 +-0.28180599,0.47731701,-0.0107521,-0.86517203 +-0.73929697,-1.23265,-0.00125948,0.99230999 +0.0191915,-1.14266,-0.089832,1.32313 +-0.662319,-2.0487101,-0.087889001,2.84057 +0.762528,0.77880001,-0.036559202,-0.49641299 +0.39797899,1.63188,-0.095485799,0.34753901 +-0.43525299,-0.619003,-0.039020099,1.70117 +0.0926864,-0.30500501,-0.11495,3.0711801 +-0.030642999,-2.5850899,-0.075655103,0.72976798 +-0.39424601,-2.9173801,-0.0203094,2.5106299 +0.26539201,0.41203499,-0.0102536,-1.92151 +0.80498499,-0.30916101,-0.082287401,2.9224801 +0.11437,-0.57934701,-0.33711201,-0.718889 +-0.379058,2.3174,-0.208878,-2.89098 +-0.35591999,1.08201,-0.0091383504,-0.59405702 +-0.085370101,-2.9144199,-0.027392499,-0.89428902 +-0.15926699,0.64956099,-0.015979299,2.2488899 +-0.57244498,2.3404,-0.0206805,3.0690601 +-0.49368101,-1.80935,-0.174151,-0.219115 +0.33508399,0.92998701,-0.114219,3.1256499 +0.30203801,-1.8860101,-0.0127153,0.026044499 +0.61514997,0.208413,-0.123985,0.59735298 +0.71210098,3.0579,-0.125788,-0.26486999 +0.240068,-0.35763499,-0.00750507,2.3467901 +0.33485201,2.20542,-0.00468334,-0.255808 +0.213709,1.49599,-0.076696999,-0.40838799 +-0.043941401,-1.48219,-0.0135179,1.12439 +0.51498199,-2.35496,-0.0194086,-2.1905899 +0.400709,1.77941,-0.029661801,-3.0208099 +-0.15736599,1.60361,-0.029231999,0.57631499 +0.85473901,-3.0179801,-0.095774099,-2.68785 +0.53497201,1.58679,-0.0035758801,-3.0583401 +-0.210648,-0.62893301,-0.084119901,-1.53737 +-0.228066,2.8150401,-0.047578201,-2.7142 +0.427295,-1.6515599,-0.0352736,0.067881301 +0.232472,-2.6559601,-0.0022296801,-0.84046698 +0.55223298,2.0685,-0.0485228,2.8334999 +-0.46016401,1.44807,-0.00095310301,-2.2311299 +-0.25332901,-2.0483501,-0.078321896,1.70796 +-0.12975501,2.6438899,-0.175281,-0.817936 +0.326765,0.35300201,-0.19043,-1.63415 +0.31920499,2.21524,-0.18849,2.6296501 +0.48700199,-0.98495698,-0.059929501,-1.2804 +-0.00066857599,1.42307,-0.035897899,-0.14792401 +-0.28418201,-1.48993,-0.0305374,-1.00611 +0.159282,-0.309605,-0.045486599,-0.275956 +-0.37284601,2.3954599,-0.048872199,2.47101 +-0.37823001,2.0661099,-0.045049202,-0.37295899 +-0.084126003,2.43871,-0.031273901,1.5802 +-0.82472301,-2.04439,-0.0023143999,-2.3469901 +0.227107,0.93928897,-0.075086303,0.87341899 +-0.45279199,-0.49036801,-0.108497,2.8452499 +-0.092932299,0.68385899,-0.047733299,-2.8185101 +0.14879,0.15957101,-0.076015197,1.76852 +0.30086499,2.3201699,-0.177191,-2.9317501 +0.85447502,1.23581,-0.077893801,-0.95592499 +-0.301332,0.43916601,-0.220018,3.09326 +0.69743502,-1.78071,-0.22963899,-0.29303199 +0.112322,-0.423278,-0.00526697,1.43179 +0.032804798,0.51113403,-0.093401797,-0.35213 +0.20042101,-0.770266,-0.055309702,1.9152 +-0.193222,0.80044299,-0.0045481198,1.02729 +0.23303901,-2.81217,-0.0526863,-1.94788 +0.23450901,3.08288,-0.109374,-2.5846601 +-0.186571,2.54421,-0.106219,-2.3483801 +-0.0084325597,1.74726,-0.0038757499,-1.48809 +-0.302163,0.141045,-0.17614301,0.086701602 +-0.10341,1.77325,-0.12379,-0.35192201 +0.16500001,1.18233,-0.104877,0.48093101 +0.565301,-1.62014,-0.0929849,-2.3341601 +0.036079001,0.47333801,-0.10341,0.26911101 +0.438963,1.3974,-0.043761399,-0.083580203 +0.76591998,0.116616,-0.120409,-1.64932 +-0.376311,2.6277101,-0.0431551,-1.9560601 +-0.822326,-0.66064101,-0.026410401,-2.4544201 +0.137025,-0.365224,-0.097215302,-0.70802301 +-0.46944001,-2.8262601,-0.0051834998,1.58262 +0.17292701,-0.596048,-0.032127898,1.05906 +-0.113482,2.3504,-0.13892899,2.6135099 +-0.060332201,1.39845,-0.033258099,0.48401701 +0.188559,0.16899499,-0.067465298,-0.0218837 +-0.096118301,-1.98282,-0.024670601,-2.66295 +-0.365165,2.57234,-0.0811662,1.35981 +0.33685201,-0.76847398,-0.0134358,-0.86571699 +-0.392952,-2.9379699,-0.122879,-2.9916401 +-0.56855702,0.90247297,-0.0154766,-2.5763299 +-0.77132601,-2.2794399,-0.063891098,0.57053101 +0.36202601,-2.2076099,-0.0209831,2.56268 +0.26886201,1.10479,-0.124676,1.0985301 +-0.666444,-0.68489701,-0.042922501,-0.88247198 +-0.33632001,0.14137299,-0.112121,-0.138056 +0.70558798,-0.104501,-0.0389161,-2.46281 +0.53718001,0.94094098,-0.100524,-1.9981101 +0.61151499,2.67187,-0.0252214,-1.07048 +0.350907,-1.07718,-0.060829502,-1.854 +-0.052126799,-1.0839601,-0.093350701,2.7364299 +-0.69244897,1.88784,-0.124907,-0.046004299 +0.189775,-0.73066097,-0.089819103,-2.08918 +-0.50909901,2.2362199,-0.084820502,-1.83744 +-0.73760998,-2.9374399,-0.089667797,-0.56169403 +0.507581,0.62570798,-0.099252202,1.25247 +-0.22484501,-1.5545599,-0.170166,2.86274 +0.57235903,-2.80197,-0.116676,-2.4151399 +-0.32167801,1.56062,-0.094971798,-2.48963 +0.85851598,-1.06379,-0.049634598,-1.70336 +-0.597193,2.0313399,-0.054214198,0.118596 +-0.64091802,-0.78421402,-0.0217574,3.02616 +0.18115699,0.689417,-0.0345596,0.59710699 +0.265504,3.1405499,-0.12374,1.22253 +0.097721703,2.0456901,-0.048927799,-3.0045199 +0.912148,-3.0970199,-0.034490999,0.080860503 +-0.091812402,-2.3176899,-0.14238299,1.40315 +0.78886002,0.51274198,-0.0091240499,-2.5929699 +-0.79066199,0.037398402,-0.0049153701,-1.01898 +-0.37261501,2.3252399,-0.063614704,0.30154401 +-0.46153399,0.56127602,-0.11704,-2.74085 +0.67784601,-3.0897501,-0.0112613,0.084840298 +0.64518201,1.87508,-0.136997,0.69187498 +0.74189699,-0.704817,-0.0830319,0.26499 +0.29917499,-3.0443101,-0.0250316,-2.1099999 +0.037856899,1.41061,-0.028664799,3.0650699 +0.18895601,1.43533,-0.097304098,-0.55495799 +0.230849,-0.63087702,-0.0895826,-1.05706 +-0.41390699,-1.42781,-0.073054403,-0.43005499 +0.63005298,0.691634,-0.016670801,-2.68343 +0.31706399,-2.45522,-0.083870098,-0.70122701 +-0.30377001,1.28407,-0.0102949,2.6858599 +0.50823599,-0.97310698,-0.114676,-2.87988 +-0.0242224,-0.54830098,-0.061161999,0.45493701 +-0.44683,-0.359799,-0.192532,-1.63787 +0.56421101,-0.79821301,-0.0556641,3.0438499 +0.097015403,0.225081,-0.222535,0.280368 +0.42985401,1.42721,-0.0181468,2.66255 +-0.56858897,-1.65633,-0.016044,1.11991 +-0.41129401,-1.53821,-0.036969502,-0.44391 +0.33344701,0.79597503,-0.0186,1.4077801 +-0.035367001,0.958278,-0.32939601,0.98252499 +-0.30835801,-0.82438803,-0.030309999,-0.087890603 +-0.38931501,0.528341,-0.0075971801,-1.69979 +-0.123507,0.244679,-0.0270776,0.79146397 +-0.361635,3.1123099,-0.183706,1.77802 +-0.64882499,1.23706,-0.050543901,-1.0005701 +-0.57153797,0.34683299,-0.0245694,0.57846898 +0.699462,0.98285002,-0.081718199,2.3350999 +0.61736602,-0.69529301,-0.077964999,-2.56025 +0.34278601,1.6820199,-0.0076428698,-0.175366 +-0.36078399,-2.0071001,-0.176434,3.0032899 +-0.084804296,-1.21939,-0.054682601,-2.87344 +-0.71736997,-2.85711,-0.325331,-1.14596 +-0.53447402,2.7472301,-0.0800201,-0.903907 +-0.34455901,-1.66748,-0.020085599,2.9879301 +-0.68339598,-1.62599,-0.0820053,0.41477799 +0.885741,-1.48286,-0.0310532,-0.39462399 +-0.14282,1.5497299,-0.0099490201,0.620318 +-0.064522497,2.3623099,-0.00699405,1.2123801 +0.784073,2.71469,-0.220676,-0.0183142 +0.161926,2.02912,-0.0310829,0.56735802 +-0.0302683,-2.5066099,-0.0180657,-0.76048303 +-0.66572899,-1.62518,-0.0060226899,1.2316 +-0.68547899,1.99489,-0.17738201,0.37746799 +0.35617,0.88225901,-0.13125999,-2.8117199 +0.311542,-2.37216,-0.25616401,2.3424599 +0.111642,-3.0012,-0.0098386798,-2.6526501 +0.032519698,-0.61653203,-0.077168196,0.51971602 +0.25689799,1.79474,-0.185129,-1.18549 +-0.32895201,-2.7765901,-0.022360099,-0.90552503 +0.16979299,1.62708,-0.0136711,-0.39129999 +0.88290501,1.33798,-0.123336,2.44607 +0.33695301,2.9530599,-0.31370199,-2.6289699 +-0.393774,2.8353601,-0.030188801,-0.682033 +-0.847929,-0.90414798,-0.00276056,-2.2904401 +0.73892599,2.97574,-0.161236,-0.50999099 +0.319038,-1.89566,-0.29193199,1.8431799 +-0.71953398,2.6903701,-0.016179699,-3.0731299 +-0.50286901,2.6057,-0.084310196,1.52544 +0.36964399,-2.96592,-0.117263,-2.6907001 +-0.278725,-0.83947402,-0.040723301,-0.35964301 +-0.70709097,2.76774,-0.054365899,-2.2955 +0.41471401,-0.225704,-0.0151399,-2.6928 +-0.46297801,0.178656,-0.123163,-2.31306 +0.059460901,2.7571101,-0.067437202,0.57961202 +-0.294045,0.534042,-0.144765,-0.34261101 +-0.47388801,-0.56747699,-0.208746,-0.66242099 +-0.14405499,2.31565,-0.029534901,2.5861599 +-0.00552605,0.76166803,-0.052808098,-0.50399297 +0.00762395,0.353497,-0.084871799,-0.41088 +-0.70584202,2.20718,-0.107057,-2.4017899 +-0.29037499,-0.210967,-0.088323399,2.54372 +-0.487308,-2.8472199,-0.057449602,2.79322 +0.46384501,-2.5989201,-0.00142678,-2.7107601 +0.512999,-0.73533899,-0.070812501,-0.681876 +0.57431298,-2.25365,-0.00680207,-0.0211129 +-0.091367804,-1.6238199,-0.042310301,-0.480708 +0.159245,1.9387,-0.126926,-2.71122 +-0.522852,1.06494,-0.123787,-0.0524843 +0.39226699,-0.77013499,-0.0228309,3.04423 +0.115977,1.9221801,-0.0102162,-2.9899199 +-0.13705499,0.55302298,-0.0024796899,-0.101463 +0.84339899,2.1273,-0.117853,-1.93592 +0.197822,-0.053310301,-0.33322799,-1.31293 +0.64053601,3.0240099,-0.0155082,-0.84017301 +0.365502,2.86466,-0.021193201,1.38603 +0.13431101,0.60774899,-0.035930298,0.56757802 +-0.124847,3.0095401,-0.0068870801,-0.23289999 +-0.78440601,2.0283101,-0.14119799,-0.43194801 +0.0294073,-2.99879,-0.168173,-0.65048498 +0.57213199,-3.11151,-0.31947401,1.9572901 +0.78450102,2.91868,-0.15112901,1.26113 +0.143906,1.0302,-0.0026551799,-2.6933601 +0.20732901,1.48132,-0.0145761,2.2318499 +0.072034404,1.89132,-0.113675,3.01824 +-0.019371601,0.026798399,-0.0132725,0.58298498 +0.034577001,2.7061701,-0.142361,-2.01911 +-0.115309,-3.0673499,-0.032536201,-0.19558001 +0.048416998,2.02583,-0.171535,2.1807899 +0.32939601,2.9014299,-0.092355996,-0.32392001 +-0.741175,1.09435,-0.071091302,2.1825199 +-0.057424702,-1.37525,-0.0305006,-1.00017 +0.58941799,-2.2137799,-0.0582151,0.43232399 +0.23622701,2.32336,-0.228302,-0.52652502 +-0.089226298,-2.0683,-0.091705397,-3.1354401 +0.23258901,2.73751,-0.0643107,2.43892 +-0.246696,2.41679,-0.103526,2.6740301 +-0.018523701,-2.1029699,-0.024968101,2.3556001 +0.216757,0.094740599,-0.034084901,2.2513399 +-0.69391698,3.09409,-0.077886999,-0.053751599 +-0.32872999,2.04812,-0.246961,-2.22405 +-0.33829799,-1.7766,-0.036536001,0.27164 +0.24514,-0.71178102,-0.17377,-0.156381 +0.51251298,0.029984901,-0.023647601,-2.6759601 +0.13002899,-1.05909,-0.107655,-0.78038299 +-0.38795701,-1.2247699,-0.043770202,-2.3372099 +-0.31557301,0.97714102,-0.051490899,-2.32758 +-0.222785,-1.8323801,-0.229994,2.4050701 +-0.30472299,-0.31500199,-0.110177,2.56601 +0.213164,-2.9175501,-0.039274499,-1.73869 +0.251937,-0.679901,-0.0342899,0.370141 +-0.267508,-1.66011,-0.128516,-2.4016199 +0.954041,0.98212498,-0.034173399,-0.85063601 +0.319601,-1.63248,-0.13757899,-2.05847 +-0.13530201,2.0925901,-0.37149701,2.60566 +-0.387759,-3.0922501,-0.0354314,-2.7562599 +-0.073927604,0.364209,-0.062096499,-1.11299 +0.200651,1.97005,-0.085364997,-0.037976801 +-0.55396998,-1.14371,-0.040603999,-2.99754 +-0.59036702,-2.6398799,-0.0273293,-2.4331999 +0.62040597,1.33284,-0.18152501,-2.9647901 +0.453159,0.0105158,-0.152052,-0.033431601 +-0.134776,0.0158436,-0.152022,3.0611999 +0.66970497,-0.325688,-0.011445,2.6985099 +0.76608199,-0.75931501,-0.074547797,0.00073833601 +-0.32284099,0.47593299,-0.264799,-2.75125 +-0.086508699,-2.4177799,-0.117384,-1.13231 +0.32575399,0.41258699,-0.042860501,-2.07493 +0.076076999,0.997006,-0.0073018302,-2.87692 +-0.25196001,0.136024,-0.068673402,-0.85777199 +0.60673302,1.23611,-0.0142505,0.26183 +0.76759201,-1.1196899,-0.028627601,1.76459 +0.404809,3.11919,-0.0068389601,-0.27511701 +-0.56570399,-1.2824399,-0.038027,-0.62042701 +0.25420099,2.0668399,-0.0161542,0.191071 +0.335022,0.447642,-0.12559199,0.48126099 +-0.57451099,0.34833401,-0.012753,0.79518503 +-0.88551098,-2.28847,-0.0181085,-0.73900402 +-0.27250499,2.5246301,-0.045500401,2.6006601 +0.52168602,-2.9405899,-0.0036593699,-0.14274301 +-0.22438,-0.21354701,-0.093640096,3.0750201 +-0.52922201,1.46269,-0.0038386399,-2.30094 +-0.18607201,-1.6148601,-0.0267902,-2.7981601 +0.34320799,0.806624,-0.141868,-3.0599599 +-0.47950599,-2.4537001,-0.0310336,2.3575499 +-0.198211,-0.185471,-0.0033962401,1.69243 +-0.33967701,-1.1247,-0.18047699,0.58981502 +-0.40986401,1.4446,-0.035845,-3.0901201 +-0.232408,-2.2135601,-0.0124997,3.0164499 +-0.738841,2.5727401,-0.0133492,-0.40077999 +-0.27001801,2.7010801,-0.0492853,2.56703 +-0.041770101,-0.89815301,-0.0276425,0.25780001 +-0.046701401,-2.6624,-0.061154898,-2.8958099 +0.194261,1.6403,-0.0336533,-1.60181 +-0.222086,-0.97409898,-0.0468917,2.8513601 +-0.45527801,2.7144899,-0.111801,-1.9284199 +-0.19250301,0.71559399,-0.048872799,0.249282 +-0.26351699,1.14056,-0.13373201,-2.3232 +0.096089803,0.209142,-0.103426,-2.63695 +0.46423,2.5155001,-0.11123,2.8783 +-0.62023503,0.64578998,-0.078852497,0.190954 +0.66269398,1.9213901,-0.155123,1.9649 +0.57871801,2.93608,-0.110179,0.103987 +0.0058749202,-1.16949,-0.033071801,-0.81815201 +-0.47103801,0.161937,-0.0475423,-2.54387 +-0.27044401,2.6447501,-0.073134802,1.25938 +-0.20349599,-0.63859099,-0.319105,-1.58069 +-0.759556,-2.86186,-0.27734199,1.55892 +-0.261464,0.51143903,-0.32569301,-2.59688 +0.15265299,-2.1166501,-0.19434901,2.9295101 +0.036568802,2.1278999,-0.0753657,-1.46324 +0.57661003,-0.57858801,-0.069552101,-0.38422501 +-0.79193902,-0.55683702,-0.111046,0.91316903 +0.166734,-1.3704,-0.023572201,-1.2342401 +0.176377,-1.13111,-0.084942102,-2.1886401 +0.57385999,-0.96696699,-0.0543877,0.66203201 +-0.82391602,-0.39830801,-0.023414699,0.81316298 +-0.247998,-0.92624903,-0.14269599,-0.32305899 +-0.054360699,0.67507398,-0.031517901,-1.14061 +-0.186846,2.1006999,-0.045215499,1.40731 +0.63392901,3.11656,-0.071621403,2.8368599 +-0.30232599,1.21078,-0.0925823,2.4369299 +0.0143094,-2.88011,-0.015693299,-0.65449202 +-0.64515799,-2.6091001,-0.486211,-2.8564601 +0.50217199,-1.20296,-0.0142196,0.85293901 +0.36542401,1.71767,-0.10304,3.00862 +-0.48475799,0.96238899,-0.048139401,1.36994 +-0.103855,-0.188852,-0.021966999,0.45439899 +0.21224999,-2.9753301,-0.079945602,2.49703 +-0.0194645,1.21935,-0.066943802,-2.54968 +-0.232769,-2.8919699,-0.0577209,-0.100088 +0.111258,-0.044737101,-0.035091698,0.123115 +0.043736201,-1.64645,-0.17886201,0.654764 +0.130349,1.22063,-0.0144175,-0.888897 +-0.222828,-2.1154699,-0.065316103,0.46769601 +0.696845,-1.8063999,-0.13577799,0.65826899 +-0.290315,2.9920001,-0.143288,-3.06884 +0.317343,-2.93626,-0.0112332,-0.0205011 +-0.34934601,0.38563401,-0.087532297,-1.92985 +-0.65277803,2.13518,-0.13236,2.47352 +0.31663099,-2.5429399,-0.0160437,3.14077 +0.78037697,0.72198802,-0.058124501,0.025845701 +0.029402699,0.63616198,-0.0020583901,-0.170357 +-0.28371599,2.2046199,-0.0143847,3.03124 +-0.19629499,-2.2962899,-0.0159804,-0.72812498 +-0.119005,-0.857535,-0.0100229,-2.9073801 +0.48986799,-1.40534,-0.149065,-3.01457 +-0.42245799,0.00204902,-0.156066,0.41429499 +-0.40258399,-2.4312,-0.0150756,-0.298843 +0.67087901,-0.384157,-0.0236843,1.95388 +0.11713,-2.1066301,-0.14359801,3.10518 +0.0387838,0.83574098,-0.0152785,1.4925801 +-0.180691,-2.8826699,-0.0446385,2.4600799 +-0.399483,1.76366,-0.0890719,-1.54434 +0.0291829,0.020852,-0.047811199,2.7282901 +0.083580799,-0.34370601,-0.155044,-2.8062301 +0.582533,-0.18202899,-0.047615901,0.26486799 +0.026270499,3.0676899,-0.124276,2.14714 +-0.85693401,2.6853099,-0.0199457,-1.10504 +0.150051,-0.34971499,-0.0104888,2.36958 +-0.683806,-2.0522299,-0.099051498,-2.3958001 +0.68774199,0.189533,-0.060583699,0.165906 +-0.0025523801,2.72155,-0.18778101,0.43464199 +0.406317,0.77195603,-0.030475101,-1.73746 +-0.82692701,-1.6483099,-0.0020276001,-2.04632 +0.57961601,-3.1294999,-0.017142501,-0.38720399 +-0.269757,1.82337,-0.0117826,-2.89433 +0.231447,-1.7925,-0.0361256,2.7117801 +-0.00661908,0.100396,-0.081263103,1.33214 +0.200946,2.1026101,-0.27856201,2.3373599 +0.51770198,0.40616,-0.17085101,-2.6584899 +-0.085338898,-1.8401,-0.126002,1.9957401 +0.29578301,-2.19946,-0.077165902,2.83992 +-0.52059799,-0.747805,-0.0048585101,0.915268 +0.411304,0.59774101,-0.190548,-2.8162601 +-0.058486901,-0.51685297,-0.18086,2.89974 +0.42731801,2.8779199,-0.049669001,2.9728301 +-0.210923,0.065655097,-0.0480415,-2.6293001 +0.40755799,-2.7728801,-0.088874102,0.79536998 +-0.198245,-2.1342299,-0.185056,-0.94898802 +0.138647,1.11278,-0.139742,-1.36491 +-0.78426802,-1.91936,-0.0053609302,-2.88744 +0.46941,0.76206601,-0.0033388799,-0.58881903 +0.189968,-1.8733799,-0.100428,2.2236199 +0.0300631,2.22662,-0.047198899,-1.11365 +-0.228783,-0.95377499,-0.021972699,0.33768699 +-0.55631298,-2.8450301,-0.105734,0.616992 +0.175221,-2.4133101,-0.108262,-0.073330499 +-0.338891,-2.91278,-0.019529,-1.1294301 +-0.063872904,0.71393102,-0.110521,0.81660998 +-0.29261199,0.48544899,-0.389025,3.1047001 +0.53256798,-1.42591,-0.034453802,-2.94819 +-0.59121799,-0.176522,-0.0261232,1.04864 +-0.402614,2.8160601,-0.060856301,-0.87945199 +-0.26872599,2.65535,-0.032510798,-2.8202901 +0.357364,-1.02492,-0.096801303,1.84394 +-0.77463597,2.8742399,-0.0241955,2.9832101 +0.54271501,1.68288,-0.0118392,-2.0424099 +-0.082645498,2.7495501,-0.056090899,0.028642099 +0.042861,1.6577899,-0.27496299,2.0225599 +0.69561601,-2.1900201,-0.038690299,3.0536499 +0.44484201,-2.18191,-0.148239,2.81938 +-0.84995699,0.207211,-0.0047764801,0.50731802 +-0.105614,-3.1216199,-0.093863897,-2.6787801 +0.524306,-0.75045401,-0.094112404,0.074952297 +0.50435501,1.90273,-0.133965,-2.35502 +-0.162677,2.2676499,-0.067769296,1.98074 +0.73499602,-1.8708,-0.0903126,0.0228983 +0.28713199,-2.1926899,-0.0137356,1.4005899 +0.35032201,-2.1463201,-0.176474,-3.07253 +0.228461,2.7190299,-0.0126725,2.9893501 +0.37558001,0.84283298,-0.065834299,-0.72053099 +0.23628899,-0.56541198,-0.0058327499,-2.7427101 +0.68863899,-2.20681,-0.070629299,2.98016 +0.153137,1.78222,-0.48811901,-2.53929 +0.63836598,-0.109266,-0.109862,-2.6133101 +0.26660499,0.88283199,-0.048599299,-2.9164 +0.43952501,2.9642999,-0.085773602,-0.99305499 +0.0514731,0.72651601,-0.039837301,-2.37012 +0.225757,1.46041,-0.026513999,-2.8784699 +0.097632602,-0.63371402,-0.184275,-3.1013999 +-0.0135763,-2.4888,-0.111214,-1.20014 +-0.65292102,0.913131,-0.074009098,-1.93577 +-0.52914798,2.9186599,-0.129765,-2.4065599 +0.20814,-1.1455801,-0.108866,-0.69727898 +0.081667498,3.0597701,-0.0196169,2.06286 +-0.079319201,-2.0625801,-0.0719513,-0.83283103 +0.25801399,-0.56521797,-0.116449,-0.0577977 +0.83890498,0.194166,-0.033606999,0.51506698 +-0.0051668999,-0.87240899,-0.110871,0.97705001 +-0.031078599,-1.69283,-0.083811499,-3.1339099 +-0.191302,-2.3620501,-0.085936897,-3.00753 +-0.79107302,2.5355401,-0.057423402,-0.43591401 +0.47470301,-0.123047,-0.090834498,-0.45114201 +-0.52495801,-1.18557,-0.18413299,0.57485998 +0.435673,-2.2286201,-0.204184,1.89712 +-0.80205101,2.25509,-0.073865801,2.40517 +0.357483,-1.40666,-0.0161833,-2.3613999 +0.252525,-0.93480402,-0.0264205,1.49951 +0.051046502,-1.52858,-0.019534601,0.220497 +-0.35232499,2.45123,-0.036127001,2.7964101 +0.55675298,-1.0776401,-0.0192625,1.8474801 +0.33134899,2.06355,-0.120896,-3.03211 +-0.65697598,2.5747499,-0.047056701,0.057098199 +0.123583,-2.73943,-0.0183754,-3.0843501 +0.18585999,1.2479,-0.0144557,0.91645199 +-0.340276,2.2807701,-0.061434198,0.207552 +0.322061,-2.69612,-0.070136398,2.5929599 +0.098837703,2.8513701,-0.093231499,-2.79023 +0.54948199,2.7571599,-0.067192197,0.53958601 +-0.153575,-0.52027202,-0.057042301,0.42325601 +-0.050797701,2.26472,-0.0507911,-0.71136397 +0.52709103,1.55453,-0.031712402,2.7625899 +0.29203799,-1.31358,-0.0085647199,1.11081 +0.174356,-1.41259,-0.097889103,-2.3235199 +0.077039398,-1.75111,-0.10722,-2.14991 +0.028430199,-1.3094,-0.0062390999,0.70924503 +-0.55312997,-2.8460701,-0.020381199,-2.1312799 +0.34196901,-2.95836,-0.031645201,-2.1101601 +0.55341601,-1.18029,-0.21833199,0.59336102 +-0.36055499,-1.86176,-0.166732,-0.25942001 +-0.071846999,2.2002101,-0.0176029,-2.25754 +-0.038385902,-1.88451,-0.0091609797,-2.5803499 +0.122455,-2.1779301,-0.013924,-0.75657201 +-0.85892701,-2.19332,-0.065632097,-2.42097 +0.38102201,-2.10236,-0.0508167,0.727817 +-0.26024801,-2.1409199,-0.15166201,0.83569998 +-0.35295001,-2.6124799,-0.034359001,-0.34510899 +-0.219308,0.85133702,-0.023023801,-0.30501601 +-0.838184,2.0342,-0.0250492,2.95732 +-0.269005,-1.17696,-0.21417201,2.9280601 +-0.79131103,-2.28438,-0.0347781,2.3564799 +-0.33027801,0.184918,-0.094870202,2.7305501 +-0.50461602,-0.77766001,-0.12148,3.0456901 +0.33755201,-0.064952902,-0.011104,-3.13585 +0.0473685,0.180005,-0.120365,-2.2469201 +0.0203331,0.72305501,-0.24259,1.82804 +0.16182999,-2.70151,-0.0248936,-0.25863299 +0.153403,-2.6935501,-0.055030901,-2.19943 +0.108907,0.478706,-0.042100102,-0.65622598 +0.14815401,-1.11542,-0.0146999,2.36076 +0.429268,0.59153998,-0.180792,-0.58778203 +0.26460499,2.73807,-0.085212603,2.9386401 +-0.67799002,-2.21228,-0.049269501,1.13756 +-0.029945699,-2.54901,-0.030363601,1.25011 +0.000861204,2.3171101,-0.034572199,-0.27244601 +0.62269002,1.77113,-0.0058017499,2.4912601 +0.738325,1.70862,-0.18756101,-2.3882501 +0.14679,-0.400819,-0.275262,-2.5397301 +0.40799701,-0.23048501,-0.049671698,0.50759798 +-0.64237899,1.40697,-0.22940999,-1.6681 +0.444215,-0.44271699,-0.148829,2.4040401 +0.095482498,-0.073376402,-0.100854,-0.100973 +0.142978,1.61777,-0.071972102,2.0544901 +-0.48706299,1.0462,-0.039453499,-2.8182399 +-0.132264,2.22346,-0.0276668,2.5316999 +-0.27341399,-1.5468,-0.0054142498,-2.6954 +0.30691499,1.30257,-0.045918401,-0.263551 +-0.25587001,0.20571101,-0.074107602,-2.22666 +-0.92983401,1.7905101,-0.0230365,-0.45592701 +-0.059069,1.08436,-0.026717599,0.014906 +0.186171,-1.8689899,-0.123831,-2.0790601 +-0.33330601,2.9907,-0.0478976,0.57166803 +0.23736,1.98264,-0.091088504,-2.8361101 +-0.037342701,-1.27237,-0.032420501,1.3318501 +-0.60186201,1.66649,-0.0450131,2.5397799 +0.656569,-0.547943,-0.17340299,0.44938099 +-0.496281,0.68677801,-0.193968,2.7583699 +0.42262399,2.8850999,-0.0790134,0.084221803 +-0.096112803,0.861821,-0.039269902,-0.0121541 +-0.56716198,-1.57981,-0.078899696,0.196234 +-0.43282899,1.35978,-0.0110976,-0.255034 +-0.21585301,-1.4114799,-0.051443901,1.86696 +0.0194028,2.67452,-0.0308557,0.97432601 +-0.31625101,0.83795702,-0.095017098,2.3271799 +0.70787197,1.7044801,-0.0045551299,2.18523 +-0.28667101,-0.138722,-0.059617199,-1.03528 +-0.51284897,1.01503,-0.0482907,0.98422903 +-0.0530544,3.03864,-0.121316,2.2746401 +0.92081499,0.49121201,-0.088435598,-1.05431 +0.41594201,-2.49599,-0.098233402,2.2987199 +0.018222,2.55546,-0.096697301,-2.8863201 +0.15398,0.240345,-0.038975801,-2.2237501 +-0.36108199,1.1318901,-0.20049199,0.048255298 +0.84555697,-2.51232,-0.064147301,1.59428 +-0.75560898,2.3471601,-0.095599703,-1.8421201 +0.80986202,0.91808403,-0.099131703,0.073459402 +-0.34946099,-1.0836101,-0.037467699,0.092653602 +0.0140295,-2.85885,-0.027509199,-2.58599 +-0.494573,0.022700001,-0.115319,-1.14451 +0.122101,-1.4981101,-0.016452201,-2.52545 +-0.45154601,-1.9667701,-0.0820271,-2.74611 +-0.073765598,1.41528,-0.042906102,-2.53319 +-0.125248,-1.44367,-0.120706,-1.21742 +0.078030497,1.11766,-0.030374,-0.150601 +0.92402899,0.48714501,-0.071309201,2.6471701 +0.64893001,0.67921197,-0.117369,2.5337601 +0.45405099,-2.9096701,-0.028749401,1.80799 +-0.70928502,-2.94314,-0.093595497,-2.58091 +0.12543599,-0.733675,-0.073068,2.82338 +-0.587385,1.58515,-0.00250998,-2.81057 +0.528929,1.7512,-0.0175857,0.345909 +-0.73425102,1.0628099,-0.043759301,0.42716399 +0.76785302,2.9300699,-0.070790797,1.64022 +-0.39370501,2.27174,-0.056853801,-2.1454599 +0.457257,-1.95645,-0.083034702,0.078317501 +0.231905,-2.65732,-0.040608902,-1.14437 +0.060508899,0.80107898,-0.184441,1.02285 +-0.71655202,2.78741,-0.065794103,-1.0870399 +-0.36697701,1.35206,-0.191845,1.59665 +0.52096301,-2.4874799,-0.131522,-0.086839303 +0.87853402,-2.67817,-0.0091427201,-1.45472 +-0.41659999,-2.4173501,-0.121947,-1.77899 +0.79835898,-1.2684799,-0.0120798,-2.08481 +0.492576,2.8162601,-0.0096566398,2.8108301 +0.2599,2.4881201,-0.0301487,2.13711 +0.29237199,0.69774199,-0.067698799,-3.0234699 +0.20824701,2.34705,-0.0045162798,-0.60264498 +0.36112699,1.33521,-0.026448799,2.00281 +-0.71348298,2.67663,-0.0156541,2.4003201 +0.51695299,-0.917027,-0.112614,2.3436201 +-0.69223201,0.76609302,-0.115033,-1.7776901 +-0.16358601,-0.0476849,-0.041887499,-2.97649 +0.036642,-1.7579401,-0.0865523,0.27191901 +0.58502901,-0.591043,-0.0074160499,-2.68753 +-0.196997,0.45047101,-0.101319,1.99467 +-0.41881499,1.5974,-0.00386747,2.5580001 +-0.69082099,-1.48103,-0.064564399,-2.4861801 +0.724338,2.94139,-0.0332109,-2.9256401 +0.38552001,-0.73141903,-0.031006301,2.5241499 +-0.47573301,2.1246901,-0.0917174,2.55726 +-0.063137397,-0.194346,-0.115098,0.0997447 +0.25265399,-1.32007,-0.031464599,-1.47182 +0.68951201,3.0781801,-0.337488,2.73348 +0.431243,0.630898,-0.101459,1.93839 +-0.31095201,2.26581,-0.0103646,-1.92091 +-0.072201997,-1.08338,-0.181365,2.35167 +0.058673698,2.6590099,-0.097540401,-1.1927 +-0.73879403,-1.38854,-0.30380601,2.19823 +-0.57258803,-2.0408001,-0.0023435,2.5130799 +-0.77604002,-2.8652599,-0.31482601,2.2349999 +-0.22111,0.93886399,-0.305457,-2.7454901 +0.90866101,0.398545,-0.196482,1.42644 +0.50347501,2.2330401,-0.107325,2.9175999 +0.455309,-0.0049694199,-0.19756401,1.19163 +-0.31057599,1.49111,-0.079263002,2.1955099 +0.7209,2.0151401,-0.0788377,1.9087501 +-0.82947898,2.85092,-0.0123651,1.17283 +-0.015822999,1.97983,-0.0476714,-0.16925199 +-0.021689599,0.48619401,-0.116618,-2.13499 +-0.46259001,-1.89663,-0.014963,2.48592 +-0.24543101,-0.353414,-0.028009901,3.04368 +-0.25509399,0.97230202,-0.0048060399,1.31073 +0.38401601,-2.08424,-0.0076998798,1.68314 +0.203032,-0.94541299,-0.031188199,-0.73052597 +0.221586,-0.25863999,-0.19944,-2.6323199 +0.227613,-3.03776,-0.161322,0.98638803 +0.064465702,2.59501,-0.057500999,-1.0501 +-0.56239802,0.75915098,-0.150867,-1.63662 +0.56654298,-0.323484,-0.0421938,2.78092 +-0.11492,1.47785,-0.056161702,-0.35351801 +0.092130899,-1.8897099,-0.0240271,-2.7848599 +0.629251,-1.20244,-0.197468,2.7906401 +-0.452876,-0.74100298,-0.0188992,-2.9954901 +0.145593,1.39249,-0.050051302,3.00035 +-0.79159999,1.4349999,-0.0099743903,2.11324 +0.27230799,1.20284,-0.114601,2.36006 +-0.169649,0.11679,-0.0070263701,1.88984 +-0.0318732,1.06137,-0.117067,-0.37089199 +-0.46420899,0.40296799,-0.054800201,1.13396 +-0.51113898,1.42812,-0.0089035798,0.75471902 +0.096473798,-0.98765302,-0.064002402,2.2200501 +-0.132181,1.77183,-0.069199704,-0.933869 +0.34338501,2.05633,-0.19101299,-0.157563 +0.27120501,0.56638002,-0.044903599,-0.73378801 +-0.381145,0.34146699,-0.15544599,3.0271399 +-0.823376,-2.9728701,-0.0568179,1.64727 +0.000144998,1.30542,-0.0220348,1.60497 +0.61495602,3.00775,-0.112986,-0.63588899 +0.56358999,-2.4851899,-0.059229899,-2.2383001 +-0.12890799,0.82910502,-0.082113497,1.8354599 +-0.81590199,-1.55923,-0.204227,0.68932402 +0.25707299,1.46498,-0.119342,-0.88922602 +0.38416499,-2.9552901,-0.092124097,-2.9472499 +0.930812,0.30101201,-0.098632403,0.463651 +0.0172075,2.7248499,-0.132534,-0.79138601 +-0.053189602,-2.4016199,-0.124844,-1.90582 +0.15555599,-1.57595,-0.10515,1.0425299 +0.29296601,-2.9500799,-0.0107302,2.1547 +0.53398597,-0.063684501,-0.223153,0.46043 +-0.617176,-0.99962097,-0.107179,1.12903 +-0.072421402,-0.99646503,-0.0067950501,-1.59974 +0.563021,-0.30875501,-0.0064058299,0.00159841 +-0.751158,1.92316,-0.066282399,2.64096 +0.282116,-1.8781101,-0.024934599,0.114024 +0.64416498,1.43068,-0.0069453702,1.06091 +-0.381657,-1.65121,-0.38533401,-0.29188901 +-0.341694,-1.30191,-0.113339,1.97284 +0.383221,-1.56332,-0.00708583,-3.10954 +0.059882399,2.0257399,-0.0569712,-1.262 +0.41229099,2.5788901,-0.035854898,-2.2720201 +0.73681802,-2.3823299,-0.24183901,-0.94131303 +0.20121001,-1.3494,-0.212071,3.06599 +0.48898399,-2.29515,-0.12277,1.00264 +-0.75020099,1.6543,-0.0088233901,-0.21506201 +0.68899298,-0.50945699,-0.082112901,-0.35102901 +-0.85619402,0.202234,-0.00533076,1.20926 +0.207929,-2.7206099,-0.092880599,-2.1415601 +-0.112061,2.6820099,-0.202033,-3.0235801 +-0.421572,-1.88287,-0.0140068,-0.88362002 +0.714167,2.0875599,-0.32282799,-2.6612 +0.14768399,-1.35606,-0.066178203,2.5027599 +0.51898098,0.32095101,-0.082002901,2.6905601 +0.48066899,2.1439099,-0.0323353,0.0285217 +-0.013266,-0.268392,-0.032417402,-1.9321001 +-0.60842401,2.7137401,-0.038227201,2.42943 +-0.405875,-0.67386103,-0.045051798,-0.56930399 +0.21216699,-3.01513,-0.010199,0.38834101 +0.36063001,-1.34991,-0.285932,-1.71164 +-0.47997299,-1.39368,-0.138041,0.55017298 +0.158934,-2.4330001,-0.0125809,-0.24563999 +-0.424283,-2.32148,-0.0220608,-0.346609 +-0.0026852801,1.91255,-0.036878798,-0.140275 +0.65313101,-1.95775,-0.074884303,0.050166301 +-0.41895601,0.55168903,-0.027353801,-0.56867403 +0.27628401,1.24006,-0.0109306,0.61932099 +-0.103967,-1.17329,-0.0803698,-2.4412799 +0.147212,-0.91252899,-0.179629,-1.77013 +-0.56130898,2.7346399,-0.0212317,-2.6621301 +-0.498887,-0.62769401,-0.021156499,-2.7488201 +-0.42540601,1.35855,-0.0149784,-0.30649999 +0.79433298,-2.45456,-0.046572499,0.57260197 +-0.244653,-1.3587199,-0.104884,-1.75018 +0.59505898,0.80624598,-0.0105307,2.68325 +-0.32890201,2.37076,-0.108177,0.51912099 +-0.082604103,-2.7035501,-0.062116802,-2.41991 +-0.042899199,-2.29862,-0.215819,-0.536102 +0.9526,1.47909,-0.067993499,2.4712901 +-0.87905699,1.26545,-0.0086892601,-2.67768 +-0.307506,0.45052701,-0.15483201,-1.63264 +0.24184,3.0216601,-0.130557,0.110447 +0.50626999,1.10971,-0.035583202,0.79320502 +0.43562901,-2.48926,-0.157828,1.1134 +0.156578,-1.65528,-0.12725499,1.55933 +0.55872399,3.02476,-0.065139003,-2.70263 +-0.41311899,1.90918,-0.147918,-0.113725 +0.77708,-1.44323,-0.2163,-0.79753298 +0.77778703,2.18609,-0.0199265,-0.579813 +-0.20463599,-0.80998802,-0.058055699,-0.56968498 +-0.19850001,-0.76576799,-0.029203201,-2.0894401 +-0.76527399,-1.4853801,-0.0037988599,2.223 +-0.58838302,2.9872,-0.057183102,1.78738 +-0.46238801,-1.2614,-0.022820501,-0.055439699 +-0.77681202,1.99239,-0.00117184,2.0336499 +0.37637001,0.63973099,-0.15578599,-0.0077806502 +-0.73987401,-3.0323999,-0.053555898,0.93014002 +-0.65011001,-1.74707,-0.12642799,2.3239999 +-0.0222499,-0.82545602,-0.117814,0.414756 +-0.24019,2.84203,-0.00079912,0.74250001 +-0.45313501,-1.45969,-0.109153,-2.3959 +0.50488198,-1.2771,-0.065724701,0.20600399 +0.044638898,-0.162155,-0.067759499,2.5709801 +0.66651899,-1.29194,-0.032698601,-2.61343 +0.337672,2.04035,-0.061553899,-2.8875401 +0.0079143802,-0.553738,-0.0155884,0.94144797 +0.696778,0.167446,-0.022843501,2.3710401 +-0.71092403,-2.0099199,-0.00651814,0.80312598 +-0.131837,1.55893,-0.062358402,0.71493697 +-0.27460301,1.08263,-0.103489,1.39141 +0.0554615,2.5179701,-0.0416945,2.2497301 +-0.258908,3.0134799,-0.0304475,1.11483 +-0.059204999,-1.91723,-0.00321119,2.1657701 +-0.186528,-2.51952,-0.0081712101,-2.4154201 +-0.608697,1.4132,-0.1259,2.1531799 +-0.00126433,-0.81859201,-0.166678,0.088482298 +0.69511598,-0.65109497,-0.00104156,1.5763 +0.192307,0.86504197,-0.089863203,-2.23803 +-0.0928661,3.04796,-0.090103403,-2.11427 +0.71191901,1.00691,-0.054615598,-2.9863501 +-0.170984,2.4730501,-0.119451,0.61751997 +0.59878701,-1.1814899,-0.00373911,0.54241502 +-0.049311601,-2.4310701,-0.069891103,-0.66504401 +-0.60525799,-2.2737601,-0.0226338,-2.90031 +-0.32400399,-0.0302941,-0.00171415,-2.1260099 +0.45377901,-2.7969,-0.269012,-2.25666 +0.74950898,-3.08319,-0.0231176,-2.5455599 +0.53618997,-3.13341,-0.0181603,0.41997901 +0.025710801,2.03866,-0.045404401,-0.86575103 +0.59366798,-2.9995899,-0.35178,-2.5638399 +0.23323201,-2.65658,-0.18360899,-2.96086 +-0.315081,-1.29791,-0.026551699,2.44417 +0.602889,2.14835,-0.121891,-2.2408099 +-0.055295199,-1.2465,-0.00964275,2.5110099 +-0.069191501,-2.4182701,-0.0317082,2.8417399 +-0.35693699,0.113539,-0.222259,-2.81534 +0.84118402,1.82075,-0.12103,-0.97604197 +-0.38659301,-1.3347,-0.021419801,-1.88982 +-0.0126077,-1.6577899,-0.209117,-2.2774301 +-0.82683998,0.55014002,-0.175662,2.20981 +-0.31334999,2.5915699,-0.0150145,-2.6375301 +-0.52175403,-1.1992,-0.0504972,0.190559 +0.44655901,0.61509103,-0.028612001,-1.7174799 +-0.284933,-1.06074,-0.061710499,-0.48215899 +-0.0142979,-3.0678,-0.052422699,-2.4260099 +-0.94697398,-0.0495781,-0.041799001,0.38216001 +-0.44139799,0.211698,-0.105548,-3.0810201 +0.12147,1.76231,-0.090046197,-0.0095640998 +-0.28145099,-1.8752199,-0.071164601,1.4249001 +0.94156498,-2.89977,-0.0389507,0.83584499 +0.368774,-2.6313,-0.104668,0.081877202 +0.387283,-1.18453,-0.212871,0.37493101 +-0.52274102,3.0850899,-0.11389,2.2456801 +-0.65669,1.80323,-0.106467,0.16239899 +-0.70329601,-0.23138499,-0.081597902,2.7695701 +-0.85179198,-1.47679,-0.032236099,-2.1382999 +0.32303101,-0.45394099,-0.0119617,-0.31027699 +-0.186589,2.3410499,-0.035461001,-1.69803 +-0.0863159,2.04948,-0.069591202,1.9623899 +-0.63611799,1.47802,-0.0136375,-0.39650699 +-0.886374,-0.48427299,-0.026634101,-2.08742 +0.27777001,-1.21007,-0.0220627,0.68260401 +-0.54841799,-0.87129301,-0.092278399,2.9402299 +-0.742679,-1.58691,-0.086454198,-0.60091299 +-0.81843102,-0.65900898,-0.10005,-1.41751 +0.358069,-0.320003,-0.0139198,-0.800291 +-0.95212197,-1.34321,-0.086513497,-3.0097699 +0.129006,0.73062497,-0.061585899,-0.12815601 +-0.13426299,3.1408801,-0.068386897,2.62287 +0.27757299,1.52503,-0.0265241,-0.48139301 +0.769072,-2.0671301,-0.032094099,2.67644 +-0.103164,1.7761199,-0.079572797,2.0593901 +0.030064501,2.9149401,-0.0131999,-2.1466501 +0.17298099,-1.25583,-0.13415299,2.54825 +-0.30323899,0.964656,-0.040418699,1.9985 +0.37492201,1.88498,-0.0155206,-0.688761 +0.78849602,-2.35514,-0.057470199,-0.0330735 +-0.44229299,-1.85917,-0.051834099,-0.33978701 +0.383055,-2.4003601,-0.13301399,-2.8563199 +0.0890579,2.7216699,-0.045754701,-0.121082 +0.54775703,-1.88106,-0.0014340701,-2.7911301 +-0.84936601,-0.29984,-0.027238799,-2.65435 +-0.44072899,1.05214,-0.18278401,-2.85287 +0.50380999,-0.253966,-0.079296298,-0.25460199 +-0.524113,1.96138,-0.143098,2.26458 +-0.27172399,0.21463899,-0.122282,0.403007 +0.34031999,3.0337,-0.178239,2.4690499 +-0.196374,1.0162801,-0.036995001,0.66012299 +-0.72724801,-1.51401,-0.0345487,2.38796 diff --git a/tests/data/pyfit/rho/flat_data.csv b/tests/data/pyfit/rho/flat_data.csv new file mode 100644 index 00000000..57e8b68f --- /dev/null +++ b/tests/data/pyfit/rho/flat_data.csv @@ -0,0 +1,2500 @@ +ctheta,phi,tM,psi +0.82843602,-2.0290599,-1.52119,-2.4907601 +0.68983197,-1.37301,-0.0079075303,-0.17027999 +0.74687898,0.323093,-0.045326099,-1.52201 +-0.489528,1.8686,-0.0165796,-0.94242001 +-0.517488,-0.0045061801,-0.70858902,1.37927 +-0.218126,2.24052,-0.0398723,0.361532 +-0.39163601,-0.87766403,-0.117453,2.10815 +0.923935,-1.9638799,-0.0264499,2.6077099 +0.34006,2.99525,-0.084425502,-2.7353201 +-0.081775397,1.04243,-0.085151903,-0.498631 +-0.61269301,1.625,-0.0594327,-1.20056 +-0.479498,1.5943,-0.232077,1.10151 +0.14970499,-1.20258,-0.291491,-0.138116 +-0.85828102,1.90895,-0.48219299,-1.48146 +0.76188499,-1.83451,-0.133994,-1.87558 +0.368058,2.3147399,-0.0066950801,1.3160599 +0.97862202,0.168312,-0.22525001,-3.00126 +-0.88709801,-0.156036,-0.00309042,-0.035703599 +-0.66752601,2.42277,-0.134988,0.29384199 +0.086265698,-2.12901,-0.33881599,1.42967 +-0.200103,1.0785,-0.0021625101,1.60119 +0.20925599,-2.29234,-0.021633601,-2.6809199 +-0.758632,2.0834501,-0.150694,-2.99859 +0.345146,-2.6042199,-0.0131897,-0.58135498 +-0.46747801,0.58474398,-0.062320702,-1.19235 +-0.128043,2.6124001,-0.029650901,-1.51974 +0.83669198,0.49106199,-0.373546,1.6583 +0.084627897,-1.8206199,-0.22193401,-0.37336999 +-0.058212101,3.1341901,-0.051339,-0.108169 +-0.82911801,-2.71787,-0.042258698,1.40874 +-0.82141799,0.58393401,-0.13947999,2.2893701 +-0.0286544,-1.89884,-0.15073401,2.01507 +-0.186024,-2.0523901,-0.225538,2.6178801 +0.92690498,0.56933802,-0.163892,1.18915 +-0.602916,-2.2683599,-0.170937,-2.0648301 +0.117583,-1.8321,-0.159786,1.87317 +0.648417,-2.54161,-0.40853199,-1.29533 +-0.73366302,-1.0455101,-0.347563,1.7216901 +0.39531299,2.29439,-0.34037501,-1.7646101 +0.85970199,3.00598,-0.067188703,-2.44117 +-0.57121599,2.9488101,-0.17843001,-2.8444099 +-0.91343802,-0.30635399,-0.240741,-3.1368699 +0.82501298,1.03643,-0.0322088,-1.9564199 +-0.065588303,-2.90838,-0.0220422,-2.9762499 +-0.43096101,-2.8995199,-0.037489999,3.1245899 +0.72606701,3.02584,-0.394391,-1.2345001 +0.075411901,2.1601601,-0.15467501,-1.49427 +0.113949,0.94738698,-0.0053513502,1.1372401 +-0.37213701,-1.82561,-0.248803,1.73086 +-0.45494401,2.37341,-0.25282401,-1.43501 +-0.39621201,1.3313299,-0.21356399,-1.50166 +-0.33850399,2.6549599,-0.0031908299,-1.9572001 +-0.14536799,-1.45328,-0.058298599,2.54404 +-0.080330297,-0.210572,-0.0177917,-2.7151401 +-0.89193702,-2.8283701,-0.00628709,-2.14326 +0.412846,-0.239485,-0.26287699,-2.1838601 +-0.81662703,0.27601999,-0.00867307,-0.228736 +-0.992558,-0.37224099,-0.23158801,1.81091 +0.95986301,2.4214101,-0.229606,-2.58722 +0.80026799,-1.1953501,-0.54487997,-0.883847 +-0.29803801,-0.70624,-0.257328,3.08675 +-0.79393601,0.71052498,-0.082652502,1.50089 +-0.90569001,-3.12866,-0.124602,0.47066399 +0.45488301,2.7838399,-0.0544497,2.17874 +-0.32771799,-2.0187099,-0.141046,1.96271 +-0.494674,1.577,-0.52511603,-0.79746097 +0.892084,-0.058113702,-0.0220329,-0.98154497 +0.079876199,-1.29296,-0.88871801,-1.86663 +0.75786102,2.93103,-0.075170301,0.92147201 +-0.462396,-0.88036102,-0.0085196001,2.04931 +-0.98148298,0.78260201,-0.122974,0.821473 +0.73285002,2.37293,-0.364952,0.147313 +-0.929138,-2.03929,-0.366146,0.43379 +-0.61176902,0.28191799,-0.10717,2.01632 +0.56519097,2.9918399,-0.23992699,0.468826 +0.59048897,0.86785001,-0.37961301,1.05127 +0.109687,-1.75067,-0.099880204,-0.55385298 +0.82859099,1.8866,-0.071826696,-2.43859 +-0.69800401,-0.163258,-0.41592899,-1.15976 +0.33191901,0.88219601,-0.036109399,-2.9228301 +0.39173701,0.88477701,-0.120858,2.64346 +-0.26192701,0.57046902,-0.060985301,-2.3445301 +-0.278954,1.74896,-0.41723999,-2.6850901 +-0.91263801,-2.5770099,-0.102805,1.7174799 +0.94069898,-0.54751199,-0.025542,3.0309501 +-0.248153,-2.1057401,-0.357135,3.1380501 +0.42211401,2.10811,-0.112027,-2.93893 +-0.82243103,2.1540201,-0.164083,-2.04127 +-0.93761498,2.3937199,-0.093873098,0.220057 +0.0623339,-2.80229,-0.076187,1.5581501 +-0.00053999602,0.33556801,-0.137297,0.338222 +0.91477001,2.3505399,-0.0552705,-2.6221399 +0.14539699,-0.138565,-0.066939101,-2.5120499 +0.281479,0.85296202,-0.055697899,-0.035050198 +0.57449698,0.323773,-0.22262099,3.10289 +0.67297798,-2.98089,-0.100951,2.9528601 +-0.0297892,-1.3475,-0.135382,0.86743802 +-0.42739001,0.49187601,-0.30121499,-0.94995099 +0.093300998,-0.54575801,-0.16746099,0.59375602 +-0.50242299,-2.0796199,-0.158446,1.8220299 +0.34028101,1.1215,-0.18703599,3.13973 +-0.26041499,-2.7597101,-0.083587699,2.9321001 +-0.98816502,0.74073499,-0.0053270999,0.210666 +-0.189367,0.31671101,-0.079234302,1.38644 +0.85433102,1.37226,-0.0314877,-3.0229299 +0.21487699,0.46320799,-0.087503202,1.01358 +0.099722199,1.97488,-0.13537601,1.4090101 +0.38091001,-2.1512401,-0.51065201,0.209392 +-0.41969499,2.599,-0.071369797,-0.087372102 +-0.95858598,2.6304801,-0.21324,-0.11484 +-0.69564497,-1.1795,-0.204919,2.03019 +0.75386697,0.90558797,-0.60165298,1.29224 +0.64184999,1.1403199,-0.038463201,-1.01692 +0.96545899,2.3722601,-0.485026,-2.4328201 +-0.56059998,-2.4902599,-0.239011,-2.2722001 +0.98356199,1.83132,-0.158687,2.2856901 +-0.34383401,-2.8491001,-0.250462,2.27335 +-0.97784102,-0.36356199,-0.303013,-1.2983201 +0.81139201,3.1013801,-0.201199,-1.08531 +0.96171802,-1.27566,-0.022535199,1.89109 +0.86015701,-0.51395601,-0.28912699,-3.1224501 +0.609761,2.01635,-0.149123,2.98821 +-0.055364601,0.0674062,-0.20246901,1.7922601 +0.28251699,0.652336,-0.14545,1.38862 +0.153162,2.8696101,-0.109939,-2.6780701 +0.047628101,-1.28295,-0.019624401,-1.07801 +-0.82631499,1.57271,-0.108593,0.31765699 +0.773233,-3.0155101,-0.0206149,-1.15441 +0.39584801,1.0121,-0.141265,1.53645 +0.079048596,2.01771,-0.50180399,3.0896101 +-0.24570601,2.5181899,-0.41199401,-2.1440899 +0.807347,2.3380499,-0.056233902,-2.9423101 +-0.456164,-0.292595,-0.21813101,1.8976099 +0.15439799,1.6086,-0.057939701,0.762003 +-0.69089699,-0.63861501,-0.0553931,1.06907 +-0.60949802,2.21123,-0.52877498,2.7121501 +-0.90431398,0.32259199,-0.052417699,3.0097201 +-0.47594199,-2.3243201,-0.229735,0.83604002 +-0.29219401,-1.92875,-0.188778,-1.68442 +0.122114,-2.08547,-0.043747399,0.193177 +0.0854408,2.5796499,-0.00308839,0.61235797 +-0.70835501,0.70165098,-0.0061375001,-2.6969199 +-0.442817,-1.08288,-0.235587,2.32447 +-0.84229898,0.42317501,-0.261751,1.19824 +0.27444899,2.6614599,-0.0289372,-2.9781001 +0.80024499,-3.11444,-0.0539461,1.21223 +0.50767797,-1.98366,-0.35389,-1.58287 +0.311086,-0.106071,-0.12850299,2.5387599 +-0.53197098,0.60347801,-0.204512,2.12991 +0.90935898,2.5815201,-0.195067,-2.4742801 +-0.680942,-0.861112,-0.025094699,2.96542 +0.33451799,-2.44557,-0.086146504,2.1028099 +0.27591699,-1.67085,-0.13626599,1.4662 +0.456514,1.66474,-0.314796,1.64992 +0.65730298,-2.59114,-0.0289611,1.14527 +-0.82546401,-1.97118,-0.72401202,3.0984399 +-0.77874398,2.68524,-0.23598,-0.98034602 +0.72474003,-0.305435,-0.129263,-1.3338799 +-0.94585901,1.20253,-0.221875,-0.39281201 +-0.80905801,-1.99791,-0.2511,0.48723701 +0.030707801,2.07757,-0.13616601,-1.98919 +0.48616999,-0.81261599,-0.32883599,0.247786 +0.16454101,2.1503501,-0.077478997,2.33408 +0.30967799,1.38731,-0.24835201,-2.9537001 +0.51752698,0.90581399,-0.073627703,1.38612 +-0.26831701,2.83374,-0.154608,1.92865 +-0.646927,-1.59474,-0.30564401,-0.392214 +0.19481599,-1.07795,-0.41134301,2.8454199 +0.42967001,-2.8882599,-0.49028599,-0.39218 +0.41072601,2.5378399,-0.504071,1.47326 +-0.71004099,3.09214,-0.154754,-2.3410699 +-0.51012802,1.1199,-0.22126,0.483275 +0.51342899,-0.15879001,-0.16026001,0.078389697 +0.45174,0.092398703,-0.105508,0.62286198 +0.925237,2.5146401,-0.727961,1.80281 +0.31084901,1.84922,-0.018578,-2.30825 +0.071979702,-0.62607402,-0.066854097,-0.16235299 +-0.771658,0.40930399,-0.60433799,-0.77876103 +0.0920204,-3.0583601,-0.088713698,1.27343 +0.14529701,-0.39616501,-0.106333,-1.84427 +0.91126603,0.074088097,-0.0264639,-0.47293001 +0.313503,2.47732,-0.065265402,2.80704 +0.12472,-0.52407998,-0.0619669,0.0065621301 +-0.27850699,3.0236599,-0.29017299,-2.37761 +0.155742,0.62430203,-0.15973599,-0.0070308801 +0.28114,-1.3655,-0.190317,-1.54027 +0.095270902,-0.42244801,-0.058347199,-2.6045899 +-0.0446054,2.7967401,-0.17121799,-0.387018 +0.78123701,3.13483,-0.477945,-2.3073399 +0.52205402,-1.32084,-0.034010299,-1.127 +0.217464,-2.8996501,-0.34723899,1.3631099 +-0.29513499,-1.02145,-0.20548201,-0.97189403 +0.87526202,1.45316,-0.67576098,-0.073235199 +0.41516599,2.6103599,-0.00510818,-2.9513199 +-0.919523,1.32844,-0.0045370902,-1.99656 +0.16378801,2.84584,-0.220412,-0.34328499 +-0.92274499,-0.106895,-0.0436408,-0.800286 +0.603297,0.319637,-0.0155436,0.311198 +-0.67407697,1.54035,-0.50380403,-2.0726099 +0.82064199,-0.955383,-0.51610601,2.4754701 +-0.0054480098,1.8135999,-0.039423302,0.53625399 +0.640728,0.242815,-0.0095645599,0.994367 +0.730865,0.44517699,-0.043007899,-0.126076 +0.22923499,-3.1104,-0.156726,2.1579299 +0.496786,1.2960401,-0.031806,-1.5707999 +-0.272176,2.73914,-0.22376999,-1.10756 +-0.14676,1.35639,-0.16136201,-0.188089 +-0.64296299,-0.43169901,-0.0134857,1.0181201 +-0.40502799,1.96628,-0.113308,-2.6284499 +0.71979302,2.87954,-0.25431699,-1.18758 +-0.98055601,1.42111,-0.091028199,-2.1421299 +0.094723202,-0.74347699,-0.37129501,0.96741998 +-0.077283204,1.77835,-0.0435565,1.51316 +0.190689,-2.5032599,-0.107889,0.37455699 +0.81558698,-0.36282,-0.231388,-1.75789 +0.88528103,-2.3762901,-0.0828133,-0.077233203 +0.84642899,2.4695499,-0.027533401,-1.44312 +0.89551598,-2.0799501,-0.042229801,1.92061 +-0.243876,-1.01475,-0.00240648,0.723575 +0.68416399,2.8475599,-0.15990099,2.3012199 +0.61805499,-0.29942599,-0.014519,0.45922899 +-0.184533,-1.41552,-0.099186398,-2.50647 +0.349585,-1.80857,-0.072224803,-2.6129899 +0.47005099,-2.2516601,-0.43188,2.97455 +0.26708201,0.302953,-0.70281398,2.7691901 +-0.590716,0.51035303,-0.053105202,0.27238801 +0.71337098,2.4233601,-0.41173199,-1.1195101 +-0.138257,0.87636501,-0.106974,1.39821 +-0.61611998,-2.0398099,-0.0852504,-2.68402 +-0.93861401,-0.28347901,-0.17321,2.83023 +-0.161566,1.78018,-0.106234,1.82155 +-0.64406103,-0.48439601,-0.22327,0.084720299 +-0.78842002,2.47506,-0.0075797699,1.20394 +-0.037514798,-1.9931099,-0.058201,1.6481 +0.63722003,-1.33751,-0.148849,-1.76853 +0.82251298,1.93973,-0.023210701,-2.42892 +-0.997742,2.4021699,-0.128475,3.06299 +-0.82127899,-2.50664,-0.044090498,1.05265 +0.75346601,1.35076,-0.25741899,-2.6901901 +0.90248901,1.97916,-0.094563499,-1.42194 +-0.90465897,-2.5516701,-0.102096,-2.57199 +-0.986121,-0.079242997,-0.13786601,0.060556401 +0.242452,2.05498,-0.45921999,-2.3578899 +0.87324399,2.9000001,-0.01029,1.3366899 +0.54905999,2.1979101,-0.153973,-0.18708301 +-0.102815,-2.5771101,-0.420524,-1.2469701 +-0.142241,2.2691801,-0.210145,-2.1498499 +-0.69709599,0.93851298,-0.113418,-1.5285701 +0.76789302,-2.2625101,-0.035383798,-2.1515501 +-0.79537302,-1.85671,-0.0647199,1.0735199 +-0.64096302,-2.5144401,-0.118807,0.230471 +-0.70541197,2.0194099,-0.212161,0.21041501 +0.92744499,1.41951,-0.091135502,0.21626601 +0.94164002,-2.8571999,-0.115281,2.1243701 +0.79018301,1.164,-0.0052683698,-2.3159299 +-0.318589,2.1087301,-0.094936296,1.8324 +0.85676599,-2.72245,-0.0142763,-1.25258 +-0.115442,-2.5881901,-0.22081199,-0.065601297 +0.57470298,0.97214502,-0.33732,-2.24225 +0.48399299,2.1418099,-0.10747,-0.99800301 +-0.86420399,-3.00683,-0.044652201,2.25402 +-0.881778,-1.52939,-0.230242,-0.87731397 +-0.84417498,-1.5038199,-0.487023,-2.9108 +-0.45659199,1.79766,-0.0339991,-1.46865 +-0.95560402,-2.53825,-0.31104699,1.69111 +-0.0507509,0.34977299,-0.065035,-0.37893799 +-0.62355697,2.5447099,-0.22903199,-2.46311 +-0.62913901,2.7051101,-0.28474501,0.32853699 +0.89142197,-0.77550799,-0.0131991,-0.92455697 +0.36731499,-0.83321297,-0.18060499,-0.75943297 +0.75055802,0.81240201,-0.17378099,1.14346 +-0.21565101,0.147503,-0.066876002,1.5948499 +0.095911399,-2.9194901,-0.0150224,-2.0502501 +0.70528799,0.284711,-0.137107,1.1441 +0.35330701,2.11202,-0.131069,2.0039899 +-0.248088,-2.1206601,-0.31374899,-0.43700299 +-0.63872403,-1.4706,-0.118274,-0.24461401 +-0.50538099,0.18947101,-0.034317199,2.9426601 +-0.68584597,-1.08527,-0.25610799,-2.0458901 +0.160414,-2.7014201,-0.205778,2.13135 +-0.39557299,-2.28949,-0.131623,3.08623 +0.033634599,0.219603,-0.332964,2.2786901 +0.29506499,0.439132,-0.070103198,-0.026979299 +-0.15240601,2.89797,-0.0142986,1.87494 +-0.93931597,0.036217999,-0.0845939,2.1520801 +0.57553601,0.43954399,-0.033889402,2.86816 +-0.97185898,-2.81214,-0.125834,1.26792 +0.179317,1.59399,-0.041446801,2.93696 +-0.169112,0.93141502,-0.0445319,-2.0186601 +0.86501998,-1.14509,-0.17369699,-2.52105 +-0.62871498,-1.31438,-0.13838901,-2.85762 +-0.57986701,0.93543202,-0.37547901,-0.0093112299 +-0.470588,-2.01736,-0.0139377,2.18522 +0.58475602,2.41098,-0.0108354,0.25011101 +0.174715,-2.87907,-0.038697999,0.69301701 +-0.88273698,2.96275,-0.48870999,-2.47299 +-0.0068932702,2.76525,-0.67628002,-0.237279 +-0.850142,-2.5751901,-0.152334,2.4892499 +-0.48757499,-0.0018720099,-0.36079499,0.456633 +0.25762999,2.8888299,-0.085967898,0.62996799 +0.26071799,-0.17157,-0.072733402,1.92295 +-0.989245,-2.98348,-0.00229436,2.4502499 +0.230535,1.43741,-0.40674499,0.33989701 +-0.105137,-2.3554499,-0.24486201,1.5337 +-0.15750299,1.15405,-0.108373,-2.76561 +-0.705401,2.96401,-0.175575,-1.4764 +-0.703843,0.99190199,-0.0262431,-1.49816 +-0.95308298,-0.069906302,-0.050304402,0.80158299 +-0.122524,1.6638,-0.0065628998,-1.4672 +0.100314,-2.68891,-0.132149,1.26212 +0.29032901,-1.9126199,-0.0387499,0.840231 +0.73617798,0.151979,-0.0942396,-0.162774 +0.0220083,-1.6982599,-0.0136226,3.0211301 +-0.146874,-2.83547,-0.0258161,1.14411 +-0.084969603,2.87185,-0.237702,0.210787 +-0.189999,-0.64729798,-0.038100298,0.027871 +-0.97978997,-0.788903,-0.31846201,0.84701699 +-0.261565,-1.42484,-0.0127735,-1.3279999 +0.34054801,2.07763,-0.088602297,-2.5418501 +-0.56768101,2.05615,-0.033468299,-0.42110601 +-0.87440199,1.25841,-0.0083939303,-0.97645903 +-0.23350599,2.42981,-0.089813299,0.76279002 +0.56808197,2.9707601,-0.130762,0.19545101 +-0.43360901,2.2707701,-0.108843,0.16610201 +-0.0104143,1.25907,-0.11082,-0.70167297 +-0.77614599,1.18027,-0.036524199,-0.200064 +-0.0251984,-1.9921,-0.15107299,2.4683299 +0.66794997,-0.25578499,-0.0206773,1.34855 +-0.41532499,-1.21411,-0.046568401,-3.0626299 +-0.65865803,-1.38737,-0.107506,1.84096 +0.68495899,-0.27852699,-0.088759802,-2.6786301 +0.125912,0.83588898,-0.0145581,-2.8431699 +0.13266,2.0571001,-0.031766899,-0.72362101 +0.93832999,0.105186,-0.167827,3.11533 +0.31317601,2.14679,-0.048679698,-2.1097901 +0.394021,-2.09606,-0.0084877303,-0.50613999 +0.12541699,-2.10676,-0.050965302,-0.0229293 +-0.101686,-1.96031,-0.0273553,0.98854601 +-0.39637199,2.4649799,-0.0153768,-1.06397 +0.595976,0.0125675,-0.160795,0.0875284 +0.295863,-0.44780999,-0.00724302,-0.42426899 +0.69050699,-0.21287601,-0.38471699,1.08201 +0.426184,-0.40226001,-0.131589,0.70998502 +0.37617701,2.06639,-0.13278,-2.3298299 +-0.46952999,0.414673,-0.37724701,-2.30967 +-0.67720997,0.891702,-0.042019401,3.039 +0.722049,2.0624199,-0.086746998,2.2491801 +0.90386802,-1.01946,-0.0266048,-2.78843 +0.24219701,0.57141799,-0.155265,-1.55015 +0.81945401,2.68152,-0.138588,-1.31213 +-0.65855002,-1.68765,-0.0198557,-1.00797 +0.95442498,2.6774399,-0.169264,0.25816199 +-0.444224,1.90256,-0.0045032101,0.630494 +0.54771799,0.78557903,-0.36357301,2.9776101 +0.66688198,-1.87161,-1.04515,-0.33746701 +0.65777099,-0.80297202,-0.097502403,-0.88135803 +-0.47451401,2.3118999,-0.047916699,0.034646802 +0.114033,-0.058579098,-0.034286302,-1.55179 +-0.76953399,2.09899,-0.115313,-0.34898099 +0.34497499,-1.27701,-0.064311698,1.05963 +0.88527298,-3.1361101,-0.019806501,-2.17015 +-0.90003502,-0.92652202,-0.0269418,3.0046899 +0.112575,2.25858,-0.425376,0.129737 +-0.15520599,0.99389601,-0.0352199,-2.6178401 +0.42741099,-2.44839,-0.0386509,-2.7249601 +0.64214998,2.6235199,-0.053406101,-0.61686999 +-0.29834199,-0.66538602,-0.122698,-1.59111 +0.13759799,1.3414299,-0.025119999,0.57175398 +0.18960799,1.38989,-0.477871,-0.164902 +-0.15005299,-2.60516,-0.77438301,-2.0406599 +0.062668398,-1.09361,-0.25314,-1.7334599 +0.20392101,-0.20301799,-0.016556101,2.3445499 +-0.96634001,2.1808901,-0.060272299,-0.767456 +0.67812699,0.340058,-0.468824,-3.10778 +-0.96964502,2.1057899,-0.0332601,-2.1452301 +-0.307592,0.87400502,-0.284125,-1.88632 +-0.96293902,0.040387802,-0.147286,-0.84585899 +0.44427201,1.09552,-0.30787301,-2.3299301 +-0.195393,1.88305,-0.53131002,0.67240399 +-0.067927398,2.6080101,-0.093646899,-2.7583499 +0.36735001,-2.1773801,-0.52693301,0.35328901 +0.496589,0.81749898,-0.092557803,2.2534101 +-0.27219501,-2.84812,-0.0025172301,1.11955 +0.59183198,-1.7632,-0.143361,1.86283 +-0.812774,0.73359102,-0.090124898,-1.58565 +0.25270301,-1.14666,-0.63279998,-0.52942801 +0.59066302,-2.6668501,-0.103741,-1.0006599 +0.0501923,2.4826701,-0.070101701,-1.1520801 +0.82690901,2.0062301,-0.101949,-1.65276 +-0.1542,1.62646,-0.18771,0.63456601 +-0.36847901,-0.83996803,-0.27369601,-0.580423 +-0.77152401,1.9684,-0.071738802,2.90469 +-0.72547299,-0.274322,-0.043146599,-3.09584 +0.54793298,0.115707,-0.0103564,-0.97092599 +0.095757499,-1.89379,-0.39701799,0.837789 +-0.76172298,0.29144999,-0.075586401,-0.0257107 +-0.29411101,-1.07568,-0.0911071,-1.3128099 +-0.148587,-1.86483,-0.130979,-2.1183801 +-0.353369,-2.6578,-0.197457,0.39938 +-0.31837401,2.87165,-0.053704798,-0.80436999 +-0.31539401,-0.156745,-0.27718899,-1.39148 +-0.267836,-0.53797698,-0.39393201,1.67541 +0.93283099,1.20274,-0.0129461,1.48938 +-0.60468298,2.9669399,-0.662377,1.84403 +-0.796884,2.17769,-0.248221,1.32917 +-0.86818099,-0.90846997,-0.18029501,-2.4474699 +0.91470402,0.325991,-0.068123102,-1.32206 +-0.0528524,2.6442101,-0.70343399,1.18208 +-0.97814298,-3.06669,-0.29569301,3.1078801 +0.118358,-0.058194201,-0.177792,-2.5541799 +0.0180213,0.97454399,-0.10285,1.5297101 +-0.46685699,-2.7416301,-0.048143402,3.0022399 +0.63371998,1.41096,-0.25861999,-1.67959 +0.87796903,0.59193301,-0.098540097,0.43588901 +0.67340201,2.70772,-0.034162901,1.77843 +0.35888901,-0.41720501,-0.0079065198,-1.88924 +-0.38864499,-1.81428,-0.85137498,0.86955899 +0.356015,0.58133399,-0.0310545,-1.42538 +-0.808833,-1.45182,-0.108843,-0.0129187 +0.53469998,-2.86691,-0.025542499,0.699085 +-0.57212102,-0.50295901,-0.28847799,2.7823601 +-0.118468,1.80585,-0.59885001,1.67864 +0.419597,1.52283,-0.26691201,-2.3265901 +-0.91587198,-2.03582,-0.121028,-1.71108 +-0.35748801,-0.52617502,-0.59773999,-0.92822897 +-0.29176101,1.16734,-0.0472361,-0.55126899 +-0.57109702,-1.19195,-0.13757899,-0.26391301 +0.26640499,2.4293799,-0.097503901,1.30685 +0.37351799,-0.56623697,-0.50352699,1.53783 +-0.12806,-0.62915498,-0.124284,-1.36643 +0.32391801,2.1522501,-0.192055,-2.9161601 +-0.775594,-2.9330399,-0.067481197,1.65737 +-0.907583,-2.5516601,-0.37012801,0.90161902 +0.024927501,-0.033838201,-0.061381198,1.34738 +0.52265102,-2.2552299,-0.0227479,-2.6810801 +-0.097233497,2.9832799,-0.211125,-3.1079199 +-0.0796564,0.63966298,-0.059197601,0.68155903 +-0.10727,2.93222,-0.050893199,0.62675399 +0.68625998,-2.5021501,-0.094464697,-2.29089 +0.122772,1.82601,-0.0546063,-0.083301798 +-0.035091098,-1.85115,-0.0271235,1.03583 +-0.32125801,-1.4165699,-0.042546399,-2.9029601 +0.95295399,-0.84026903,-0.36123201,-0.83878201 +0.0595471,-2.5002699,-0.37620401,-1.2118599 +0.66973698,1.0239201,-0.099341899,1.30468 +0.85684502,-2.3415899,-0.071822301,-0.93542498 +0.233224,1.26871,-0.186671,-2.9075699 +-0.34505999,2.07236,-0.129051,-0.077787504 +0.77114302,-0.53010601,-0.0072657401,-1.2695 +0.108537,2.2414701,-0.13003799,1.42953 +-0.87252402,1.07467,-0.077871598,-1.91057 +0.89761603,-1.49951,-0.39800099,0.116137 +-0.55361801,-0.0476881,-0.495626,-3.05162 +0.092407897,-2.2843699,-0.073515996,-2.53245 +0.67690301,-1.8149199,-0.12874401,-0.85219401 +-0.92573202,-0.32308599,-0.41493201,-1.77721 +-0.40367699,0.47602201,-0.065624103,2.8473201 +-0.37390599,-2.8731599,-0.113961,1.27046 +-0.64337498,-1.75919,-0.174393,1.31523 +0.25696799,1.08632,-0.17312799,1.79996 +0.0375043,0.0116552,-0.192453,2.72809 +0.123001,3.12832,-0.0591617,1.2966 +0.33984199,-0.79398,-0.18185,-1.47356 +-0.36803001,-2.69293,-0.51419997,0.72648501 +-0.35177499,0.340821,-0.111111,1.61518 +0.81890601,-1.6819299,-0.0370115,1.0874799 +0.56076998,-0.54288298,-0.015812401,2.6572399 +-0.70102203,-2.66101,-0.165132,1.7116801 +0.455037,2.0915999,-0.15277199,2.1699901 +0.26920801,2.3295801,-0.0052347798,-0.067587599 +-0.65625298,-1.27167,-0.284042,1.51345 +0.47059399,-0.34117901,-0.30863199,0.378883 +-0.53044999,-1.08685,-0.493471,0.218613 +-0.074752301,0.300825,-0.016481699,1.75983 +0.050988499,-0.41822299,-0.0548159,-2.3155 +-0.171388,-2.3199401,-0.0264566,1.0062799 +0.99909198,-2.6545999,-0.279183,0.738509 +-0.52845103,-1.35809,-0.120885,0.57902998 +0.13950901,1.59401,-0.506226,-2.34675 +0.97330803,-0.666749,-0.0345232,0.36744899 +0.270524,-3.0508299,-0.0664832,2.1343901 +-0.776806,1.9230601,-0.68183303,2.71807 +0.00080954999,2.7606499,-0.0945898,0.993101 +0.64524001,0.66040701,-0.18117499,-2.69225 +-0.37823901,2.9300699,-0.271754,0.0060714199 +0.65895402,-1.79747,-0.044146501,0.86333299 +0.95830899,2.32412,-0.073040001,2.35308 +0.50028199,-1.28374,-0.053991798,-2.15171 +0.41033399,-1.84515,-0.00278995,-1.52714 +0.72510701,0.147779,-0.072616197,-1.50149 +-0.32770601,0.36446199,-0.036056802,-1.48391 +0.0110042,-2.28549,-0.202042,1.24975 +0.88472003,1.43601,-0.188271,-2.17927 +-0.32161999,-0.31782901,-0.116526,-0.33525601 +-0.19137999,1.98456,-0.45228001,2.34268 +0.235866,-1.16508,-0.44028401,0.94965398 +0.96938097,-2.77742,-0.213147,0.78986698 +0.0260364,1.9502,-0.036959201,-2.0671999 +-0.326114,2.76724,-0.058657099,-2.1954999 +0.74486202,-1.56393,-0.99728203,-0.36253899 +-0.58262402,-2.5070901,-0.073700897,2.14311 +0.48196501,-1.94435,-0.13639501,2.7202599 +-0.086331397,0.481273,-0.0235999,2.33565 +0.339708,2.5506101,-0.080818303,2.19346 +0.58026099,0.99728298,-0.099930599,0.85685599 +-0.85266501,1.13148,-0.071566097,2.0924499 +-0.86135399,-1.37182,-0.031714801,0.82322299 +0.042727102,-1.54089,-0.590689,-0.919725 +0.331801,-1.23298,-0.175873,-1.61782 +-0.245502,2.8169899,-0.155379,-2.13504 +0.94360602,2.7780199,-0.0287391,1.04597 +0.040567901,-2.0945599,-0.25402001,2.85201 +0.91731203,-2.43701,-0.106092,2.72085 +-0.68833101,0.85437399,-0.465561,1.53599 +0.96687001,-0.314208,-0.35400301,-1.49472 +0.529181,1.41643,-0.37524101,2.8340499 +-0.715119,-1.8178,-0.162811,-0.52838898 +-0.641132,1.40075,-0.17205399,-2.6382599 +-0.61634898,2.7476699,-0.34931901,-2.0571101 +0.719868,-0.60418802,-0.046484198,0.58819598 +-0.66191798,0.890935,-0.0208974,0.085295103 +0.181714,-1.7704,-0.088362202,-0.33973199 +0.72445101,-2.1043799,-0.12748601,2.1673601 +0.075276501,-0.56329697,-0.15544599,-1.35183 +0.28252,-1.96175,-0.121805,-2.3062401 +-0.0172674,1.3878,-0.035071399,1.99413 +0.34055799,-2.7945399,-1.53053,-1.27496 +0.446944,0.90960997,-0.089073502,-1.13299 +-0.71056998,1.04533,-0.17934,-0.780554 +0.80464703,0.374392,-0.0110631,1.18243 +-0.56023401,0.46750101,-0.065510303,-0.310527 +-0.144907,0.37426999,-0.439821,-2.37082 +-0.39234501,-1.94635,-0.120484,1.10515 +0.29894501,-0.46510899,-0.353064,-0.225798 +-0.91892701,-2.83197,-0.0095632896,1.8168 +0.494827,-2.55356,-0.229224,0.144076 +0.52812099,0.35908499,-0.0246033,0.66215801 +-0.47954699,-2.65943,-0.028560599,2.0811901 +-0.377206,0.187604,-0.37713301,-2.79774 +-0.078924298,-2.65083,-0.0067668902,-0.69737601 +-0.934192,-2.63271,-0.052158002,0.666062 +0.173517,0.94922501,-0.170919,-2.6566899 +0.76737499,0.97799599,-0.052933499,1.3040299 +-0.221358,-1.78783,-0.28456199,-1.79213 +-0.22674,2.4166601,-0.287173,-0.65300202 +-0.56906903,-0.38139999,-0.38569501,2.76158 +-0.42853701,-1.80295,-0.31853601,3.0678501 +0.87794501,-0.50347799,-0.099250302,-2.9110301 +-0.261729,2.26281,-0.063781999,1.7779 +-0.89907598,0.87167001,-0.052830599,1.50916 +-0.42467001,0.867015,-0.336788,-2.03076 +-0.414217,2.31495,-0.345736,-0.31656101 +-0.25267601,0.27414599,-0.243452,0.117796 +-0.92936802,-2.6868401,-1.0831701,-2.3240399 +0.33093899,-1.53653,-0.24078999,-2.52074 +0.028777201,-2.7130899,-0.55000901,-0.067304797 +-0.774064,2.3883801,-0.14948399,-1.88717 +-0.242669,2.8375199,-0.0425658,1.45733 +0.88703197,1.61139,-0.0042248699,-2.79652 +0.99603403,-0.0286371,-0.121163,-2.1403 +-0.385984,-0.76778501,-0.14654399,-2.8023901 +-0.84499502,-0.51942497,-0.32243201,-1.73624 +-0.98231202,-2.0987101,-0.31652999,-1.56604 +0.164597,-0.26499501,-0.121003,3.0228701 +0.93304801,-1.82777,-0.296453,1.41833 +0.205761,2.00034,-0.092340402,-1.14275 +0.77224898,-2.92612,-0.0724006,2.9369299 +-0.59514701,-2.8388,-0.28649101,2.7338901 +0.1249,-0.88340598,-0.0291833,-0.72430903 +0.74664599,3.09411,-0.095851801,1.12173 +0.75404,1.79145,-0.31560001,0.945337 +0.99078298,-1.2388099,-0.44931501,-1.8872499 +-0.33161101,-0.70393699,-0.073265001,2.7725899 +-0.52945399,1.96859,-0.112012,-2.9130099 +-0.28516501,-2.33689,-0.26245901,0.98972797 +0.105808,-0.76985401,-0.0129059,-2.2131801 +0.66701603,-2.00157,-0.075461298,2.6639199 +0.158191,0.39929599,-0.22868501,-2.5796599 +0.13209701,1.56795,-0.16128901,0.084411703 +-0.67476398,-0.46559101,-0.299243,-0.454835 +0.48616499,-2.3768699,-0.43446201,1.55918 +0.698026,-1.6217,-0.36492401,-2.9599199 +-0.026141301,-0.137804,-0.437769,0.44928899 +-0.150653,0.53796798,-0.0222074,3.02087 +0.32561201,-1.78073,-0.33663401,1.8722399 +0.53132403,1.97981,-0.304654,2.92132 +0.87595302,1.90078,-0.044242799,0.61546803 +-0.20118099,-3.08531,-0.041783798,-0.141625 +-0.206182,-1.76586,-0.289428,0.96669 +-0.68708301,-0.0162456,-0.487602,-1.53812 +0.48891699,0.19608501,-0.13422801,1.48384 +-0.93867898,-2.46346,-0.267589,-2.07512 +-0.33128101,-1.03687,-0.059039999,-1.83666 +-0.393105,-0.99923801,-0.42662701,1.5299 +0.66251701,2.8595901,-0.048960902,0.111209 +0.96386999,0.96226799,-0.102717,1.45323 +0.385921,-1.15262,-0.0068533402,-0.59644198 +0.60369599,-1.8217,-0.00749315,0.84759301 +-0.48332,-0.0787654,-0.48240301,-2.7218001 +-0.112071,-0.51389199,-0.110146,0.682468 +-0.977045,-0.47776201,-0.81636602,-2.8002999 +-0.77298999,-2.67489,-0.071789101,-0.536304 +-0.69375002,0.45539001,-0.091206498,3.0787799 +-0.040994801,1.30567,-0.052847501,1.9701101 +0.50994301,-0.41814801,-0.14117201,1.98804 +0.088171802,-0.201665,-0.037618499,2.9820499 +-0.833776,-2.88219,-0.51213098,-2.9015601 +-0.18168101,0.066710398,-0.32087901,-0.84976101 +-0.74111998,3.0806501,-0.088018,0.24741501 +0.78684598,-1.0137399,-0.201856,-2.0652399 +-0.88715899,1.20329,-0.58087999,1.68326 +0.94481599,-1.79408,-0.33759001,1.85253 +-0.60774601,-1.7456599,-0.39376599,2.7811899 +0.79608703,-0.195926,-0.387384,0.581783 +0.35801801,2.67838,-0.167184,-0.46583101 +-0.47176301,2.15905,-0.184783,1.8068 +0.0032816201,-1.66194,-0.239926,2.90693 +-0.047081701,1.9089,-0.27587599,-0.26108 +-0.80381298,0.45381701,-0.104383,1.35653 +-0.184329,-0.059563901,-0.037997201,-2.2430201 +-0.33860001,-0.38668501,-0.16491,-1.73488 +-0.56490302,-0.68900198,-0.0046071298,2.55283 +-0.17650899,-0.464003,-0.31753901,1.18002 +0.79531997,-1.51283,-0.40847501,1.2413501 +0.831204,-0.84153801,-0.116222,0.84825099 +0.218777,1.5189,-0.078970999,-0.38360301 +-0.347087,1.2967499,-0.26409701,2.89482 +-0.389714,-1.2529401,-0.24948999,-0.25321701 +-0.180758,2.0442801,-0.083486803,-2.5011699 +0.245544,-0.42680001,-0.210071,-0.390053 +0.42057201,2.10291,-0.121368,-2.4405899 +0.407208,1.74842,-0.023282399,0.98303199 +0.409015,-1.83849,-0.0271801,1.07026 +0.81376803,-1.7447701,-0.236773,1.50691 +-0.14887901,1.0701801,-0.31672299,-1.12307 +-0.84128499,-1.3339,-0.112265,-1.6546 +0.86716503,1.78229,-0.080378503,0.53845602 +-0.562482,2.6997499,-0.211992,0.72540998 +0.45450801,2.0508101,-0.124015,-0.34878299 +-0.369311,3.0743899,-0.113301,-2.24194 +-0.021440201,-0.95784998,-0.073539197,0.72605997 +-0.51375997,3.10835,-0.1187,0.55541199 +0.42497101,-0.61092001,-0.014311,-0.32001299 +-0.49494499,-1.82248,-0.184103,-2.61063 +0.553262,1.41442,-0.169599,-0.15548301 +-0.421817,0.257173,-0.386657,2.9343901 +0.56640899,1.08814,-0.16277701,2.34484 +0.84752297,-1.45171,-0.086119004,0.117296 +-0.206214,-0.484824,-0.28719699,-3.1385901 +0.30759701,1.86759,-0.070275404,2.1526599 +0.058813501,-2.7370999,-0.72815299,0.034283701 +-0.70205897,1.35622,-0.20237499,-2.76947 +-0.595945,0.53765303,-0.140186,0.82400298 +0.20768701,-2.54478,-0.082292698,0.833556 +0.99964601,-0.46141899,-0.24377599,-2.74105 +-0.87636101,-0.97927803,-0.066828698,-0.79991001 +0.59786499,-1.1241699,-0.0445293,0.31333101 +0.75151402,0.97678202,-0.071923301,2.59391 +-0.96363699,-1.02795,-0.098775402,-1.76188 +-0.95726299,-2.4139299,-0.079079702,2.15167 +-0.123595,2.25475,-0.163167,-2.5236499 +-0.57918203,1.59605,-0.028623801,0.54110003 +-0.206122,2.5097799,-0.044423599,2.7011499 +0.50157797,1.9183,-0.41146401,1.68524 +0.34065899,-1.44013,-0.0280517,0.595824 +0.21333501,2.80393,-0.14584,1.78611 +-0.48051101,-2.47123,-0.0210378,-2.3326299 +-0.54865098,1.65519,-0.26118699,-1.2951699 +-0.93271703,1.18612,-0.0077986801,1.66555 +-0.39075601,-0.92897201,-0.72058201,-0.64662498 +0.84260303,2.8472099,-0.24765401,2.04283 +0.29658899,-1.06643,-0.118305,-0.32815501 +-0.52267301,2.2000699,-0.243048,-3.0825701 +0.90304798,-0.37822399,-0.48207799,1.70138 +-0.943712,1.55233,-0.12778901,-2.59444 +0.98223901,-2.7648001,-0.24533799,-2.8577499 +-0.959701,-2.61516,-0.235258,-3.06056 +0.381962,-1.77676,-0.078605197,-2.52213 +-0.177633,-0.83402401,-0.27488399,1.44223 +-0.475786,-1.04618,-0.071616396,0.27299899 +0.14395501,-0.91287601,-0.209833,3.08283 +-0.80124003,2.8441701,-0.11149,-2.7504699 +0.63635302,0.514543,-0.15929499,-2.3961699 +0.90626103,-1.48136,-0.25698799,3.1415501 +0.449251,2.87198,-0.0834141,2.5518301 +-0.96316099,-3.00267,-0.122465,-2.01336 +0.893996,2.3141,-0.67679799,-0.45630601 +-0.0321417,1.48153,-0.21448199,1.3058 +-0.949229,-2.2184401,-0.060827501,-1.3083 +0.40848601,-3.0160899,-0.0119532,0.93687999 +0.109472,2.5241301,-0.127432,-2.40816 +-0.199938,1.33698,-0.0100201,-0.99920702 +-0.289341,-0.49766701,-0.030933199,2.62533 +-0.099752299,1.10874,-0.126287,-1.14464 +-0.228411,1.6294399,-0.23920301,1.29939 +0.16397201,-2.5650499,-0.166647,0.29195401 +-0.100127,0.13012899,-0.193499,2.3352599 +-0.638816,-1.98966,-0.140662,-2.61956 +-0.63583499,-0.128406,-0.0080768,1.86484 +-0.93239701,2.57863,-0.0354871,0.58596998 +-0.57228303,-1.72179,-0.0236148,-2.9462199 +0.0396295,-3.0067,-0.076022297,2.40517 +-0.92162597,-1.46437,-0.52524799,3.1252899 +0.040422101,0.14627901,-0.236911,2.1380601 +0.48653099,-0.99239802,-0.089063197,1.0463001 +-0.0186339,-0.95574999,-0.0086626196,-0.873182 +0.20884199,0.142395,-0.35383999,-1.64801 +-0.504448,-0.62939399,-0.22451299,1.12334 +-0.57002997,1.0513099,-0.151572,-0.92631698 +0.131053,-3.13726,-0.73988497,1.30604 +-0.64939702,0.364759,-0.047783099,-0.437819 +-0.756181,1.8256299,-0.547638,-3.00981 +0.60054803,1.87661,-0.068496101,1.984 +0.34290999,-0.73000199,-0.16728599,1.25799 +0.78814602,2.5307701,-0.0040427102,-2.74597 +0.44152299,0.28024501,-0.16267601,-1.88609 +0.73970997,2.3340001,-0.059319202,2.8061399 +0.56841302,2.70818,-0.333507,-0.765122 +0.00071769702,2.0078199,-0.35227701,2.30388 +0.216315,0.0539575,-0.114129,1.28667 +-0.120729,-1.45269,-0.041191399,-0.098082803 +0.52563399,0.206844,-0.144095,1.38283 +-0.78911602,2.6647699,-0.084657401,-0.47519499 +-0.27480701,2.1340499,-0.39713299,-3.07951 +-0.80975699,-2.9690199,-0.0124818,1.3006999 +0.077610999,-0.72310299,-0.043777201,-2.32549 +-0.53411102,2.6851201,-0.158869,-0.95427001 +0.831361,-1.24708,-0.14255901,-2.5397699 +-0.457017,2.9156301,-0.25975999,-0.056920499 +-0.418556,3.0297899,-0.263504,2.09587 +-0.88736802,-1.58233,-0.321251,-1.01177 +-0.79123598,-0.74090499,-0.20565499,-0.054368399 +0.847826,-1.46576,-0.61820197,-2.1112399 +0.086852796,-2.0100701,-0.37489799,-0.087694101 +0.57404,-0.41351199,-0.038414199,-1.41786 +0.47323501,0.80345303,-0.111749,2.2653301 +-0.23942,3.1379099,-0.0112652,2.8847799 +0.57911998,1.89241,-0.14598601,0.61618602 +-0.93355799,-1.69682,-0.42300799,2.9899001 +0.38294899,-0.0364656,-0.123977,3.05036 +0.50027502,2.0903201,-0.051891699,-1.3694201 +0.91527599,-2.4583399,-0.0042687198,-0.0127799 +-0.69830799,1.4251601,-0.19644,1.5464799 +0.61652398,0.198478,-0.0321346,-1.13589 +-0.80288601,-1.7151099,-0.24004801,-2.6869199 +0.52463698,-0.94451898,-0.080366701,1.9615901 +-0.98659801,-0.045161098,-0.117443,-0.963292 +-0.31044701,2.2971101,-0.16843501,1.94542 +0.082162701,0.95812702,-0.027765701,3.0875001 +0.26508901,-1.79002,-0.18439101,-2.01332 +-0.24456701,-0.58286202,-0.083439097,-0.340902 +-0.808559,1.62628,-0.0064994702,-1.05875 +0.185737,1.45664,-0.291913,-1.0680799 +0.666125,-3.0257599,-0.0172907,-0.84514201 +-0.70937902,1.91378,-0.0297537,0.59770298 +0.109247,1.34705,-0.23552901,2.3664501 +-0.573017,0.66165501,-0.26061499,-0.80508697 +-0.58670199,-1.86797,-0.51624101,-2.8087201 +-0.91904598,1.28174,-0.124987,0.58557498 +-0.82148099,-2.1479599,-0.59428698,1.39568 +0.36478499,2.4003201,-0.114401,0.231731 +-0.71577698,0.95013303,-0.448349,2.0950799 +-0.77468699,2.35479,-0.0059501301,-2.6038499 +-0.86376601,2.68314,-0.097357698,-2.1240301 +0.560745,0.86457598,-0.059006199,2.0509801 +-0.97219002,2.6092401,-0.176333,1.10979 +0.796579,1.36456,-0.056631099,1.31223 +-0.843072,-2.1571801,-0.081565201,-1.01791 +0.38738301,-3.11026,-0.0886757,0.57072699 +0.28591001,1.4062001,-0.29523301,-1.93963 +-0.382195,0.40826899,-0.084356502,0.55510098 +0.42338899,-0.54729998,-0.197925,0.62241 +-0.756064,3.1131401,-0.018307799,0.0113634 +0.48815101,1.34332,-0.021894099,2.1408401 +-0.75054097,2.4310999,-0.043676499,2.60939 +0.45234001,-2.89486,-0.25669,1.11269 +-0.233327,2.9611599,-0.165564,-2.70169 +0.13015001,-2.2648799,-0.044368502,0.121391 +-0.668935,-0.47921401,-0.0081045497,-1.14236 +-0.78276497,2.2309,-0.082727402,0.383735 +0.88937598,-0.286823,-0.22244801,-0.77044898 +-0.28637299,-2.7792399,-0.15583,0.62755799 +0.14101,-2.21034,-0.119954,-0.158777 +0.65283298,-2.0511,-0.15431599,1.88572 +0.42929101,2.29179,-0.039527901,-0.145869 +0.67207801,0.358105,-0.154432,3.0770299 +-0.48819199,1.25388,-0.216703,3.0064199 +-0.48725799,1.91965,-0.118059,-0.89735597 +0.42501599,1.21472,-0.0103518,-3.04141 +0.26185101,-0.99704403,-0.0643356,2.9623001 +-0.043186899,1.83012,-0.068660401,0.207081 +0.70343202,2.9382701,-0.18190899,-0.95997399 +0.77157801,2.6215999,-0.038626298,-1.2323999 +0.99042702,-0.548253,-0.38398999,-2.8610799 +-0.044298202,0.063229598,-0.235135,0.87952298 +-0.45383099,-3.0754001,-0.041039199,-3.1076701 +-0.47064599,2.2042201,-0.198733,-1.02031 +-0.324462,-1.49053,-0.117124,-1.3405 +-0.98627102,1.42492,-0.0040316102,-2.49896 +-0.30556899,3.1016901,-0.37185401,0.62774098 +0.69728202,2.3580599,-0.120545,-2.9314899 +-0.68322998,1.9207799,-0.0269586,-1.95581 +-0.353517,-0.552499,-0.107335,0.0064778202 +0.944556,-1.09943,-0.171784,1.41754 +0.0112885,1.68628,-0.084216997,2.41325 +0.36177501,0.383724,-0.19488101,-1.76841 +-0.96378899,-1.8154,-0.0282207,2.30865 +-0.0222346,-1.96698,-0.149434,-2.56936 +-0.250911,1.89634,-0.0652657,-1.49569 +0.51734298,-2.04703,-0.49896401,3.0478001 +0.36054501,0.54697597,-0.24879099,-1.87091 +0.38062,-1.41366,-0.290921,-2.7125499 +-0.53353101,-0.93661201,-0.069025204,1.52407 +0.42889699,-0.602148,-0.150773,-1.82609 +-0.172581,-0.169306,-0.198898,3.0209999 +0.155634,1.93651,-0.74999201,1.12049 +0.57846099,1.55311,-0.50573701,1.85691 +-0.290705,-2.6348801,-0.43458399,-1.2974401 +-0.90987903,0.61771202,-0.15244099,-1.81178 +-0.61327797,0.88103998,-0.0130193,-1.49835 +-0.25273299,-2.5330701,-0.162176,-0.40037501 +-0.74378902,3.07201,-0.059558101,-0.00674647 +0.952528,0.98485601,-0.0216657,-1.96057 +-0.63856399,2.3260701,-0.080627501,-0.20263 +0.82197702,-2.87797,-0.265706,-0.390791 +0.055989001,1.86555,-0.204418,1.85622 +-0.48251399,1.33312,-0.071603402,0.902147 +0.49451399,1.6776201,-0.040073801,2.7866499 +0.265885,0.29166701,-0.41472501,-0.64978099 +0.0452158,1.76205,-0.16384,1.41347 +-0.102818,0.104439,-0.207174,-2.40184 +-0.81430203,-0.78801602,-0.0247555,-1.53698 +0.017995199,2.5637901,-0.084168799,-2.6763799 +-0.65837502,-3.03934,-0.0087412801,-1.64519 +0.33174199,2.23329,-0.156137,2.7216001 +-0.95646697,-2.7021999,-0.144278,1.94427 +-0.047193099,-1.42435,-0.115111,0.64552897 +0.276346,-0.121649,-0.32659501,2.0367899 +-0.090329699,-0.25887901,-0.103096,0.037963498 +-0.41832599,0.61594701,-0.089860603,0.55710799 +-0.136922,2.1296201,-0.353504,0.51943099 +-0.230198,1.23743,-0.100628,-1.01231 +-0.92953801,-2.6189899,-0.052912001,0.70539802 +0.98100299,-1.6614799,-0.157032,1.11976 +0.043543499,-1.54696,-0.00819219,0.43434101 +0.182845,1.55897,-0.160473,-1.23815 +0.565718,1.31155,-0.152308,2.79528 +0.42359099,-2.7579,-0.37299201,-0.52203703 +-0.67499,1.7826101,-0.026344201,1.8561 +-0.96758503,-0.337827,-0.211032,-0.97705001 +-0.32995999,-1.74268,-0.20378999,0.24581701 +-0.259312,-0.58123201,-0.26400799,0.26430699 +0.19301701,-0.55190402,-0.152677,2.8836999 +0.92278898,-2.7507,-0.42581499,-2.60181 +0.71044499,-0.98204702,-0.40598899,-0.77941298 +0.136306,-1.0829999,-0.068314202,-1.37051 +0.56702,-2.4542601,-0.107983,-1.82679 +-0.19312701,-2.58394,-0.389671,2.6491699 +0.75504303,0.049459901,-0.21173801,-0.109482 +-0.57819301,1.29625,-0.30003601,1.5577199 +0.37135401,2.2910299,-0.26141,2.03143 +-0.68972301,-1.9638,-0.109843,-2.3951199 +0.29036501,1.90341,-0.063463099,1.35006 +-0.86886102,0.94361198,-0.110177,-2.57517 +0.22103401,1.22127,-0.225536,-0.18744899 +0.889696,-2.72052,-0.034554299,2.8327799 +0.89574099,1.59197,-0.101633,-3.1084499 +-0.134213,-0.78597802,-0.141032,2.9739499 +-0.403126,-3.12448,-0.119219,-2.1062801 +0.94277602,-0.99545699,-0.282821,-2.63322 +0.63413399,1.6122299,-0.46553999,1.42417 +0.46056601,3.08688,-0.28048599,1.84738 +0.79712498,-1.34803,-0.091093101,2.0638499 +-0.79437798,-0.228359,-0.069621198,-1.83342 +-0.200482,-2.62919,-0.0077187498,-2.2097099 +-0.527731,2.2505,-0.400922,2.3166001 +0.419173,1.1253099,-0.010037,-2.9188001 +0.34213299,3.10847,-0.101006,-1.32436 +-0.80870998,-0.88646799,-0.44192299,-3.0985501 +-0.440312,-0.85155398,-0.0282108,-0.34803799 +-0.107581,2.5149901,-0.141019,-2.0518301 +-0.88268101,-2.1400599,-0.0235707,-0.17862301 +0.0500184,0.58924299,-0.088337101,-0.86116397 +-0.51574802,-1.1206599,-0.160671,2.15839 +-0.30587399,0.77767003,-0.61291099,1.10269 +0.112136,0.887146,-0.048497502,-2.4662299 +0.60287303,-2.6742799,-0.0590325,-2.6375101 +-0.37041399,-2.08096,-0.14835,1.28259 +0.348288,-2.66063,-0.42591101,0.34768999 +0.160706,2.82774,-0.055882201,1.21184 +-0.462614,-1.68089,-0.187526,2.9339199 +-0.021738101,2.2387199,-0.095017798,-1.77266 +-0.0402078,-1.8136801,-0.129025,2.08641 +-0.744519,-0.58647799,-0.046757001,2.87852 +0.96124703,-0.419972,-0.107088,2.6880901 +-0.0653935,-1.40501,-0.18313099,1.50639 +0.75348902,1.3701,-0.181307,-0.051726501 +-0.22233599,-0.74515802,-0.0131216,1.0809 +-0.889763,-2.78108,-0.115565,2.3338799 +0.64205301,-0.97860199,-0.183852,-1.81609 +-0.40112299,0.327526,-0.60799199,-2.2463801 +0.116584,2.16097,-0.189392,-1.49617 +-0.87528998,-1.25002,-0.12673201,-2.3426499 +0.86630899,-0.068178304,-0.289635,2.2676301 +0.28294501,-2.38097,-0.0434677,1.51254 +0.86871397,2.51244,-0.33654901,2.43326 +-0.060325298,-1.65289,-0.0117333,2.9584799 +0.65849,1.17607,-0.28852701,-1.98586 +0.70750999,0.27227801,-0.057871599,-0.74072701 +-0.39674899,-1.56154,-0.15239599,-0.164662 +0.794927,-1.41746,-0.30636701,2.07303 +0.73112798,2.7000599,-0.0499763,1.84797 +0.57718801,-0.405855,-0.049300998,-3.04725 +-0.66657501,-0.84818798,-0.116438,2.9848299 +0.087750196,-2.2062099,-0.101138,2.75704 +0.764157,0.82279402,-0.17697699,-1.76054 +-0.51435202,-1.42089,-0.0092787603,-1.2276 +0.29753801,3.10325,-0.080858096,0.61163998 +0.28648201,2.1043999,-0.0029380999,1.64011 +-0.18475699,-2.91063,-0.164336,2.7896099 +-0.53916502,-2.3219399,-0.350896,1.53857 +0.52557802,-0.97300398,-0.066551797,0.45859799 +0.48763901,0.113363,-0.050485499,-0.345606 +-0.111088,0.127726,-0.0985163,0.075042203 +0.240897,1.64779,-0.0165627,-0.906299 +-0.28858301,1.3273,-0.048200998,0.76004702 +-0.345869,0.512528,-0.584768,1.25819 +-0.075344101,1.50945,-0.059090901,-0.58068699 +-0.76800001,-1.22003,-0.41403401,-1.78959 +0.54073203,1.80318,-0.021461001,1.8249201 +0.71525598,-1.7334501,-0.28081599,-0.88480097 +0.28662899,0.867154,-0.0198112,-0.99018902 +-0.437832,2.9619501,-0.042770699,0.87875003 +-0.74787098,-2.3663499,-0.105402,-2.30797 +0.95699501,-2.1147399,-0.063650697,1.66712 +0.92408401,0.44410101,-0.044576101,2.59113 +-0.14479101,0.99894798,-0.0375361,1.0878299 +-0.067593798,-1.91108,-0.169641,-2.97666 +0.61462897,-1.3058,-0.135895,1.68629 +0.329344,-1.27267,-0.064409398,-0.71837598 +0.81210202,0.77955002,-0.210612,0.922786 +0.84352201,-2.93699,-0.47571701,-2.54777 +-0.73728299,-1.91348,-0.69609803,-2.5757799 +0.28911501,2.7074001,-0.0104215,-0.80969298 +-0.72257698,0.18614399,-0.163036,-0.203898 +-0.42727199,-1.7234,-0.47969699,-0.37312299 +0.29719299,-2.2922699,-0.404019,2.83795 +-0.054319602,1.07806,-0.323057,2.5415699 +0.033757102,-0.16407301,-0.088822901,2.85745 +-0.238993,0.85576999,-0.0241256,1.49207 +-0.76467901,0.25900501,-0.35477901,2.53441 +-0.361206,-2.6987801,-0.45411399,-0.95174402 +-0.71380198,-1.04103,-0.434073,-1.26722 +0.740448,-0.48010001,-0.033134401,-0.166835 +-0.206599,2.3816099,-0.35975301,1.06927 +-0.79132903,0.40008101,-0.043126699,-2.6206601 +-0.40258601,-1.9129699,-0.076572798,-2.0325699 +0.1191,-0.69003898,-0.097819299,1.38833 +-0.0073638302,-0.33930901,-0.0105626,-1.9996099 +-0.55292898,0.497924,-0.047331199,0.422115 +0.14810599,3.0107801,-0.122472,-1.6136 +-0.55810302,0.82536602,-0.051886398,-1.06308 +0.804295,-1.98535,-0.497675,-0.39506099 +0.74769098,-0.393085,-0.078422897,-2.41064 +0.050907101,-0.78855002,-0.162377,1.72293 +-0.27993199,-2.3819201,-0.034237999,1.92062 +-0.71857202,1.7185,-0.043746699,1.3179801 +0.0274795,-1.5804501,-0.0254739,-0.204533 +-0.94511801,1.3443201,-0.53056401,2.4366 +0.57898802,-2.9981301,-0.686297,0.62339997 +-0.74271601,-1.10098,-0.13051,1.6808701 +0.41272101,2.16324,-0.034076702,0.993572 +0.931925,2.4256301,-0.239709,-2.0752299 +0.46632001,2.2458,-0.023007,-0.243948 +-0.153667,1.64443,-0.20545401,3.00001 +0.83786601,0.0113177,-0.083282098,-2.1891999 +-0.552531,0.68374902,-0.18655699,-1.97232 +-0.77559102,-3.0131299,-0.12928399,1.4308 +0.149863,2.0816801,-0.053112,2.5515201 +-0.022659,1.8584,-0.0632881,-2.0165 +-0.079920404,2.3752601,-0.414671,-2.85552 +0.92092699,2.35987,-0.225722,1.5802701 +0.60887498,-0.19840001,-0.036206599,1.20289 +-0.26451099,-1.2578599,-0.67796302,2.0736599 +-0.97734201,-2.4221399,-0.152472,2.02858 +0.044105999,-3.1071899,-0.107028,2.63412 +0.0108524,2.57429,-0.029943701,-1.43144 +-0.28356999,-0.329638,-0.00523195,1.47399 +-0.69884503,1.78829,-0.0121013,-1.9797601 +-0.94712502,0.72998297,-0.0216415,-1.32434 +0.86883199,-2.8547299,-0.25460401,-2.47668 +-0.290999,1.54048,-0.039742399,-2.1351099 +-0.40898699,-1.03723,-0.112225,-0.62888598 +0.97803098,2.1352701,-0.121365,2.4602001 +-0.38850799,2.3230901,-0.102977,-2.9442599 +0.73826802,-0.92340702,-0.11188,3.13781 +-0.107885,1.38229,-0.39537701,-2.09446 +-0.49311599,0.60104001,-0.32959399,0.80676502 +0.62748301,1.24058,-0.127296,1.41208 +-0.49980801,-0.117608,-0.39153099,-0.61435002 +-0.54399198,0.46133399,-0.093155801,-0.29881001 +-0.157717,0.18262701,-0.181169,-2.96826 +0.747235,-1.89959,-0.103162,-2.4397099 +0.237754,-0.35093701,-0.0732508,2.6328101 +0.63633502,1.16886,-0.081473,-1.76864 +0.211597,-2.18364,-0.184799,-2.8743501 +0.90658802,1.96035,-0.071888499,-2.8747399 +-0.73218697,2.0880201,-0.094130203,-2.1658001 +0.048716601,1.49717,-0.21469399,1.19796 +-0.69015199,1.7376699,-0.15409601,1.08909 +0.064341702,1.72802,-0.139999,1.64899 +0.46654299,-2.71105,-0.24184,-0.58812398 +-0.82294899,0.83573997,-0.217539,1.54064 +0.413178,-1.98362,-0.053493701,-0.36707199 +-0.71974099,2.1503799,-0.127996,1.12757 +-0.87416899,-2.8177299,-0.00865224,2.0036099 +-0.26012599,2.7771399,-0.227227,-2.27724 +0.72662699,-3.02525,-0.0113283,-0.94014102 +0.15468501,1.7715,-0.0081058703,2.8123801 +-0.38354799,-2.60833,-0.13590699,0.45564201 +0.38005599,0.0394524,-0.118316,-2.43261 +-0.69320601,0.80673403,-0.094394699,-0.150668 +0.23634499,1.90402,-0.40067199,-3.0185299 +-0.00275918,2.19611,-0.62919402,-2.07037 +0.988446,-1.47697,-0.172187,-3.1093099 +0.52541202,0.230002,-0.0877873,2.4114201 +-0.087224901,-0.101209,-0.0246963,2.4686 +0.137263,-2.2356701,-0.54739201,-0.96542603 +-0.890567,3.10993,-0.259606,0.136051 +0.426247,-1.03048,-0.052048799,-0.083260603 +0.063017197,-0.369277,-0.13868999,-1.08302 +-0.76463902,0.778988,-0.31963,1.86136 +-0.252462,1.36055,-0.29947501,-2.7011001 +-0.71148401,0.74465102,-0.032296099,-1.75774 +0.47369999,-0.70660102,-0.33277699,-3.1333499 +0.48192701,-2.31531,-0.0492648,3.04146 +-0.47071099,-1.3344001,-0.159097,2.6606901 +0.0695161,1.83403,-0.044172201,0.197703 +-0.096504599,-1.56214,-0.0144898,-1.39571 +0.224693,2.0223501,-0.25518101,-1.49212 +0.46070099,2.0086701,-0.154906,-2.73349 +0.0885491,1.36369,-0.011228,0.46228001 +0.73580903,-1.40413,-0.095177598,0.549088 +0.057286002,2.0051799,-0.0564362,2.1270299 +0.408043,2.10361,-0.24559399,-2.6614699 +-0.884287,-1.0145,-0.31377,-2.97842 +-0.72176999,-1.45918,-0.0405415,-0.66382003 +0.627855,-0.292409,-0.0246296,0.93131799 +-0.0260597,-2.0775599,-0.118993,1.80765 +-0.991292,-1.1571,-0.0134043,-2.4748499 +-0.135529,1.78435,-0.23301201,1.64832 +0.085895397,1.17169,-0.0806638,-2.4611001 +-0.838907,-0.0079511199,-0.14947701,2.7195799 +0.33843401,1.64643,-0.53182697,2.08109 +0.0430113,0.90821302,-0.345263,1.25142 +0.073779501,2.7377901,-0.092383102,-1.26705 +-0.708251,2.61865,-0.112735,1.06654 +-0.67272002,1.2955,-0.031722799,0.97388202 +0.040747199,1.77071,-0.162976,0.58594102 +0.30001801,-0.0213899,-0.0119916,-1.12405 +0.39034799,-1.82258,-0.40169099,-2.8979199 +-0.220063,1.78676,-1.12026,1.6039 +-0.40575501,-1.63236,-0.0294431,1.14105 +0.16796499,1.87588,-0.0096098697,2.50934 +0.84974402,-1.5669,-0.200229,3.0943799 +0.51791298,-2.5487399,-0.041204799,-2.5366099 +-0.29274499,-0.43560299,-0.108686,-1.2849801 +0.528925,-1.64004,-0.11647,-2.2076001 +-0.583534,-0.43557799,-0.24562401,-0.1046 +-0.52235299,0.16574401,-0.049747199,-2.7527399 +-0.32348999,-0.73837602,-0.078192703,-0.75707197 +-0.43402901,0.63119602,-0.403,1.63205 +-0.88723898,-1.77679,-0.0219978,-1.48089 +0.051076502,3.04215,-0.51122499,-1.0146101 +0.0157547,2.02479,-0.0114652,-0.43664899 +-0.92207599,0.893821,-0.216645,2.1392 +-0.64960098,0.70406199,-0.100136,-1.3455499 +-0.0236986,-0.336422,-0.171973,0.43151 +-0.52483201,-2.33619,-0.137063,1.20463 +0.89206898,2.7182701,-0.111115,-2.39416 +0.29260001,-1.9565099,-0.0060501401,1.61092 +0.240238,-3.11411,-0.143356,-1.18274 +0.29160601,-2.18501,-0.88309097,1.38983 +-0.46689999,2.5332799,-0.314982,-0.231589 +-0.91710103,1.43625,-0.22692201,-0.039818101 +-0.498335,2.52968,-0.097938903,-0.47408199 +0.78695703,2.11552,-0.066675298,-0.59486097 +0.80893898,-2.3835101,-0.80126202,-0.44618401 +0.99036402,-1.6002899,-1.08241,-0.61918998 +-0.899719,3.1230199,-0.069677599,-3.0987501 +-0.57138097,-0.243131,-0.122524,2.70157 +0.161503,0.38570201,-0.121597,-0.18015701 +0.76187199,-2.3016901,-0.70440602,-1.22422 +0.075229801,1.07026,-0.083795302,-0.142923 +-0.52690703,-0.067889199,-0.200609,3.00367 +0.34579101,-1.63089,-0.17833801,-2.6508901 +-0.88475198,0.15666801,-0.041479498,0.103314 +0.84540999,1.54285,-0.82709497,-2.7948201 +0.34889901,1.61993,-0.17060301,-0.671619 +0.86835498,1.66852,-0.23920099,-1.2822 +0.140074,2.1583099,-0.0836123,-2.7720301 +0.28855899,0.51127201,-0.16606399,-2.0283699 +-0.26125801,0.83303797,-0.079287998,2.9830101 +0.42001301,0.27489299,-0.042481001,-2.93117 +0.3881,-0.45687699,-0.0142434,0.85199201 +-0.186822,2.6140599,-0.172951,2.7902901 +-0.64747101,0.111049,-0.035363302,-3.02054 +0.72489399,-0.69060999,-0.51800799,-0.11979 +-0.71191502,2.69735,-0.23905399,-0.89274102 +-0.95427799,3.10197,-0.25174001,0.495823 +-0.65606099,-1.72139,-0.248587,-1.59594 +0.268536,-1.53403,-0.25903401,-2.9710701 +-0.77527702,-2.9611101,-0.054256801,-2.93524 +-0.85042697,-2.1821201,-0.0319768,0.90400398 +-0.0833048,-0.89738899,-0.191164,-3.1171401 +0.52624899,0.79808098,-0.240538,-0.0235577 +0.29611599,-2.9635,-0.111801,-1.13041 +0.40670201,2.85883,-0.096009597,0.0145144 +-0.286479,-1.196,-0.151033,-2.0055799 +-0.299099,-2.30632,-0.028413599,2.60939 +-0.72359598,2.64996,-0.096220098,0.92667103 +0.71206701,-1.53061,-0.10233,1.7530299 +0.23483101,-0.0113406,-0.25388601,-1.9207 +0.79394001,0.98022002,-0.109711,1.84395 +0.31041399,0.92730099,-0.0084634796,0.25158 +0.85964203,-1.4232399,-0.076153003,0.53024203 +-0.275388,-0.90863901,-0.21164501,-0.80217302 +0.58343101,2.7391701,-0.092079297,-2.1572199 +-0.472101,-0.99164099,-0.75606501,0.59433901 +-0.603926,-0.0150608,-0.164382,-0.0033861201 +-0.46942401,2.8911099,-0.0693933,-0.63516998 +-0.98329997,-0.578839,-0.0087907696,-0.934636 +-0.33717901,1.96057,-0.42322701,1.8923301 +0.79333502,1.53509,-0.0112931,-2.8875201 +-0.77562499,-0.159972,-0.0640954,3.1278601 +-0.497444,-2.3638799,-0.21917599,-1.71219 +-0.49870101,-1.42467,-0.0191912,-1.24558 +-0.39967,1.98164,-0.0083430698,0.76952899 +0.893565,1.88597,-0.0059829298,-2.68419 +0.63247699,-2.0138099,-0.28634301,-1.33789 +-0.71289301,1.38126,-0.192046,-1.88095 +-0.58314902,1.5423,-0.085515298,1.89096 +-0.96200401,-1.05847,-0.0088713001,-0.68062103 +0.24881899,-1.63081,-0.084612601,2.6431501 +-0.19995201,-3.0699699,-0.111086,0.171405 +-0.69465101,-2.3190899,-0.106124,-1.55551 +0.23431399,-0.408117,-0.032785501,-1.25696 +0.95481402,0.88531899,-0.207807,1.03907 +0.37966701,2.94416,-0.162406,-2.2632101 +0.65027398,-0.95792699,-0.17617901,-2.86395 +-0.284013,-2.18521,-0.79656798,1.20199 +0.645594,2.22189,-0.47683999,-1.2776099 +0.55655801,-0.81300801,-0.109263,2.5878899 +0.80479801,0.57343799,-0.224379,0.455282 +-0.67196,-0.32314599,-0.066638097,2.332 +-0.913634,3.0176201,-0.132209,-0.171477 +-0.46933001,-1.33757,-0.075200699,2.53268 +-0.440606,0.771047,-0.75384301,1.56256 +0.77608001,0.39753699,-0.0025432201,-1.81098 +0.710949,-0.62835097,-0.58760601,-0.44917601 +-0.47372901,0.071074203,-0.086220801,-2.2713499 +0.27184901,1.82429,-0.228297,-1.53387 +-0.36037201,-2.46489,-0.112908,0.35486901 +-0.281192,0.48025,-0.165345,2.7165101 +-0.64152902,-2.01478,-0.0126589,-1.5992399 +0.44374201,-2.3230901,-0.295984,-0.97382897 +0.0170663,3.0434101,-0.077453703,-1.54037 +-0.32440901,3.01882,-0.107031,2.0353501 +0.81172299,1.6614701,-0.292445,-2.85502 +0.043573,0.0131124,-0.0226113,-2.7472999 +-0.183495,-0.46432999,-0.111115,1.65047 +-0.376205,-1.76402,-0.095450997,-0.67740798 +0.51949799,1.97176,-0.093124501,2.01986 +0.56283897,-2.8380899,-0.33054999,-1.22597 +-0.633255,2.2243099,-0.0544548,-0.352054 +-0.54509503,-0.12867001,-0.140239,2.74102 +-0.98370999,2.1841199,-0.14555401,-0.90231401 +0.150923,2.00564,-0.25492299,1.24911 +-0.079170197,1.9627,-0.054382499,2.3361499 +0.285611,0.387297,-0.231668,1.10552 +0.912265,1.16562,-0.301837,-1.11663 +-0.34998199,1.22355,-0.85062701,-1.2000901 +0.50411397,2.0492599,-0.27411801,-1.0094 +0.382029,-1.68718,-0.40902099,1.57403 +0.74547499,-2.9142101,-0.019796001,-1.41495 +-0.40594399,-2.4495699,-0.070011601,2.8633201 +-0.69569498,-1.13632,-0.138989,-2.1254699 +-0.961824,-1.91898,-0.35286701,-2.6252601 +0.27819201,1.88237,-0.082008801,0.181713 +-0.25225201,-2.7771699,-0.034000002,2.7588999 +-0.54594803,-1.21629,-0.29030901,-0.75060499 +0.40404999,-0.95918298,-0.089648403,-2.0239301 +-0.80407399,-2.55566,-0.144247,-0.98937601 +0.74799401,0.12939601,-0.099485397,-2.35991 +-0.76878601,2.7577701,-0.12939601,-2.5185399 +0.80470902,1.67194,-0.26234901,-0.84671497 +-0.697079,-2.1200399,-0.221725,1.07863 +-0.129816,0.63371098,-0.45455599,-2.40484 +-0.20621599,1.22229,-0.34110901,-1.41448 +-0.139906,-0.145935,-0.229166,-3.0773399 +-0.859698,1.11649,-0.29346499,-1.38397 +-0.86345798,-1.78549,-0.0562956,-1.9346 +0.362506,-1.71035,-0.076792799,2.2605 +0.61265999,0.92452502,-0.046293098,-0.79746401 +0.63238198,-1.52052,-0.062144399,1.57216 +-0.71202999,-2.8308899,-0.27989501,-1.51283 +-0.92744201,-1.58473,-0.0020568001,-2.3335299 +-0.76766402,-2.69087,-0.144723,-0.137403 +-0.52915603,2.7654901,-0.0245113,2.19418 +-0.098645203,-0.38545999,-0.102314,-2.1038599 +-0.0299688,1.1391,-0.058147602,2.9847 +0.93314898,1.67322,-0.160135,2.05393 +0.24586201,1.7665499,-0.059701301,-0.88368201 +0.31259799,-0.32559299,-0.17284501,-1.0147901 +-0.91869801,2.1956,-0.021031501,-3.09374 +0.73780799,0.457977,-0.24188,0.084640197 +-0.61574602,0.40334901,-0.59174597,-1.13263 +0.70911598,-1.4360501,-0.155865,2.3375199 +0.849756,0.66189998,-0.238838,-1.32906 +0.36625999,0.751625,-0.0211688,-1.57889 +0.42750299,-3.0083699,-0.0214503,-0.91273999 +0.184944,-3.03776,-0.117039,1.61169 +-0.158407,0.83759701,-0.0263262,3.00616 +0.85864198,-2.9528999,-0.317945,-0.528337 +0.27363199,-0.38220701,-0.018479399,2.6782501 +-0.075897902,-0.392353,-0.14453,2.8352301 +0.0165914,1.09956,-0.034473501,1.90149 +0.46454799,1.89685,-0.118566,-2.1736801 +-0.85982299,2.7196,-0.020368701,-2.8666201 +-0.28412801,-2.0290401,-0.44727299,2.58834 +-0.595182,-2.34676,-0.0141593,-0.273056 +0.44234401,0.63850498,-0.034019601,0.29329601 +-0.028511001,-0.296819,-0.0106793,-2.8171501 +-0.191366,1.64167,-0.020393999,2.0699699 +-0.110552,1.24629,-0.0647825,-0.086335897 +0.31395599,-1.86259,-0.045229599,0.52030897 +0.914958,-2.1603999,-0.035485901,-1.2813801 +0.49236399,-0.382465,-0.43922901,-2.2728801 +-0.25850499,1.87321,-0.111161,3.11428 +0.76649499,2.4233999,-0.237774,-0.87947899 +-0.826464,-0.60871202,-0.17201699,0.52670199 +-0.148424,1.61696,-0.42042899,0.70096201 +-0.90882999,1.58399,-0.91351402,-2.9080701 +-0.978558,1.16477,-0.062613197,-0.28490001 +0.491714,1.25348,-0.13079,-2.16342 +-0.27340001,3.0806899,-0.0497307,1.30814 +0.50296801,-0.37395701,-0.00296286,-0.116284 +0.43740901,2.38908,-0.0209665,0.89381599 +-0.94818503,0.290086,-0.193453,-0.097410098 +-0.905626,2.14505,-0.36802101,0.157796 +-0.16157199,-1.19793,-0.037695698,0.93955499 +-0.59817201,-0.018475899,-0.201765,0.77447402 +-0.093369603,2.6347201,-0.15165301,0.78333002 +-0.65999401,-1.94663,-0.060453199,0.0420168 +0.50963598,1.31687,-0.0557096,-1.3631999 +0.79672301,-1.75471,-0.583287,0.61188698 +-0.61793798,3.1374099,-0.035982698,-1.65609 +-0.37502,2.8158901,-0.157258,-2.1907201 +0.95106,-1.5490201,-0.65771902,2.08746 +0.25068101,-2.3710101,-0.51570898,-0.120607 +-0.911044,-0.62156999,-0.080493398,0.72254801 +-0.56457001,-1.2552201,-0.45991299,-2.78743 +0.23406599,0.554151,-0.33794501,0.45879301 +0.105056,-2.52777,-0.085504599,2.91273 +0.36615101,-2.4730201,-0.124694,-2.5136499 +-0.28643,-1.45143,-0.076575503,1.8552999 +-0.520284,-1.5685,-0.056237701,-1.25709 +0.52037799,-2.3875101,-0.28204,-1.27774 +0.72669899,-0.82717001,-0.038291302,0.37430501 +-0.99056298,2.5896699,-0.53234601,-3.0903499 +0.83611798,-1.84567,-0.143445,-1.21067 +-0.40823501,0.94813198,-0.76086402,-1.73315 +0.184817,0.747428,-0.041061599,3.0746901 +0.34673899,1.72404,-0.123893,-2.65312 +0.99882603,-0.98005801,-0.21316899,0.62853801 +-0.50961697,-0.081279702,-0.131951,0.88473302 +0.948268,-0.30349299,-0.15930399,-2.33301 +0.95251,2.3985801,-0.268778,-3.0090101 +0.52259499,-2.03952,-0.0536368,2.6910501 +0.222598,-0.0614517,-0.0300673,1.91907 +-0.48884299,-1.31776,-0.0226488,-0.72431803 +0.19810601,-0.102682,-0.146642,2.53722 +0.69989902,2.56604,-0.50382501,-2.69804 +0.248375,-1.7338901,-0.125166,-2.7665701 +0.74958903,-2.1242001,-0.19839901,-1.2072901 +0.44126499,1.14178,-0.029012,0.49485201 +-0.0387525,0.27910399,-0.0457309,2.2070401 +0.67973101,0.89576799,-0.0076268599,-0.27774599 +0.80446202,-0.70121402,-0.202988,-0.843261 +0.37530801,0.273056,-0.0323033,0.74158198 +0.327189,-3.0274301,-0.064003401,0.905509 +-0.69694501,2.5313799,-0.28862199,0.273348 +0.0103629,2.4470899,-0.032567099,0.861193 +-0.118419,1.26377,-0.21383201,2.0215199 +0.71851802,1.46723,-0.393823,1.01351 +0.50061899,-3.11779,-0.060083199,2.6619699 +0.94560802,-0.207609,-0.261089,-1.55492 +0.88884801,-1.39493,-0.0588702,-0.88683099 +0.089946598,1.3944,-0.54775202,-0.99011701 +0.168236,0.427221,-0.043423999,2.131 +0.595869,0.76636499,-0.140227,-3.1176901 +-0.115394,2.4094,-0.140241,1.50427 +0.25643501,-0.167549,-0.068905398,-2.70697 +0.231948,-0.93817198,-0.31914699,-1.60385 +-0.53599203,3.0697,-0.33725899,-3.07657 +0.58163601,2.12217,-0.018293301,2.7463 +0.95303297,-3.1118901,-0.46557999,0.28111401 +-0.212267,2.92433,-0.263464,2.6874299 +0.068875499,1.03798,-0.168303,-1.47225 +-0.55668497,0.047206301,-0.109935,2.46524 +-0.74329603,0.41662499,-0.017042501,-2.1663401 +0.074675001,2.54176,-0.00324262,1.31933 +-0.91321802,-0.061458599,-0.081901804,-1.4165699 +-0.392912,-1.84326,-0.126734,1.28476 +0.88320202,0.564906,-0.082649,-0.487694 +0.59627903,-0.705419,-0.56687599,-0.40202799 +-0.94113803,0.054535799,-0.0226292,1.73366 +0.396166,-2.17132,-0.172048,-2.59869 +0.77956098,2.2283399,-0.19565301,-2.1004701 +0.90054899,-1.2130899,-0.23812,-0.63967699 +0.62043601,-2.4149799,-0.0435187,2.6561699 +0.21860699,-1.90108,-0.493334,-3.11022 +0.77857202,2.50421,-0.095737197,-1.87991 +-0.60442001,-1.0820301,-0.241025,1.30513 +0.355508,0.25371799,-0.40673301,1.65756 +0.50453401,1.9132,-0.0639612,-1.08601 +-0.64169598,-0.77002102,-0.041040901,-2.4516001 +-0.25194401,2.8264401,-0.101574,1.69274 +0.096399501,-1.43999,-0.17519701,-1.54568 +0.76950699,-2.22785,-0.13000201,2.43468 +0.82536799,1.54355,-0.105165,-2.6740601 +0.238932,2.32146,-0.37354901,1.15168 +0.58247602,1.24572,-0.14582901,2.5211201 +-0.64308798,-1.6478601,-0.119178,-1.86248 +0.064547598,-2.97732,-0.044364098,2.8361299 +0.283319,-2.6062901,-0.18522,2.60693 +-0.54447103,-2.08745,-0.44472799,1.6842901 +-0.41275901,1.66302,-0.344708,-2.4095099 +-0.61024898,-0.37735301,-0.373656,-0.195741 +-0.87141103,-0.59070498,-0.075718701,-1.78968 +-0.77326798,-1.9808199,-0.027769299,-1.33016 +-0.48459199,1.1182899,-0.17075799,-0.41125199 +-0.739299,-1.50082,-0.016345499,-2.3283999 +0.13973901,-1.60903,-0.051071201,-0.96309203 +-0.91283,2.7087801,-0.055383299,1.28583 +-0.596367,-1.85146,-0.130449,-2.22311 +-0.25039801,1.11046,-0.0176314,-1.69598 +-0.0264643,1.22182,-0.085128397,-2.3424301 +0.98000902,1.55206,-0.023358,-1.8465101 +-0.90185499,-0.83275598,-0.024569299,-0.93535298 +0.89554203,2.3663399,-0.049766701,-1.09694 +0.68204999,-2.52175,-0.0034634201,-1.00852 +0.626544,2.7300701,-0.183706,-2.4114399 +0.294606,-1.5544,-0.113442,-2.9612601 +0.272558,-1.3408999,-0.21558399,2.392 +-0.085366301,1.72001,-0.211145,-2.4051299 +-0.37835401,1.19836,-0.0202918,1.43699 +0.27522501,1.68367,-0.180934,1.8354501 +-0.0071191699,-0.394173,-0.077621303,2.33056 +0.0047263699,3.12111,-0.295771,1.62783 +0.286116,-2.2560899,-0.081784301,1.50606 +0.74530602,1.41442,-0.116217,-1.30425 +-0.095614798,1.36431,-0.26071501,-0.00741708 +-0.065783501,1.71711,-0.0163843,-3.03461 +-0.78293598,-2.7439101,-0.56007397,-1.54019 +-0.383176,-1.19049,-0.053651001,-0.28544 +-0.87732297,2.8327601,-0.211643,0.50752902 +0.036502901,0.67535198,-0.0169007,-2.5415699 +0.59589499,2.7355299,-0.245263,-0.147238 +0.76304901,-3.08392,-0.124072,-0.71951997 +-0.77151,-2.7231801,-0.081759602,2.31128 +0.488832,-2.05182,-0.30999199,-2.4525101 +-0.189142,2.9955399,-0.35638201,1.72786 +0.60206401,-1.7136,-0.043086398,-2.5097201 +0.515697,2.7801299,-0.057059601,0.21678799 +0.72408801,0.91691399,-0.16257399,-2.0892999 +0.52082199,-1.81163,-0.38902301,-1.36725 +0.55364603,0.30550501,-0.67920703,2.64784 +0.72645003,-2.6349399,-0.120554,2.57587 +-0.301478,-1.1478699,-0.1036,2.4948599 +0.313021,-1.00366,-0.34216401,-1.16941 +-0.87296098,-0.66931999,-0.26394999,1.85176 +0.36991701,0.094306,-0.0308713,1.24832 +-0.073402897,2.8102,-0.221582,2.46351 +0.30463701,-1.64325,-0.040154502,1.45842 +-0.51574397,0.093187399,-0.59223998,-2.30371 +0.206873,-0.163269,-0.300659,2.5759499 +0.433898,0.40384999,-0.067418501,-2.9521599 +-0.63674903,-0.108621,-0.095228098,1.70605 +0.45310301,0.72625101,-0.0298847,-1.58911 +-0.66304398,-2.73944,-0.40300599,0.74991101 +-0.087730102,-1.50815,-0.030045001,2.66066 +0.245867,-2.45596,-0.16192099,1.48392 +0.30498901,2.36463,-1.16395,0.41982701 +-0.24955,1.96882,-0.079514503,-2.72686 +-0.788077,-2.58883,-0.051803,2.2946401 +-0.79088199,1.5941401,-0.235393,2.4800401 +0.084023103,2.6781299,-0.45043501,-2.18485 +-0.66819698,-0.20551801,-0.31350401,-2.02126 +-0.987234,-0.84372902,-0.096861303,1.32581 +0.877087,-2.99634,-0.456478,1.90648 +0.87787402,-2.4667201,-0.0309052,-1.2385 +0.86633199,-0.70671099,-0.0138759,-2.50209 +0.38659301,-2.2536099,-0.0220985,-2.4830101 +0.356383,-2.86236,-0.122512,-1.6680599 +0.454519,0.536937,-0.35994101,-3.1379001 +0.43579,-0.175476,-0.470451,2.73068 +-0.49843901,2.8847001,-0.072476096,1.87125 +0.258414,-2.61165,-0.13167199,0.85852498 +-0.31952101,-3.1073,-0.17074201,2.4811001 +-0.69741201,-1.99772,-0.089016303,-1.2715 +-0.27504799,-0.66419798,-0.0328147,0.68826902 +-0.37816399,2.3162601,-0.221645,3.0209301 +-0.60180098,0.54433697,-0.133742,-2.0651 +-0.79351097,1.0423501,-0.255739,-1.78739 +-0.236176,-1.62998,-0.201068,-2.5770099 +0.49125901,-2.6024799,-0.036273099,0.56490499 +-0.62812901,-2.2299399,-0.198714,-2.6225801 +-0.112891,0.85084802,-0.14940099,-1.45568 +0.51336098,-0.99798399,-0.0269033,2.23684 +-0.89657402,-1.37194,-0.028405899,3.1122601 +-0.67843902,-3.03828,-0.041684899,2.9572301 +0.32438901,-0.349309,-0.121377,-0.78825498 +-0.53026003,1.4643,-0.072293699,1.3784699 +-0.451974,-2.05867,-0.164278,2.4355099 +0.36234701,-0.275341,-0.139336,-2.8067801 +0.70533198,1.26056,-0.28280601,1.03629 +-0.0329239,0.94545901,-0.067914903,-1.59326 +0.2297,1.25326,-0.35433999,-1.60861 +0.735416,2.0899899,-0.12652899,1.31723 +0.627078,0.22203,-0.183743,1.182 +-0.62683702,2.23456,-0.0102545,-0.69485998 +-0.195196,0.381769,-0.071312502,1.1229 +-0.60461199,0.27601501,-0.433391,-0.484106 +0.81658202,1.90083,-0.14795899,0.00306076 +-0.33128101,-2.7671001,-0.022845799,1.66151 +0.32021099,1.19752,-0.146268,0.430224 +0.60023099,-2.25895,-0.0094379,-3.0062599 +-0.586779,-0.0111213,-0.048441,-0.405099 +-0.85737002,1.95612,-0.0118643,1.79897 +0.42338401,1.85457,-0.087460101,3.09992 +-0.226319,0.33063099,-0.065572597,1.6452399 +0.53267503,0.78877902,-0.094652101,0.88920802 +0.85211003,-0.72415102,-0.099888302,-1.5623699 +0.85844302,-2.08952,-0.19484399,-2.2734699 +0.41540799,-2.06653,-0.176918,0.384855 +0.931431,-1.8520401,-0.097398601,-1.41956 +0.75038397,2.89691,-0.0039346698,-1.62685 +-0.794195,2.68682,-0.076327503,-2.2060599 +-0.055766001,-2.7337699,-0.40057299,-2.3015299 +0.0371265,-0.97781599,-0.57717502,-0.152937 +-0.109719,-2.51302,-0.0118013,-2.3876801 +-0.10233,-1.57023,-0.76667601,2.1988101 +-0.233023,-1.34045,-0.282682,-0.98158902 +-0.46793601,-3.0823801,-0.105574,3.0065601 +-0.19745301,2.98844,-0.077836998,3.0025599 +0.63616198,-1.16118,-0.053419702,2.3106999 +-0.93388897,0.668589,-0.55452502,-2.7979701 +0.58754301,-3.03771,-0.34949899,-2.87481 +-0.33909199,-0.01267,-0.194745,0.802513 +0.65388399,-1.5969501,-0.0165253,-0.62333399 +0.73574299,-0.22747301,-0.45488399,1.5895801 +-0.233757,2.5804801,-0.17425101,2.74369 +-0.248319,1.53029,-0.113431,-0.99117303 +-0.90487999,-0.57237899,-0.262279,-2.17347 +-0.87760597,0.31884199,-0.073745497,-0.67219299 +-0.79858202,-2.0127001,-0.26452899,-2.97559 +-0.218659,-0.87340701,-0.064730801,-0.69415802 +0.74054098,1.8994499,-0.36758199,1.75131 +0.73295599,-1.5688,-0.163578,0.30591401 +-0.492544,-1.1075701,-0.028282,-1.3345701 +-0.444251,-2.78882,-0.36567101,2.9590399 +-0.41984701,-2.7553899,-0.330127,-2.33845 +0.109137,1.53466,-0.0223567,-2.41186 +0.92028302,2.2037101,-0.284298,-0.95822603 +0.602633,-2.8496699,-0.39884099,-1.36408 +0.52770501,3.09094,-0.0051595899,-1.42592 +0.0655099,3.1269701,-0.168421,-0.90964401 +-0.41798499,-0.77862102,-0.057778198,-0.059331499 +-0.144068,0.050981902,-0.33787999,2.12607 +0.46979699,-2.84554,-0.40779099,1.08766 +-0.73856997,-2.06603,-0.28884801,2.3907299 +-0.0303385,-0.239905,-0.095094599,-1.0988801 +-0.96212,-1.37362,-0.016528299,-1.058 +-0.120288,-2.92136,-0.075357303,-2.77141 +-0.160127,-0.26308301,-0.173813,-2.5998099 +0.363114,2.7318399,-0.0036476301,-3.0650301 +-0.67658299,-1.61438,-0.0085299201,1.30507 +0.87376201,1.43567,-0.12935901,2.5464001 +0.35921401,-0.48772499,-0.44308701,-1.9754601 +0.075880997,2.54722,-0.023367699,2.7625101 +0.22858401,1.80193,-0.0205821,-0.64425701 +-0.429041,0.73745197,-0.17970499,-0.28007901 +-0.93633401,1.83415,-0.170121,-0.76631802 +0.42125499,0.35293499,-0.0374997,2.59497 +-0.396826,2.1271,-0.118737,2.3498299 +0.210475,1.73084,-0.00288572,-2.3255999 +0.0503099,0.13266701,-0.115655,-1.77384 +-0.15979899,1.37857,-0.017676899,2.1612501 +0.12529799,-1.75122,-0.031520698,-1.50674 +0.13464899,2.4462199,-0.0086252596,2.6040101 +0.119573,0.090971902,-0.226594,-2.6946499 +-0.375036,0.239792,-0.13063,-1.31382 +0.81636298,-2.5233901,-0.226954,-0.183897 +-0.57701099,2.3807199,-0.165344,2.66012 +-0.61424297,2.2086101,-0.176145,2.7581401 +0.56200999,-1.0639,-0.00742108,0.58227003 +0.91441,-1.51766,-0.072838902,2.34266 +0.929681,2.4110701,-0.192297,-2.5629201 +0.030892201,2.5745101,-0.68414903,-3.04633 +0.42514199,2.28843,-0.36595601,0.137394 +-0.31436899,1.2841901,-0.089529999,0.78879499 +0.13725901,1.81359,-0.072154596,-2.1021299 +-0.228025,0.68466502,-0.051018901,-0.64325398 +0.049634598,1.0784301,-0.080636598,0.328275 +0.55475301,3.00804,-0.058215801,1.79787 +0.67127001,0.275745,-0.13230599,-1.70374 +0.232585,1.80823,-0.27008399,1.0365601 +0.32769701,0.285631,-0.0023608401,2.9899199 +-0.247297,-0.54266399,-0.210916,2.3132999 +0.090905897,1.5027699,-0.663311,-0.97120303 +-0.218325,-0.46641099,-0.092278101,-2.9806399 +-0.36532101,-2.1533101,-0.202471,2.8336301 +0.61470002,2.6404901,-0.020197,-2.0576301 +-0.81499201,-1.4469301,-0.0688776,-1.75266 +-0.42377201,0.92145401,-0.200932,-0.64236701 +0.94677901,1.47393,-0.422683,1.63357 +0.27375099,2.5827999,-0.020932199,0.237297 +-0.708628,1.7515399,-0.0108526,2.0647199 +-0.425749,1.58476,-0.067124799,-2.00264 +-0.142102,-2.8059299,-0.109492,-1.8132499 +0.00025973201,2.0737,-0.058784701,-1.53583 +-0.77033502,2.2346001,-0.13960899,-0.60439003 +0.843445,1.0177799,-0.215913,-1.28688 +0.93219399,2.64518,-0.044790201,2.1823101 +-0.48428199,-1.74639,-0.235732,1.09302 +0.118066,1.37594,-0.36079299,1.32435 +-0.0115762,-0.042408999,-0.360753,0.37325901 +-0.057650398,-2.05845,-0.016775399,0.906075 +-0.81024402,-1.12796,-0.099763297,-2.88852 +-0.610636,0.68238097,-0.0192813,-2.5478401 +0.257871,-0.109787,-0.065921202,-2.9559901 +-0.20976,0.56149101,-0.036570098,-3.1407199 +-0.97009701,-2.89556,-0.78328103,-0.23033901 +0.331503,2.6854,-0.30395499,-2.4837899 +0.000203016,3.13183,-0.084755898,-3.0892501 +0.455522,-1.3220299,-0.057328202,-0.65409398 +-0.339618,-2.9658101,-0.45567399,-1.07732 +0.516092,-2.62797,-0.092408597,0.30648199 +-0.49220899,0.856848,-0.115859,0.355064 +-0.217362,-2.3715601,-0.268141,-1.63326 +0.18852,-2.6368999,-0.27831501,0.486882 +0.82896101,-0.79336798,-0.385746,2.3018899 +0.98331302,-1.57609,-0.149345,-1.41608 +-0.73303199,0.0277982,-0.54803801,-3.0725 +-0.0069315801,2.7244301,-0.132146,-2.7291 +0.35133001,2.6239901,-0.151695,1.61183 +-0.79070902,-1.62791,-0.069717899,-1.7437 +0.157066,2.5357001,-0.13357601,1.81743 +0.88500798,2.2700701,-0.170966,2.85021 +0.982602,1.6953599,-0.33653,-2.0283301 +-0.190974,-2.6898899,-0.00476562,-1.48789 +-0.88690501,-0.945526,-0.29055399,-1.39118 +0.21246,0.60743099,-0.189895,2.8455801 +-0.053070199,2.28174,-0.123416,-2.21311 +-0.88260901,-0.162754,-0.107917,0.83441401 +0.36964801,0.039413799,-0.0171238,-0.20826 +0.89585698,-2.77896,-0.0819607,-1.99633 +0.62430501,-0.89912599,-0.122455,-1.03704 +0.079129398,0.097356699,-0.44693699,-0.592197 +-0.62638903,-2.72504,-0.026721001,0.71483201 +-0.80181402,1.0274,-0.10691,0.50127 +-0.46446499,0.72671801,-0.147587,0.27283499 +-0.405186,-0.20706899,-0.1719,1.52527 +-0.85954303,0.74927998,-0.128162,-2.9863801 +-0.734658,2.1674199,-0.152996,2.1747401 +0.205467,-1.66679,-0.13619199,-0.27932 +0.0060926899,2.33318,-0.0303318,-1.17041 +-0.718485,-0.497343,-0.14707001,1.12947 +-0.11656,2.2628601,-0.22320101,2.71893 +-0.578664,-0.39313701,-0.118985,-2.23106 +0.0041531902,-2.8396499,-0.754475,-0.54943103 +-0.62733197,2.5868199,-0.050940301,0.47499299 +0.542795,0.27666599,-0.138275,-0.63668197 +-0.19383401,-1.22172,-0.088435903,1.37589 +-0.124231,2.15294,-0.31724301,-2.13275 +-0.069361202,0.289673,-0.144436,0.47139901 +0.46511099,0.70088398,-0.0261568,-1.54285 +0.0273962,1.1612099,-0.239243,2.71474 +0.84239101,-0.55460101,-0.0031252599,1.94312 +0.79650903,-3.0425799,-0.058476299,-0.76239997 +-0.96753597,-1.7360899,-0.203355,-1.6468101 +0.144228,2.8764901,-0.68324703,0.67590898 +-0.93955803,-2.56043,-0.185195,0.51291001 +-0.00088215503,0.97061002,-0.083308697,-2.48908 +-0.132333,-0.97601902,-0.147002,2.0675299 +-0.89088702,2.7360699,-0.68778002,2.64099 +-0.25461501,2.33553,-0.319763,-1.58664 +-0.57283998,0.39136499,-0.00297776,0.59719199 +0.220927,1.4132299,-0.056089099,1.21867 +0.47290599,-0.55868298,-0.162477,0.76284099 +0.207141,0.55142099,-0.015545,2.15202 +-0.66160399,1.0427099,-0.229435,-3.1204 +0.168649,-1.63763,-0.20810699,2.2427001 +0.28050101,-2.72051,-0.0522709,1.37888 +0.12644701,1.60124,-0.00345163,0.72631198 +0.20991801,2.87608,-0.202718,-2.7743599 +-0.62006301,-0.042288698,-0.39924699,1.26808 +-0.435776,-2.2235501,-0.0128309,1.89566 +0.77465701,-1.5689,-0.040783901,-0.108154 +0.84701401,-1.16412,-0.37225199,-0.316338 +0.0207539,-1.62237,-0.16897,1.97361 +0.45621699,-2.8977599,-0.0420781,1.44376 +-0.228443,-1.34403,-0.235384,2.19766 +-0.41779399,-0.824857,-0.34842899,-0.163357 +0.67005903,2.3689499,-0.36756101,0.35445899 +0.73764402,-0.042569298,-0.0133743,2.6347899 +-0.94336498,2.4740701,-0.041303001,1.8130701 +-0.13547599,1.24817,-0.146965,-1.96937 +0.52811801,-0.92894101,-0.185094,1.91158 +-0.20324799,0.42811701,-0.29245099,2.4411099 +0.49610099,1.16868,-0.026803,2.5007 +0.92445099,1.8969001,-0.0104072,0.32366201 +0.40472099,-1.9485199,-0.213745,-0.913427 +-0.806279,-0.380027,-0.27834299,-2.3537099 +-0.61886197,-2.1693399,-0.123066,-0.38308999 +0.55517298,-3.0102999,-0.189125,-0.34407499 +-0.79131299,2.84481,-0.025323801,1.87658 +-0.720294,-0.84361601,-0.25112799,-3.0495999 +-0.241459,-1.42627,-0.084453396,0.058653198 +-0.93518698,3.01774,-0.189503,-3.1072099 +-0.96897,2.12027,-0.242571,-2.8572299 +0.76093799,2.98893,-0.042083301,0.045012198 +0.296388,2.2766099,-0.0090082102,-1.50872 +-0.38603199,-0.31495699,-0.16125201,2.86483 +-0.97503102,-0.0092506697,-0.199946,0.68260801 +-0.83735597,-1.31336,-0.067893602,0.44804001 +-0.77384001,2.4007399,-0.0044549,0.056810401 +-0.78265703,-0.382379,-0.100704,-1.4497 +0.20106199,0.25147599,-0.122233,-1.55887 +0.26113501,2.8123901,-0.0381984,2.0445399 +-0.93733197,-2.2179201,-0.19142,0.105485 +0.78329402,-1.30128,-0.0320439,-0.87638599 +0.957977,2.2302499,-0.22768,-0.71872503 +-0.89602703,2.2365799,-0.204943,0.31142601 +-0.371243,2.7951901,-0.060819902,2.2839899 +0.347662,-1.23165,-0.0120067,2.9430699 +0.680897,0.31172001,-0.22669201,-2.92611 +0.426521,0.00102901,-0.34466499,-1.99744 +-0.480744,2.76596,-0.17572901,0.63151598 +-0.896106,2.93208,-0.28793499,1.94508 +-0.066298299,2.2040999,-0.107671,-1.2398601 +0.74615699,-1.40769,-0.149639,-2.0240099 +0.27422199,1.99719,-0.0280829,-0.26622 +0.049509998,-0.67125899,-0.174944,1.39934 +-0.38338399,2.0671201,-0.0368516,-2.2816899 +-0.319424,-1.22427,-0.019873699,-1.12278 +0.759516,-1.9317,-0.40866199,-0.54505599 +0.51072401,2.6549799,-0.14756399,-2.9063699 +-0.696823,-1.17829,-0.0285875,-0.78438199 +-0.153497,2.4533,-0.0601211,0.222504 +0.070647597,0.0994514,-0.050728399,2.0376301 +0.0091878204,3.0234301,-0.307717,1.93286 +0.397668,2.0903299,-0.065258898,-2.4003 +-0.71687597,0.116504,-0.051107101,1.49001 +-0.67331702,-1.39808,-0.25894099,-0.74221802 +0.80005199,0.59640402,-0.0051182001,0.034821201 +-0.10768,-3.09779,-0.027716501,2.78704 +0.67226499,-2.75934,-0.21221501,0.0357586 +0.60698098,2.6932001,-0.31336701,1.8887 +-0.66436398,1.12389,-0.164222,-1.51105 +0.043285701,2.18576,-0.36726999,-0.11687 +-0.97019798,1.07093,-0.054486401,1.88055 +-0.041917302,0.157691,-0.13041399,2.40939 +-0.592668,0.86722898,-0.32586899,-2.64307 +0.124343,0.0917449,-0.18578599,1.97741 +-0.18847901,-2.9923699,-0.0144493,-2.13132 +0.0654957,2.57932,-0.0266906,1.8599499 +-0.00374787,2.55513,-0.151096,0.7022 +-0.89283198,-0.193202,-0.266303,0.191892 +0.16060901,2.56898,-0.062821403,0.50384098 +0.72403097,-1.32348,-0.086306401,2.83461 +0.94877899,-2.8629401,-0.33066499,-2.9816301 +-0.72679198,0.76066703,-0.146173,-1.2502199 +-0.35771599,2.1636901,-0.21318001,-1.70997 +-0.161323,1.4731899,-0.0220495,-2.83847 +-0.65556002,3.1231599,-0.131138,-2.0109401 +0.81368202,-3.0164199,-0.45389301,0.57035202 +-0.52676702,2.88586,-0.169542,0.33653399 +-0.70380503,-0.00399066,-0.110383,-0.89548099 +-0.89533401,-0.36250201,-0.102937,1.1465501 +-0.31202599,-0.84158403,-0.022302199,-1.15564 +0.35846499,2.8082399,-0.0065810299,-1.09113 +-0.016288601,1.00537,-0.088515602,-1.06327 +0.148155,1.61643,-0.31944299,1.79976 +0.67847598,-2.0172999,-0.11635,-1.7097501 +-0.17555501,-0.27000201,-0.096290097,-2.41099 +0.34333399,-1.75112,-0.329577,-1.67803 +0.17591099,2.71859,-0.119658,-2.7820001 +-0.242939,1.49826,-0.29656199,-2.6805699 +-0.71435899,-1.05056,-0.36316401,1.25193 +0.65577501,2.7808299,-0.345772,-0.17588501 +-0.234374,-2.8639901,-0.54148698,-2.3032801 +-0.090393603,2.3954101,-0.158986,-2.9109099 +0.41253999,0.89417797,-0.0684141,2.45962 +0.22994,0.72731799,-0.21331,-0.96636701 +-0.64004701,1.38861,-0.30103201,2.9190199 +0.93578798,-2.55602,-0.33558801,1.77194 +0.513345,-2.71597,-0.201966,0.11552 +0.80738199,0.53403199,-0.209654,-0.89433098 +-0.83019799,-2.1649101,-0.157665,-0.0464192 +0.77359498,-0.365125,-0.14058299,-0.0124114 +0.53989202,-1.45897,-0.14141101,2.42185 +-0.59616703,1.09033,-0.131901,-2.3045599 +-0.21439201,-0.74771303,-0.194344,-2.50367 +-0.50180602,0.199727,-0.13682801,0.38337901 +-0.99965,-1.97834,-0.0194807,-3.10478 +0.54923898,2.60465,-0.119983,2.4788499 +0.223703,0.074166499,-0.27214301,-2.2678001 +0.91792399,1.3575701,-0.225826,1.39776 +-0.42179,0.194618,-0.913351,-1.1292599 +0.57075799,-2.5894001,-0.28332201,1.51999 +-0.82575101,1.36454,-0.17734499,1.97574 +0.030610699,0.74524599,-0.115968,2.4544101 +0.91594797,1.7218601,-0.174208,-1.91652 +-0.939852,-0.558451,-0.078262798,-1.1093 +0.66578698,-2.6108401,-0.155614,2.4970801 +-0.62813801,-2.38184,-0.29231599,1.74255 +-0.35639599,1.88334,-0.108343,-2.1057601 +-0.30457801,1.82179,-0.40197301,1.0170701 +0.128425,0.79326999,-0.403137,2.30915 +0.20603099,1.0470099,-0.196895,1.49536 +0.97328901,1.0851001,-0.067391403,-0.231785 +0.88040698,-1.12208,-0.191236,3.05583 +-0.88918602,-0.7762,-0.37327999,-0.47332299 +-0.66726798,0.69784302,-0.26493901,-2.7975299 +-0.48950899,1.90282,-0.28507799,-1.49568 +-0.48834401,-1.29781,-0.52401298,0.158306 +0.732656,0.830221,-0.385829,0.51378 +0.070595101,0.087743796,-0.022886701,0.94517702 +-0.25366101,0.51967901,-0.43326899,3.13905 +-0.54197103,2.05018,-0.116484,1.0476201 +-0.0290494,2.3938,-0.14574,-2.1452601 +0.69895101,3.1115999,-0.164075,0.866485 +0.311537,2.8369,-0.064970903,2.5403399 +-0.212042,-0.35092801,-0.261392,2.42699 +0.92664999,-2.55636,-0.069023401,0.76885802 +-0.51599503,0.064030103,-0.116533,-0.68711102 +-0.33081299,-0.58546102,-0.23258699,1.4313999 +0.556705,0.0102053,-0.194858,-1.65441 +-0.76140201,0.0176118,-0.017125599,-0.25400901 +0.31837401,0.30008999,-0.126312,1.07618 +-0.68404299,-0.205542,-0.110605,0.75939101 +0.2834,-0.97841501,-0.079762399,-2.26705 +0.226467,-0.37610999,-0.069227502,-2.84215 +-0.97326499,1.93115,-0.0208479,0.29349801 +0.901223,-1.63675,-0.0280673,2.22049 +0.782974,0.51774198,-0.0060935402,1.83228 +-0.114747,-2.8677599,-0.095998101,1.67869 +-0.470548,-0.56840402,-0.164746,-1.3555501 +-0.306032,2.77965,-0.111448,-0.41195199 +0.65706497,1.69051,-0.63546097,-2.40012 +-0.43816099,-0.51159197,-0.106719,0.74167699 +-0.27559999,0.96647501,-0.13391601,1.1465501 +-0.192175,1.80651,-0.084748298,1.82366 +-0.86605102,-2.6739099,-0.115137,-2.4351001 +0.53349298,2.3982,-0.28541401,-0.72279 +0.53557199,1.04951,-0.13785601,-1.5734299 +0.578767,-2.43454,-0.270147,-1.42132 +0.19283,0.96283901,-0.30686301,-0.74091899 +0.47551599,-1.59723,-0.088514201,2.89274 +-0.93378901,1.46144,-0.021916701,0.54969501 +0.743321,1.75625,-0.072103299,-2.8459201 +0.47284701,1.45206,-0.34638199,0.46851799 +0.48996601,2.4739101,-0.136112,0.70731699 +-0.263257,-2.2772,-0.49384001,1.78618 +0.054276198,3.1177599,-0.26312199,2.0868199 +0.18253499,-0.57071298,-0.31611601,1.95986 +-0.152147,0.195559,-0.25879499,2.3231201 +-0.35598201,-2.58444,-0.012255,0.17591999 +-0.91841203,-2.8891699,-0.187838,2.56831 +0.218413,-2.23665,-0.185157,2.4135201 +0.90298998,-0.169525,-1.06917,1.6246001 +-0.584203,-1.36323,-0.035755899,2.55513 +0.054659098,-2.2430799,-0.193096,3.0647099 +-0.31323001,1.70656,-0.044941101,0.89319301 +-0.21799099,-0.41261801,-0.040510401,-2.7993801 +-0.105555,1.63703,-0.053791601,-1.7065901 +0.51850998,0.85437298,-0.060548201,2.37309 +0.46293399,-0.364409,-0.098559298,-2.00719 +-0.819727,2.31094,-0.068707399,1.89332 +-0.160089,-2.9317,-0.085543796,-2.78193 +0.55044901,0.067937203,-0.031385001,1.91631 +0.68563098,-0.85578799,-0.23616099,-3.1126001 +0.13039,2.2162099,-0.035427101,1.44868 +0.27056399,0.70448798,-0.097438499,-0.60683101 +-0.435765,-1.9536901,-0.25823501,-0.74073201 +-0.48881501,-2.4623699,-0.063080102,2.8480301 +-0.87851399,1.17428,-0.056382999,2.4599199 +0.39149401,2.0343299,-0.59066701,-1.30011 +-0.84316599,-0.531995,-0.21633901,-1.24138 +0.054984301,-0.40740001,-0.69638097,2.2535701 +-0.81484199,1.2868,-0.048059098,1.51627 +0.48539901,2.70204,-0.1213,-1.1855201 +0.43088701,0.31683201,-0.0501648,0.79310697 +-0.109879,2.60816,-0.144293,1.10461 +-0.33973601,-0.74686903,-0.15594199,-2.2091801 +-0.65643102,1.86734,-0.32837099,2.7861099 +-0.476275,-2.7290499,-0.0203178,2.90429 +-0.57857698,-1.89264,-0.021769799,0.94279802 +0.30792099,-2.00968,-0.301191,1.3231601 +-0.54226202,-1.25248,-0.20938,0.63311899 +0.53100097,-0.58561999,-0.245931,-2.8907001 +-0.113237,1.84993,-0.44724399,-2.8564899 +-0.263266,-1.48068,-0.081529498,-0.94286698 +-0.0374256,2.0786901,-0.40866199,0.36754999 +-0.368184,1.82177,-0.29940099,-2.1170399 +-0.77696502,-0.64101797,-0.218261,-2.3955801 +-0.98158598,2.64903,-0.056797799,0.94107598 +-0.85600299,-0.71793002,-0.0035042299,1.79316 +0.97706401,1.8648601,-0.19978,-0.81421 +-0.280265,0.222179,-0.095485598,0.61357599 +0.495141,-1.2177401,-0.28221601,0.59105802 +-0.174721,-1.42635,-0.062665798,-1.22838 +-0.92041498,1.62113,-0.0685862,0.4524 +-0.0682768,-2.1029201,-0.39319801,0.74845099 +-0.38235399,-1.55559,-0.036714401,-0.53766203 +0.119334,0.47134399,-0.26575801,-2.9713099 +0.72421199,-1.8818001,-0.049969502,2.4667799 +-0.29772699,1.36509,-0.201975,-1.03426 +0.37750801,3.0387499,-0.14088701,0.93613702 +0.966923,-0.72053099,-0.052802499,1.73683 +0.57715601,2.5475399,-0.28235599,1.01368 +0.718454,-3.0743501,-0.20272,0.69596797 +0.957551,-2.15587,-0.0116646,-0.323452 +0.57512599,-2.8359399,-0.46608299,0.52207202 +0.25545099,0.91260302,-0.18730199,-1.82893 +-0.209638,-1.25472,-0.199564,0.067932598 +0.996804,-0.30860499,-0.032010902,-2.47329 +0.87603301,0.443993,-0.53257102,0.54691899 +-0.66058803,1.47174,-0.31257099,2.8926599 +0.0091484599,0.94448501,-0.0554232,0.261554 +-0.56704402,-1.76016,-0.083519801,0.27636701 +0.82534701,-2.17875,-0.157626,-0.0257542 +-0.66452599,-0.566396,-0.065486498,0.35071701 +0.492706,0.46044999,-0.083189301,2.54214 +-0.81443501,1.68938,-0.94289303,2.2990401 +-0.79326302,2.25121,-0.070943803,2.1805899 +-0.90767998,-0.321648,-0.084159799,1.39932 +0.042967901,0.29194999,-0.13391399,-3.0778201 +0.088191003,0.123535,-0.0187348,1.58538 +0.58975601,2.2485299,-0.024089901,-2.4378099 +0.31933799,1.78028,-0.27300701,-1.70164 +-0.91447699,-2.0412199,-0.30012399,-2.5998299 +0.46415201,-0.404596,-0.0129809,0.90491301 +-0.33015901,1.50752,-0.50608599,2.34389 +0.26352599,0.185673,-0.62561399,-1.2204601 +-0.107854,-2.1687,-0.0130076,-1.96245 +0.54806799,2.9861,-0.146044,2.68066 +-0.27310601,0.55040503,-0.63504797,-1.26598 +-0.832816,1.75506,-0.35147601,-0.67901099 +-0.079438597,3.0520301,-0.027653599,-1.83798 +0.0189075,1.77686,-0.043238498,2.48052 +-0.84393501,-2.6641901,-0.0015989,0.83473098 +0.89047402,2.75124,-0.071414098,1.66804 +-0.0519282,1.33634,-0.39948699,0.37984699 +-0.33148399,-2.08462,-0.19675399,-1.65771 +0.151797,-1.94864,-0.0128584,0.725353 +0.97669899,-2.2636099,-0.0126921,0.44114101 +0.33465099,0.113521,-0.535653,2.7156701 +-0.38166299,-2.7612901,-0.107471,-1.8433 +-0.37232199,3.0332501,-0.062703297,2.4321499 +-0.81421101,-2.94648,-0.0417271,2.9755299 +-0.35565099,2.01507,-0.41049099,-2.1680701 +0.442247,0.48923501,-0.28323999,0.94802701 +0.13184801,-2.79685,-0.074645303,1.42531 +-0.33369699,1.49132,-0.080555901,-0.671534 +-0.75527698,1.0272,-0.45531201,2.3643999 +-0.66889101,2.0453701,-0.074831903,2.6779599 +-0.675942,-3.03145,-0.0308268,-0.397773 +0.47283101,0.76364303,-0.16079301,2.2698801 +0.52620298,-0.71464801,-0.0192375,1.16757 +0.90223002,2.6819999,-0.18527099,1.92056 +0.53934002,-1.48464,-0.041047402,-1.34778 +0.894499,2.9600699,-0.26808301,-1.39838 +-0.47942999,-1.5016201,-0.066346899,2.2046299 +-0.72370201,2.7712801,-0.098766297,2.7841401 +-0.37641999,2.5006499,-0.194144,0.226595 +0.410142,1.17582,-0.404612,-1.57552 +-0.38780501,-0.867715,-0.17151999,-2.7901399 +-0.210756,-0.66776699,-0.0292737,-0.212589 +-0.50134498,-1.01194,-0.219016,0.015812101 +0.543616,1.87321,-0.267784,2.28912 +0.55111301,2.62275,-0.13059799,2.5453801 +-0.157948,-1.6316,-0.0450541,2.1560099 +0.58454001,0.093162701,-0.089288697,0.043821201 +-0.052288301,0.97125697,-0.125982,-0.39943099 +-0.82993603,1.05709,-0.305105,1.67997 +0.41389,1.9383,-0.132732,-0.54196501 +0.0064336401,1.9230601,-0.0138704,2.3196101 +0.29461199,2.35466,-0.41363499,2.0358801 +-0.063907497,-0.151871,-0.0281894,-1.5687701 +-0.87945199,-0.66618299,-0.060414098,1.89214 +-0.321522,-2.3592501,-0.0049540801,-2.9531 +-0.89582503,-1.74291,-0.17243201,-1.28308 +-0.11174,-2.8815899,-0.171519,-2.9159701 +0.72475398,2.4216299,-0.079989403,2.0144899 +-0.682298,2.8984201,-0.170917,0.54947698 +0.72329497,0.46635601,-0.0203104,1.53606 +-0.86795503,0.89235401,-0.100121,-2.1303999 +-0.74122101,1.84407,-0.51161599,0.100258 +-0.49212801,-1.5448,-0.429214,-2.0251801 +0.0584254,-0.89878798,-0.37828299,-0.78521901 +0.34221601,1.06161,-0.249685,-0.472404 +0.152255,1.97384,-0.087476902,1.76524 +-0.61670899,1.99639,-0.179351,2.1523499 +0.57852203,-2.1721699,-0.039618101,-1.4147201 +-0.52140999,1.96974,-0.072096497,-1.72649 +-0.41906399,-0.56383598,-0.204244,-2.9586899 +-0.28989899,-2.70804,-0.26303899,0.544994 +0.247604,2.73739,-0.43589899,2.0924001 +0.68412,0.94446498,-0.90728402,-0.996261 +0.21201301,1.06846,-0.373633,2.0123799 +-0.81747299,0.139212,-0.386994,-1.30145 +0.60801399,0.4729,-0.184398,0.85652602 +-0.074233197,0.080012701,-0.0104939,2.51825 +-0.82095999,2.6997499,-0.29348099,2.6719899 +-0.72169602,0.80185902,-0.115206,1.32224 +0.204955,0.71508801,-0.097824499,2.83127 +0.66594601,0.43631199,-0.00429567,1.98794 +-0.0129736,2.5248699,-0.142851,0.17541599 +-0.343436,1.18784,-0.26345199,2.0123301 +-0.65888798,-2.2055099,-0.27815199,3.0746701 +0.60837102,-2.2361701,-0.00059686397,-2.63253 +-0.27316099,0.31493199,-0.054815199,-2.0336399 +-0.32526001,-2.9463301,-0.100106,0.98713601 +0.46341401,-0.97004098,-0.42999899,1.0478801 +0.0122437,-1.09431,-0.74861997,0.26591301 +0.108235,-2.83166,-0.0228831,-1.6438 +0.16628399,-2.4531801,-0.250741,-2.2293401 +0.044366099,2.4969499,-0.028025299,-0.45067099 +0.182432,0.731929,-0.095687702,0.64405203 +0.81429899,-2.0943201,-0.187966,1.4761 +-0.055750702,2.00985,-0.059980899,1.80056 +-0.52038199,3.1355901,-0.030033501,0.64481699 +0.62456799,2.1658599,-0.043098301,-2.7234399 +0.34336701,1.90932,-0.157497,1.37844 +-0.89243603,-1.14561,-0.22379699,1.5035501 +0.29816499,2.52492,-0.104725,-1.57568 +-0.86968702,2.1916599,-0.069956198,0.69585901 +0.236416,0.70990098,-0.073560499,1.42293 +-0.28035501,0.56345099,-0.122127,-2.36518 +0.86589003,-3.1175699,-0.066125102,-1.48887 +-0.39494401,-2.6661699,-0.093606703,-0.98608798 +0.41939899,0.838094,-0.124689,2.67554 +0.923549,-1.92998,-0.242882,1.63248 +-0.83168501,-2.4768901,-0.446596,-0.79846197 +0.3493,0.68765002,-0.108503,1.91685 +0.31837699,1.78633,-0.033220001,-1.7816 +-0.820728,-0.88532698,-0.212235,0.59827298 +0.053745501,0.38928199,-0.095968001,0.19233 +0.14479899,0.55965799,-0.172135,3.1129401 +0.088414699,1.30846,-0.25534901,-1.98137 +-0.21139801,3.1275699,-0.087421902,1.07876 +-0.67519403,0.348811,-0.240949,-1.34521 +0.88114601,-1.10414,-0.105293,-0.12004 +0.24731,-0.42672199,-0.56979197,-0.36177701 +0.54747099,0.034852501,-0.34427199,-1.8448499 +0.86124402,2.9251499,-0.0232068,-1.0206 +-0.828897,1.72589,-0.0040398198,-0.999946 +-0.48275799,0.092389703,-0.030760299,-0.59193403 +0.972444,2.3654699,-0.167337,2.1500399 +-0.64706397,0.75652999,-0.29558799,-0.76181 +-0.58725899,2.3027101,-0.0902991,0.120997 +0.86049902,-3.0290101,-0.55598998,-2.9179699 +0.82254601,-3.14118,-0.0489197,2.4152801 +0.833547,-0.0077484301,-0.087321103,-0.96203399 +0.29936501,2.99,-0.0036313999,2.0473599 +0.13260201,-1.57445,-0.355753,-1.58461 +0.99193501,-1.12273,-0.058403101,-2.18818 +-0.34652099,-0.88607502,-0.40761799,-2.2456601 +0.59271801,-1.90257,-0.103423,-0.53542298 +0.46307901,2.74705,-0.0425888,0.65440702 +0.314612,3.09266,-0.164698,-1.96978 +-0.81556898,1.34828,-0.24753299,0.31105 +0.47802499,-0.030292399,-0.304205,-2.5586901 +-0.0292565,3.0695601,-0.152596,2.40716 +-0.50801998,0.80306298,-0.109942,-0.492962 +0.80863798,-0.857301,-0.094506599,0.28115901 +0.26701301,-0.273958,-0.49688801,0.86615801 +0.91635603,1.12411,-0.199295,-0.083209299 +-0.78499597,2.5272901,-0.398287,-0.55606401 +0.144475,2.02373,-0.53532898,-0.346928 +-0.83948702,-0.699956,-0.158244,-0.19859301 +-0.35990199,-1.81397,-0.15861399,2.56598 +-0.65693998,1.00665,-0.110524,1.1620899 +0.61848998,-2.2093301,-0.083509304,-0.92762297 +-0.13564999,-0.32660499,-0.26302001,-0.16240001 +-0.342866,2.3383,-0.108819,1.93499 +-0.302715,-1.47223,-0.196574,0.75754702 +0.72578001,-0.81789702,-0.066064999,2.57581 +0.378573,-2.1940601,-0.11587,0.42115599 +-0.045469798,-2.9064,-0.110985,1.70841 +-0.64839298,-2.2901499,-0.0170072,-2.9405301 +-0.21247201,1.2559299,-0.052717201,1.55505 +0.234929,-2.8245699,-0.36984,-1.2679 +-0.78132999,-2.1856301,-0.17771199,0.38344401 +0.435947,1.27879,-0.056574602,1.25569 +-0.46678701,1.84062,-0.098453,0.618119 +0.82559001,-2.2237,-0.12555499,3.04984 +0.143537,2.4444499,-0.529594,-1.02463 +-0.57385302,2.5792899,-0.0084049599,2.9877999 +-0.81843698,0.23913699,-0.186763,-0.393424 +0.97450501,-0.79462999,-0.262878,0.55793101 +0.42565599,-0.61829102,-0.24171799,-1.38095 +-0.39333799,0.64393502,-0.0155013,-1.3222899 +-0.80028498,-1.22746,-0.0069100498,-2.23806 +-0.74785399,2.84358,-0.138515,-1.5398 +-0.2041,2.11408,-0.15930501,1.43452 +-0.20349801,1.57717,-0.22101501,1.53336 +0.41448301,2.30322,-0.243682,0.882173 +0.30141401,2.76454,-0.0093163,1.18174 +-0.876504,2.0190201,-0.0071677198,-1.38577 +-0.634776,1.23586,-0.18782599,-1.37556 +-0.64142501,1.88072,-0.070061401,2.95186 +-0.67102402,1.33058,-0.103632,1.081 +-0.640028,1.2978899,-0.177343,-2.6235001 +0.36746299,1.9220901,-0.00516142,-1.07726 +-0.346306,2.6544199,-0.016512601,-2.93647 +-0.405884,-0.61765099,-0.0134903,-2.6322801 +0.72176898,-1.41504,-0.130686,-0.26252201 +-0.97595,-1.77817,-0.052758101,-0.55561101 +0.49539801,-0.78350902,-0.432044,2.5424099 +-0.31983799,-2.23524,-0.032490399,-1.66678 +0.98705202,-1.21605,-0.017817,-0.336593 +-0.39175901,2.1314399,-0.248285,-1.8844301 +0.65884203,0.0084603997,-0.0185962,0.98137802 +-0.74066103,2.50757,-0.299759,-2.24123 +0.14562701,-2.6294999,-0.085023701,-0.99025899 +-0.95446098,1.1726,-0.0101492,2.4897699 +0.76848501,-0.452811,-0.0055215298,-2.2031 +0.42138401,-0.79336298,-0.0086763604,2.1411901 +-0.019927301,0.115078,-0.0287624,-1.72425 +0.714616,2.7349501,-0.216069,0.612867 +-0.89544302,1.09647,-0.136994,0.78070498 +-0.104343,-0.962852,-0.19145501,-1.2481 +0.30202001,2.5796499,-0.12528899,2.4283099 +-0.84679401,2.9446599,-0.124163,-2.1800001 +-0.54525399,0.657812,-0.037853401,0.77338099 +-0.67942703,-1.10536,-0.069353104,2.5194199 +0.63474298,1.60105,-0.0223256,0.71510297 +-0.74831802,-2.2060201,-0.158961,1.68799 +0.78990602,-1.00815,-0.71785802,-2.6609499 +0.065275699,-2.9649601,-0.40718299,0.020535801 +-0.40658399,-0.013265,-0.0067585902,-2.31759 +0.077518798,1.5396,-0.221083,-2.44171 +-0.72741199,1.1207,-0.41072699,-0.84351802 +-0.090525903,-2.9435599,-0.083301,2.54724 +0.19660699,1.47666,-0.095256001,-0.71850801 +0.242025,-2.15539,-0.121867,-1.14468 +0.91184998,1.1152101,-0.18021999,2.4028599 +0.27517501,0.55782098,-0.0765604,1.98797 +0.49315599,0.218456,-0.0637298,0.31514701 +-0.463797,0.0055524101,-0.242185,0.416583 +-0.067395099,1.2129101,-0.0266295,-3.13415 +-0.51937503,-1.33671,-0.280976,0.125623 +-0.51209199,2.1008601,-0.036610499,-2.7484901 +0.228366,2.3457799,-0.175879,-2.33371 +0.14961,-2.7969,-0.120971,0.192715 +0.438784,-2.6417999,-0.069117099,-2.8582101 +-0.961142,-2.98966,-0.259516,-2.2979801 +0.512963,-0.63621998,-0.052186199,-0.465105 +-0.25932401,-1.3135999,-0.113237,-2.21751 +0.106373,-2.11448,-0.0278011,-1.69857 +0.44914699,-1.51966,-0.0231499,-1.4276 +-0.40799701,3.0486901,-0.147439,0.79770398 +-0.22383299,2.3352699,-0.079993598,0.68986899 +-0.080438502,2.3319499,-0.022661701,-3.04321 +-0.95733798,1.02077,-0.42261201,-2.2209899 +0.52500999,2.69453,-0.0146172,-1.8264199 +-0.67330498,1.66865,-0.154309,-0.173012 +0.46223399,-1.39495,-0.432282,0.262068 +0.404607,-0.753272,-0.051165599,-2.0489399 +0.45067501,-0.464746,-0.128591,-1.2032599 +-0.71886498,-1.86396,-0.112239,-1.42501 +-0.46008301,-2.4730501,-0.236762,-2.42191 +-0.13122199,0.52603698,-0.0374921,0.55627698 +-0.93700498,-0.97142202,-0.0298148,2.50546 +0.61499399,-3.06024,-0.087773897,3.0451701 +0.73714101,1.47159,-0.0028798201,-0.93604302 +-0.76495302,2.671,-0.197422,0.27947101 +-0.81352699,-0.89922398,-0.035596799,2.7241399 +-0.35476899,1.67922,-0.122258,0.87107301 +0.0502913,1.2392401,-0.17656299,2.4675901 +0.66829097,1.06243,-0.0360808,3.0682199 +-0.31505001,1.0821199,-0.37291601,1.91466 +0.78984702,-1.76627,-0.036419298,2.37868 +-0.92176002,-2.56688,-0.0271929,1.92562 +-0.609954,-2.94889,-0.166061,2.75664 +0.80621201,-0.67005301,-0.033830099,-2.89466 +-0.0246349,0.101211,-0.094944201,-2.7674401 +-0.462109,1.6049401,-0.064277701,1.35894 +-0.32244301,0.75419003,-0.56590199,-0.338572 +-0.72798198,2.7681,-0.384424,-0.74679202 +-0.82363999,-1.99752,-0.53789002,1.1137201 +0.96712798,0.906304,-0.108299,-1.19961 +-0.58989,0.77392501,-0.43017399,-2.7606499 +0.26841199,1.7814,-0.19326299,2.0815201 +-0.093085296,0.335605,-0.102493,-2.7821 +0.91210598,2.85496,-0.0120372,1.88071 +-0.94185603,-1.63636,-0.074492499,2.6142001 +0.13380601,-1.5984401,-0.040451299,2.3473599 +-0.90365797,-1.42386,-0.45161599,3.02878 +-0.506809,-2.3744299,-0.29658699,-1.64771 +-0.518857,-2.4444201,-0.61698598,-1.64416 +0.27717599,-0.937181,-0.0827014,-0.19920599 +0.434241,-0.306714,-0.112241,-0.86506897 +0.964369,-0.51457,-0.50593001,-2.8799901 +0.58561301,1.44172,-0.155449,1.11595 +0.55628097,-1.69775,-0.116161,-1.88331 +-0.199323,1.93173,-0.13901,-1.66976 +-0.74305499,-0.61585802,-0.13481501,0.656115 +-0.928716,-0.39791,-0.044868499,-0.431283 +0.44949299,-1.06391,-0.14458799,0.072981901 +0.339627,-2.30018,-0.030601,-1.0968 +-0.10899,-2.6216099,-0.0046473402,3.0775299 +-0.72610402,2.40801,-0.129535,1.74208 +0.20232201,2.0968101,-0.171404,0.34533501 +0.076110996,-1.8671401,-0.118648,-0.78909397 +0.443892,2.30989,-0.31402901,0.77089798 +-0.246657,-1.82214,-0.38065001,-2.81249 +0.81782103,-1.53449,-0.231925,-0.80567098 +0.435186,-1.93664,-0.050021902,1.05642 +0.28603801,0.062803,-0.18568499,1.81372 +0.686575,-0.92251801,-0.0208205,-3.1408701 +-0.85943401,2.8261499,-0.081199899,1.85971 +0.354377,-1.86146,-0.053681102,3.06867 +0.378378,-0.97249597,-0.234295,1.06357 +-0.41951999,-1.1407599,-0.29184201,-3.0586801 +-0.421985,2.48083,-0.077180304,0.26099601 +0.57420599,-0.62446702,-0.169935,2.3443201 +0.0088943997,1.77782,-0.094946697,0.238911 +0.554326,0.34597701,-0.29163501,-0.068237796 +-0.54485101,-0.067015603,-0.52142602,2.66063 +0.55866301,-2.5673699,-0.0258459,-2.5943999 +-0.226037,3.1003599,-0.47605401,1.27053 +0.181005,1.59693,-0.026473301,-3.1296201 +-0.39709601,-2.3566599,-0.33619699,-0.18843301 +0.0780394,0.73698401,-0.032909501,-2.33692 +-0.72399998,2.9314799,-0.0075137801,-2.47122 +0.689677,-1.3871599,-0.099805199,-2.96821 +-0.98711699,2.3742099,-0.0261732,0.79454899 +-0.48487699,1.82304,-0.310754,-0.78629303 +-0.954988,-0.41248399,-0.25654101,1.38141 +-0.435525,-0.70710498,-0.10444,2.77723 +0.51801002,-2.1927099,-0.148619,-1.25304 +-0.0338981,-2.8577499,-0.180739,-2.2289801 +0.68361002,0.70118999,-0.122774,0.369037 +-0.979231,-1.83109,-0.0272261,2.85497 +0.55831301,0.65158701,-0.086304799,-1.15581 +0.476706,1.44074,-0.20348001,-1.12372 +0.165015,0.67456698,-0.098370999,-1.80777 +0.97759902,1.23488,-0.192072,0.90175301 +0.50106502,-1.79914,-0.099759102,-1.74564 +0.62280703,-2.46668,-0.0077179698,0.81734502 +-0.0128846,-1.30814,-0.042338599,0.69458902 +-0.46163499,-1.84629,-0.154318,-0.176875 +0.90197301,-1.45636,-0.022048101,-0.93272501 +-0.32185,2.73136,-0.153605,3.0262499 +-0.85113901,2.09727,-0.0584969,0.631679 +0.074066199,0.98718202,-0.0587635,0.77849001 +-0.68435502,0.0406061,-0.0180861,0.64056098 +-0.63609701,1.58755,-0.00547102,2.1199801 +-0.392461,1.78607,-0.039437599,-1.88728 +-0.686333,0.66030598,-0.182074,0.53193003 +0.286226,-1.33447,-0.192996,-2.80142 +0.78596598,-0.0622687,-0.107076,1.80634 +0.963193,1.02695,-0.22710501,-1.0415699 +0.98263401,-2.57623,-0.0098855896,-0.37413701 +-0.19845299,2.7827301,-0.111045,-0.40862399 +0.323737,-1.57435,-0.121622,1.40057 +0.86687601,2.7896399,-0.180323,-1.2186199 +-0.45127299,0.43722099,-0.094364099,-1.92089 +-0.30705801,-1.40712,-0.107193,1.82344 +0.83803302,-0.74067599,-0.216379,-3.09199 +-0.370352,2.5332301,-0.23518801,-2.7727699 +0.021561701,0.96195602,-0.092007898,-1.87247 +-0.68964303,-1.88673,-0.0136905,-1.6241 +-0.96346098,-0.82664597,-0.211218,0.77217603 +0.41414401,-0.215564,-0.040834598,-1.7305 +-0.84885699,0.070681602,-0.29169101,-2.0832901 +0.87205601,0.90887398,-0.12931199,1.83152 +-0.67276502,2.9279301,-0.064764,2.30475 +0.88273501,0.151088,-0.0793764,2.4937401 +0.150076,-0.72835201,-0.020020399,0.0180769 +0.56562001,2.53953,-0.0144355,-2.07039 +-0.390306,-1.3841,-0.355786,-0.055974599 +0.28939301,2.8580301,-0.071004704,2.4078 +-0.0148982,0.428195,-0.157242,-1.11572 +0.89004898,2.03895,-0.22330099,1.85276 +-0.96261698,2.8985,-0.169652,1.47361 +0.61670798,-0.95980698,-0.0195219,1.4449199 +-0.77848297,-2.90221,-0.16074599,0.81790298 +0.70127201,-2.50036,-0.18435299,1.00433 +0.201251,-2.9655199,-0.095115401,1.62012 +-0.0256347,0.88608801,-0.033721201,1.92336 +0.32262999,-0.38898399,-0.14485601,1.36401 +0.71021003,0.0316935,-0.293185,0.677522 +-0.82690001,2.6092899,-0.47527301,-1.30316 +-0.57317901,-2.5713699,-0.42128301,0.86824602 +0.487764,2.45311,-0.41683099,2.0827601 +-0.996764,1.27789,-0.0091820098,-3.0013199 +0.64347303,0.35351101,-0.34540799,1.90976 +-0.0569476,-3.0499201,-0.205064,-2.53564 +-0.381194,2.8789501,-0.230837,-0.48045 +0.91282302,2.66501,-0.26310199,-0.32241699 +-0.53657699,-1.52757,-0.26467901,0.258977 +0.44690299,1.0664001,-0.14248601,-2.1324301 +-0.36888,2.69525,-0.207481,1.47256 +0.62291598,1.79397,-0.45492399,-0.208869 +0.73095101,-0.66235799,-0.111082,-0.93642002 +0.162312,-1.1844,-0.123222,-3.03637 +-0.79560697,-3.1241,-0.0150145,0.0311333 +-0.80445898,-1.79176,-0.018774001,-1.0403 +-0.135452,0.87743902,-0.0159918,2.02772 +0.265746,0.185367,-0.108794,-0.83610398 +-0.62050903,0.70310903,-0.035746802,-0.71723503 +0.177635,-2.8412299,-0.0146764,0.084858596 +0.53919101,-1.58259,-0.103061,-1.00876 +-0.057062998,-0.52297699,-0.53822899,-2.7507 +0.16648699,2.25999,-0.150658,1.04566 +0.293984,2.6026199,-0.135013,1.60377 +0.59435898,-2.1189401,-0.13158099,2.34782 +0.83429801,-1.0048,-0.144776,0.153842 +-0.297984,-2.17416,-0.074130103,2.7711301 +-0.44058901,0.57834798,-0.111898,-1.7631201 +-0.72442001,-2.76878,-0.113263,0.379796 +-0.46830699,1.94524,-0.081186399,-2.5074799 +0.70060802,-2.89698,-0.067450099,1.1835901 +-0.80945498,-0.282235,-0.00071812997,-2.0911 +-0.75967097,-1.89105,-0.0133899,3.1332901 +0.83216101,0.69922203,-0.47887099,2.37481 +0.0655628,0.45296299,-0.13352799,-1.86711 +0.36024699,-0.581469,-0.28442001,-1.0352 +-0.72795999,-2.7846701,-0.13041,-2.7924099 +0.54848403,2.6984,-0.22044,-1.46056 +0.165787,0.77376699,-0.0065693501,0.96870703 +-0.97052199,2.8847101,-0.170891,1.89446 +0.80793101,2.3812399,-0.181363,-2.7632201 +-0.780568,-2.9108801,-0.0108179,-0.213246 +0.313095,2.8673699,-0.41025299,0.384267 +0.431191,-3.0158999,-0.0356698,2.44221 +0.21685299,-1.66796,-0.36056501,-2.5436299 +0.200848,2.43256,-0.40718701,-1.17541 +-0.205708,0.58201402,-0.059357401,-0.64304698 +-0.63377601,-0.45260701,-0.0030332699,-1.55918 +0.72294199,2.7846999,-0.1336,2.50792 +-0.114385,-0.80667901,-0.099202901,-1.85947 +-0.87096202,-2.2018099,-0.190034,-2.85567 +-0.47543001,-0.41877201,-0.32220101,-0.94891697 +-0.0148054,3.0750201,-1.10884,-0.485466 +-0.79392999,1.87072,-0.0288,1.73347 +-0.54905599,3.01508,-0.0129362,-0.052656598 +-0.75133401,-1.5227,-0.30640799,-0.0214836 +-0.072562598,1.87771,-0.079759203,-1.4636 +-0.99963999,-1.02447,-0.36765599,2.1607699 +-0.178056,-0.23022699,-0.114708,-0.038190302 +0.091099598,-2.8401301,-0.0479974,2.53269 +-0.97714603,-2.8575101,-0.211243,1.86519 +0.984326,0.95106298,-0.038801901,-3.1326499 +-0.105857,2.60831,-0.28057301,0.350146 +-0.85815001,1.08076,-0.79543799,2.45349 +0.017208399,-0.125232,-0.032590799,-0.086546302 +0.875489,0.36689299,-0.041791402,-0.054380301 +-0.12932,-2.28772,-0.0036076801,0.61375803 +-0.057938099,0.185013,-0.0135274,-1.97803 +-0.00919744,1.46881,-0.210309,-0.87409401 +0.973454,-2.9410999,-0.428045,2.3073399 +-0.510162,2.90604,-0.230882,0.49953401 +0.78098798,-0.67632997,-0.028791299,2.2834599 +0.046148099,0.12503999,-0.063760102,2.5915201 +-0.80584401,-2.5669401,-0.158346,-1.25222 +-0.039570998,-0.79641002,-0.118784,0.78940099 +-0.92330402,2.2234399,-0.103314,0.51684099 +-0.75895101,1.82058,-0.22737899,1.80423 +0.38439301,0.89299297,-0.344796,-0.075130202 +-0.72578198,2.62485,-0.16850799,-1.84698 +-0.421691,-0.044934101,-0.038631499,0.93075198 +-0.33683401,-2.69151,-0.201259,0.38433799 +-0.57255298,-0.349774,-0.13337301,-2.4633701 +0.68823898,-0.261448,-0.092921101,-1.29969 +0.336097,3.0006399,-0.141002,0.811786 +-0.89597899,1.6842901,-0.263372,-0.50764799 +0.82089102,-1.4643,-0.0037809401,2.89376 +0.0535505,-2.2046599,-0.021043099,-1.0575401 +0.54293299,-0.0142107,-0.0244634,-0.22926299 +-0.62536001,1.74377,-0.18372101,2.1257999 +0.49492699,1.1269701,-0.038748,-0.624654 +-0.539913,-1.41088,-0.185854,0.79879701 +0.265156,1.6561,-0.0139804,-1.12974 +-0.0594186,2.8224199,-0.155911,2.5534 +-0.098381802,-2.0167999,-0.038231801,-2.2351301 +-0.54730701,-2.49455,-0.0303546,-1.70069 +0.57011199,0.621692,-0.106872,0.66385698 +0.58624703,-0.72861499,-0.12826601,0.57967001 +0.80919898,1.73579,-0.22757,-2.42732 +0.87223703,-2.90646,-0.073807903,0.0046104798 +0.71704,0.75681102,-0.20264401,-2.71241 +0.642501,-2.89048,-0.071440198,-1.02267 +-0.57559502,2.6380501,-0.10181,0.80505699 +-0.382393,3.01476,-0.20412301,-0.64610398 +0.38408399,1.72569,-0.0722517,3.0027201 +-0.81551701,-0.16330799,-0.0507247,0.591452 +-0.82927901,2.7455101,-0.31038201,-1.05673 +-0.058385201,-1.2431999,-0.256863,-2.7422199 +-0.989959,1.5053999,-0.0113118,-0.465617 +-0.49849099,-0.78602201,-0.218776,1.35072 +0.207093,3.1073599,-0.067890003,-1.63336 +0.29915899,-0.56590199,-0.14682101,-1.81631 +-0.58268797,2.5269899,-0.0140968,-1.38791 +0.0172041,-2.75861,-0.074976601,1.53624 +-0.38608599,-0.68376398,-0.0069083199,0.72116601 +-0.52798301,1.00065,-0.15365499,-0.239848 +-0.82548797,-0.577003,-0.227165,2.9874301 +0.28072801,-0.96973902,-0.346203,-2.0966899 +-0.35174799,2.55337,-0.745336,0.84897101 +-0.85510403,2.26228,-0.26651701,0.00372702 +0.19238999,1.6393501,-0.28107801,-1.13713 +-0.41926199,-1.33397,-0.0070285401,1.25527 +-0.38893101,2.2225101,-0.245876,1.44525 +-0.4039,1.14457,-0.35194999,-2.5035701 +-0.48087201,2.46245,-0.0132983,2.6314399 +0.60534,-1.09874,-0.100298,1.4381 +-0.53654897,-0.98800302,-0.051356599,-0.032684501 +0.87978101,0.522457,-0.061034799,-0.94099402 +0.99132299,-0.97647202,-0.206264,-2.6951499 +0.90671802,-2.5538099,-0.0061174599,-2.7982199 +0.32999,-0.0315133,-0.37155601,-2.3827901 +-0.69939297,0.63258302,-0.12577701,1.99147 +-0.428417,-2.1059401,-0.032704301,-2.46065 +0.0527661,2.54985,-0.036598399,2.22542 +-0.38688999,1.42256,-0.049855102,-2.54494 +0.0083825802,-0.25165999,-0.0492591,2.9641199 +-0.63763601,1.76747,-0.262344,0.083767802 +-0.84522599,1.99594,-0.029588601,0.123344 +0.166627,2.14536,-0.144804,-1.9379801 +0.71706599,-0.53162903,-0.055730999,-0.81347102 +0.91689003,-0.237492,-0.090303898,2.6765599 +0.838072,-1.85166,-0.040661398,1.01539 +0.387701,3.0116899,-0.21169101,1.69511 +-0.475701,-1.7765,-0.167484,0.079803102 +0.94689399,-2.31848,-0.078999899,-1.62672 +0.0814448,-1.08516,-0.0424507,-3.0878301 +-0.48073599,-0.16506401,-0.57600403,-0.51719803 +0.99267101,0.99033803,-0.0120568,-0.27679601 +-0.98359901,1.37068,-0.035814099,-2.4765401 +-0.58163798,3.0231099,-0.192734,-2.2936599 +-0.187764,-3.0327101,-0.043839,-2.2700601 +-0.118109,1.4030401,-0.27504,-2.2102101 +-0.64843398,-0.935211,-0.701334,-0.62495399 +0.83983201,1.09443,-0.083728403,0.069653399 +-0.976152,-3.0260401,-0.022496499,3.11867 +-0.39959201,2.8506801,-0.19702099,-2.10672 +0.108327,2.6296401,-0.0127162,1.1538301 +0.13191301,0.0662008,-0.043028999,1.41286 +-0.84662497,-0.324283,-0.0159839,1.81367 +0.122163,2.53597,-0.039566599,-1.44753 +0.48359501,-2.72489,-0.062857904,1.08696 +0.059282798,-1.4593101,-0.149042,-2.0870299 +-0.84831601,1.19891,-0.162724,-1.82827 +-0.39687699,-2.0301001,-0.30999401,-1.4063801 +0.316223,0.37006199,-0.0222764,-1.73981 +-0.41658801,-0.092106797,-0.47412699,-1.59516 +-0.75352401,0.89142299,-0.241331,0.39951599 +-0.150527,-0.67349303,-0.117468,2.4084499 +-0.46898401,-0.79227501,-0.74415702,2.36443 +0.984249,-0.89751399,-0.110024,-0.162966 +0.67219698,0.88489002,-0.0120887,1.86333 +0.93870699,-2.50507,-0.021518299,-0.13175701 +-0.242203,1.47859,-0.050842501,-2.49436 +-0.97533202,-2.59624,-0.29636899,1.75489 +0.698695,2.3815501,-0.370821,1.5704 +0.129702,-0.74735498,-0.106381,-2.06989 +-0.070041403,-1.30858,-0.488377,3.14042 +-0.50981301,-1.81569,-0.046666998,-1.1559401 +0.57813603,-2.4942,-0.047746498,1.86401 +0.79004401,3.06675,-0.12543599,0.031721801 +0.85682702,-0.64385402,-0.336092,-0.055308301 +-0.63010401,1.56907,-0.127727,-0.41472101 +-0.80338401,-1.9341201,-0.69472402,-1.9805599 +0.80845398,0.58968002,-0.016083101,-1.49721 +0.696459,2.26263,-0.30068699,-2.3536601 +-0.86994201,2.0451701,-0.25586799,0.096409902 +0.82658798,-1.19374,-0.0103106,-1.75315 +-0.70902199,-1.1047601,-0.016269,-0.44325 +-0.23558,0.65101999,-0.028314799,0.13338301 +-0.322698,2.64587,-0.12590601,1.40161 +0.609797,-0.32178801,-0.0272143,1.67686 +0.75334102,-2.85063,-0.037213299,0.59059399 +-0.074637003,-1.71874,-0.016176799,-0.981655 +0.84793103,-0.23910999,-0.059290301,-0.26919499 +0.78392601,2.1859801,-0.0079653403,-1.9639601 +-0.98925602,2.9312799,-0.117123,0.57296503 +0.64082801,2.25632,-0.064630002,0.230598 +-0.112495,-2.4846101,-0.23371799,-2.4616101 +-0.286369,-2.3476,-0.217785,-0.547221 +-0.090531103,-0.0112185,-0.0687396,-1.14123 +0.35484999,-1.84851,-0.0149395,1.5775 +0.452207,1.29972,-0.0979679,1.74552 +-0.491761,0.51837701,-0.27895799,0.99485999 +-0.777327,-2.07269,-0.0047252099,1.72157 +0.73836899,-1.34455,-0.15794501,2.44999 +-0.00558426,2.43331,-0.178463,0.91527897 +0.430794,-1.02948,-0.049169101,3.1008899 +-0.34621501,2.3139701,-0.0714757,-1.33664 +-0.330966,1.57174,-0.50592399,-2.9632599 +0.4174,1.238,-0.33004001,-0.17289101 +0.78995103,0.29717201,-0.0304759,1.8607 +-0.63482702,-0.75511098,-0.024574401,1.89844 +-0.77236801,-0.213631,-0.23984,0.317577 +0.024341401,2.6884201,-0.12972599,1.6993901 +-0.87495899,0.181416,-0.0246417,2.5747499 +0.39244601,-0.62833297,-0.155827,2.68068 +-0.453877,-0.67193598,-0.112748,-0.340725 +-0.635813,-2.2425699,-0.0138162,1.98853 +0.27632701,3.0548201,-0.00245194,-1.72277 +-0.217513,0.0160676,-0.131358,-2.75771 +0.85504001,0.230526,-0.074382499,-3.01566 +-0.116115,2.9028201,-0.107946,-2.1340101 +0.64903498,-0.32408401,-0.15063401,2.3754499 +0.322292,0.46188301,-0.0109982,-1.69558 +-0.485021,-2.1496201,-0.35716999,-0.64873397 +0.461312,-0.57120198,-0.169504,-2.0922401 +-0.0608637,2.57951,-0.108467,1.35852 +-0.50675303,-1.68291,-0.27885699,-3.0371301 +-0.32319,2.8849001,-0.039093498,1.46306 +0.27964899,-1.17163,-0.157416,-0.99904501 +-0.63743198,-0.94763201,-0.0365921,-2.1100099 +0.63474298,-1.40734,-0.536017,-1.34804 +0.094384797,-2.0809801,-0.111004,-2.2117 +-0.51375997,-0.74844801,-0.46942699,2.9777801 +0.50111902,-0.888129,-0.0093382597,-1.95459 +0.98829699,1.04196,-0.095278397,2.87186 +0.51818198,-0.83454001,-0.34452501,-2.8677101 +-0.838507,-2.2869999,-0.112247,2.5487001 +0.189144,2.60044,-0.035292301,0.947631 +-0.63437003,2.4962399,-0.0074101598,1.68056 +0.548329,0.084907398,-0.0574928,-0.25878799 +-0.76490301,-3.00177,-0.179563,2.2230599 +0.62849897,1.27343,-0.066274703,-2.5943301 +-0.18860701,-1.6104,-0.081771001,2.4568999 +0.96102202,-1.51928,-0.70319098,2.60783 +-0.2807,0.391307,-0.090040497,0.67146999 +-0.57447201,-2.32778,-0.182529,-0.375994 +-0.34651101,0.78776598,-0.062208999,-1.3776799 +0.38524401,0.26317599,-0.221642,-1.54842 +-0.096877597,2.1979799,-0.15668,-1.9898 +0.59825999,-1.55545,-0.81674802,0.98978698 +0.61519301,-0.194185,-0.19865,3.0936201 +-0.14257801,3.1353199,-0.039424401,2.5805199 +0.49486199,-2.5487499,-0.238428,-2.5125101 +0.895787,1.2405,-0.019871101,-2.0237899 +-0.712677,-2.19999,-0.33174101,1.92835 +0.51293999,-1.02763,-0.079834104,-2.802 +-0.97562301,2.2744701,-0.091424398,0.217663 +0.965738,-1.6349,-0.20706099,1.11973 +-0.94155401,1.65693,-0.068596102,1.1842 +0.79727799,1.00959,-0.087378703,0.653319 +-0.076539502,0.74279898,-0.15243199,0.393693 +0.706514,0.197203,-0.134698,2.0004799 +0.39131999,0.35173899,-0.046908401,-2.28548 +0.630898,2.3793099,-0.15730099,-0.60780501 +0.43414,-2.85497,-0.13162699,-0.47292799 +0.99406201,2.8062301,-0.168853,-0.220842 +-0.86972302,-1.8821501,-0.092742898,-2.69437 +-0.228439,3.0046,-0.135195,2.7244101 +-0.080611698,0.434843,-0.027139001,0.51845902 +0.74902099,0.76959503,-0.132425,2.57423 +-0.79628998,1.80066,-0.32723901,-0.64019299 +-0.15898,-1.49825,-0.0137571,-0.86946303 +0.34289101,0.101966,-0.106202,0.81862098 +-0.055807699,1.39398,-0.36605701,-2.96545 +0.968391,-0.53004599,-0.12754001,3.02948 +-0.717565,-1.48437,-0.103096,1.05075 +-0.28424501,2.0650499,-0.239474,2.4470401 +0.86731303,2.15346,-0.59479702,-2.0687399 +-0.095879398,0.68311602,-0.0033609299,1.67105 +-0.176258,-2.99891,-0.039985299,0.22351199 +-0.82398498,2.5931101,-0.57903498,-2.23406 +0.54066598,-0.45227,-0.14337701,-1.05795 +0.35476801,-2.3404601,-0.077814601,0.602862 +0.59986502,0.102147,-0.71077102,-1.23579 +0.94584203,1.1258301,-0.24815699,-0.40469199 +0.49655399,0.276739,-0.019673301,1.8343101 +0.370839,-2.61376,-0.019207001,0.79640001 +-0.139285,-2.6046,-0.00294318,-1.33129 +0.771626,-2.5619299,-0.079561301,-2.80637 +-0.54008901,-0.90728801,-0.075931899,-0.477198 +0.955459,-2.40361,-0.335017,-1.74196 diff --git a/tests/data/pyfit/rho/testRHO.py b/tests/data/pyfit/rho/testRHO.py new file mode 100644 index 00000000..508a4084 --- /dev/null +++ b/tests/data/pyfit/rho/testRHO.py @@ -0,0 +1,32 @@ +import numpy + + +def processing_function(the_array,the_params): + if isinstance(the_params, dict) and 'A1' in the_params: + return actual_function(the_array, the_params) + elif isinstance(the_params, numpy.ndarray): + params = { + "A1": the_params[0], + "A2": the_params[1] + } + return actual_function(the_array, params) + else: + raise ValueError("Recieved unknown %s" % the_params) + +def actual_function(the_array, the_params): + wConst= the_params['A1'] + polar = the_params['A2'] + B= 6. + + theta = numpy.arccos(the_array["ctheta"]) + values = wConst*numpy.exp(B*the_array["tM"])*numpy.sin(theta)**2.*(1+polar*numpy.cos(2*the_array["psi"])) + return values + + +def setup_function(): + pass + + +def prior_function(x): + y = numpy.array([5000.*x[0], x[1]]) + return y diff --git a/tests/data/source_files/functions_without_math.py b/tests/data/source_files/functions_without_math.py new file mode 100644 index 00000000..12e6060d --- /dev/null +++ b/tests/data/source_files/functions_without_math.py @@ -0,0 +1,6 @@ +def processing(values, parameters): + return True + + +def setup(): + return True diff --git a/tests/data/source_files/simple_option_object.py b/tests/data/source_files/simple_option_object.py new file mode 100644 index 00000000..84fde8e1 --- /dev/null +++ b/tests/data/source_files/simple_option_object.py @@ -0,0 +1,35 @@ +from PyPWA.core.configurator import options + + +class SimpleOptions(options.Plugin): + plugin_name = "SimpleOptions" + default_options = { + "Option1": "item 1", + "Option2": 3, + "Option3": "A string value" + } + + option_difficulties = { + "Option1": options.Levels.REQUIRED, + "Option2": options.Levels.OPTIONAL, + "Option3": options.Levels.ADVANCED + } + + option_types = { + "Option1": ["item1", "item2", "item3"], + "Option2": int, + "Option3": str + } + + module_comment = "A Simple test plugin" + option_comments = { + "Option1": "A specific item, predefined", + "Option2": "Any integer", + "Option3": "Anything as a string" + } + + defined_function = None + + setup = options.Setup + provides = options.Types.SKIP + diff --git a/tests/data/source_files/simple_prior.py b/tests/data/source_files/simple_prior.py new file mode 100644 index 00000000..80baa013 --- /dev/null +++ b/tests/data/source_files/simple_prior.py @@ -0,0 +1,2 @@ +def prior(x): + return x diff --git a/tests/data/test_docs/configuration.yml b/tests/data/test_docs/configuration.yml new file mode 100644 index 00000000..de349306 --- /dev/null +++ b/tests/data/test_docs/configuration.yml @@ -0,0 +1,29 @@ +buitin parse: + enable cache: true +Builtin Multiprocessing: + number of processes: 4 +miniut: + parameters: + - O1 + - O2 + - O3 + - O4 + - O5 + setttings: { + 'O1':6E+8, 'fix_O1':True, 'error_O1':0.1, 'limit_O1':[0,10.E+12], + 'O2':0.3, 'fix_O2':True, 'error_O2':0.01, + 'O3':-0.1, 'fix_O3':True, 'error_O3':0.01, + 'O4':-0.1, 'fix_O4':True, 'error_O4':0.01, + 'O5':0.1, 'fix_O5':False, 'error_O5':0.01, 'limit_O5':[-15.,10.] + } + stratigy: 1 +General Fitting: + likelihoodtype: Chi Squared + generated length: + function location: test.py + process name: weighting + setup name: setup_fortran + qfactors location: + datas location: kvars.csv + accepted montecarlo location: + savename: output diff --git a/tests/builtin_plugins/data/builtin/test_docs/gamp_test_data.gamp b/tests/data/test_docs/gamp_test_data.gamp similarity index 100% rename from tests/builtin_plugins/data/builtin/test_docs/gamp_test_data.gamp rename to tests/data/test_docs/gamp_test_data.gamp diff --git a/tests/builtin_plugins/data/builtin/test_docs/kv_bool_test_data.txt b/tests/data/test_docs/kv_bool_test_data.txt similarity index 100% rename from tests/builtin_plugins/data/builtin/test_docs/kv_bool_test_data.txt rename to tests/data/test_docs/kv_bool_test_data.txt diff --git a/tests/builtin_plugins/data/builtin/test_docs/kv_floats_test_data.txt b/tests/data/test_docs/kv_floats_test_data.txt similarity index 100% rename from tests/builtin_plugins/data/builtin/test_docs/kv_floats_test_data.txt rename to tests/data/test_docs/kv_floats_test_data.txt diff --git a/tests/builtin_plugins/data/builtin/test_docs/kv_test_data.txt b/tests/data/test_docs/kv_test_data.txt similarity index 100% rename from tests/builtin_plugins/data/builtin/test_docs/kv_test_data.txt rename to tests/data/test_docs/kv_test_data.txt diff --git a/tests/builtin_plugins/data/builtin/test_docs/noise_test_data b/tests/data/test_docs/noise_test_data similarity index 100% rename from tests/builtin_plugins/data/builtin/test_docs/noise_test_data rename to tests/data/test_docs/noise_test_data diff --git a/tests/builtin_plugins/data/builtin/test_docs/sv_test_data.csv b/tests/data/test_docs/sv_test_data.csv similarity index 100% rename from tests/builtin_plugins/data/builtin/test_docs/sv_test_data.csv rename to tests/data/test_docs/sv_test_data.csv diff --git a/tests/builtin_plugins/data/builtin/test_docs/sv_test_data.tsv b/tests/data/test_docs/sv_test_data.tsv similarity index 100% rename from tests/builtin_plugins/data/builtin/test_docs/sv_test_data.tsv rename to tests/data/test_docs/sv_test_data.tsv diff --git a/tests/builtin_plugins/data/builtin/test_docs/sv_test_data_bad.csv b/tests/data/test_docs/sv_test_data_bad.csv similarity index 100% rename from tests/builtin_plugins/data/builtin/test_docs/sv_test_data_bad.csv rename to tests/data/test_docs/sv_test_data_bad.csv diff --git a/tests/entries/test_configurator.py b/tests/entries/test_configurator.py new file mode 100644 index 00000000..4d5ca13b --- /dev/null +++ b/tests/entries/test_configurator.py @@ -0,0 +1,54 @@ +import pytest + +from PyPWA.entries import configurator + + +class StartCalled(Exception): + pass + + +class MockStartProgram(object): + + def start(self, configuration): + assert "description" in configuration + assert "main" in configuration + assert "main name" in configuration + assert "extras" in configuration + if "main options" in configuration: + assert isinstance(configuration["main options"], dict) + raise StartCalled + + +@pytest.fixture() +def mock_start_program(monkeypatch): + monkeypatch.setattr(configurator, "initializer", MockStartProgram()) + + +def test_py_fit_entry(mock_start_program): + with pytest.raises(StartCalled): + configurator.py_fit() + + +def test_likelihood_fit_entry(mock_start_program): + with pytest.raises(StartCalled): + configurator.likelihood_fit() + + +def test_chi_squared_fit_entry(mock_start_program): + with pytest.raises(StartCalled): + configurator.chi_squared_fit() + + +def test_py_simulate_entry(mock_start_program): + with pytest.raises(StartCalled): + configurator.py_simulate() + + +def test_generate_intensities_entry(mock_start_program): + with pytest.raises(StartCalled): + configurator.generate_intensities() + + +def test_generate_weights_entry(mock_start_program): + with pytest.raises(StartCalled): + configurator.generate_weights() diff --git a/tests/shell/pyfit/test_pyfit_interfaces.py b/tests/shell/pyfit/test_pyfit_interfaces.py new file mode 100644 index 00000000..b6f3366c --- /dev/null +++ b/tests/shell/pyfit/test_pyfit_interfaces.py @@ -0,0 +1,40 @@ +import pytest + +from PyPWA.shell.pyfit import interfaces + + +class WasCalled(Exception): + pass + + +def processing(): + pass + + +def startup(): + raise WasCalled + + +@pytest.fixture +def likelihood(): + return interfaces.Likelihood(startup) + + +@pytest.fixture +def setup(): + return interfaces.Setup() + + +def test_setup_function_is_passed_to_likelihood(likelihood): + with pytest.raises(WasCalled): + likelihood.setup() + + +def test_process_raises_not_implemented_error(likelihood): + with pytest.raises(NotImplementedError): + likelihood.process("Some lovely data for a lovely process.") + + +def test_setup_interface_raises_not_implemented_error(setup): + with pytest.raises(NotImplementedError): + setup.setup_likelihood("data", "functions") diff --git a/tests/shell/pyfit/test_pyfit_process_interface.py b/tests/shell/pyfit/test_pyfit_process_interface.py new file mode 100644 index 00000000..8e3dd70d --- /dev/null +++ b/tests/shell/pyfit/test_pyfit_process_interface.py @@ -0,0 +1,31 @@ +import pytest + +import logging +import time + +from PyPWA.shell.pyfit import _process_interface + + +@pytest.fixture() +def override_logging_effective_level(monkeypatch): + # Output is disabled if level is greater than warning. + monkeypatch.setattr( + logging.getLogger(), "isEnabledFor", lambda x: False + ) + + +@pytest.fixture() +def output_thread(override_logging_effective_level): + return _process_interface._ThreadInterface() + + +def test_small_output(output_thread): + output_thread.start(None) + time.sleep(2) + output_thread.stop() + + +def test_full_output(output_thread): + output_thread.start(1.2233) + time.sleep(2) + output_thread.stop() diff --git a/tests/shell/test_loaders.py b/tests/shell/test_loaders.py new file mode 100644 index 00000000..caf591e1 --- /dev/null +++ b/tests/shell/test_loaders.py @@ -0,0 +1,136 @@ +import os + +import numpy +import pytest + +from PyPWA.builtin_plugins.data import memory +from PyPWA.shell import loaders + +DATA = os.path.join( + os.path.dirname(__file__), "../data/pyfit/data/data.csv" +) + +INTERNAL_NAMES = os.path.join( + os.path.dirname(__file__), "../data/pyfit/data/internal_names.csv" +) + +INTERNAL_NAMES_DICT = { + "quality factor": "qf", + "binned data": "bn", + "event errors": "err", + "expected values": "exp" +} + +QFACTOR = os.path.join( + os.path.dirname(__file__), "../data/pyfit/data/qfactor.txt" +) + +MONTE_CARLO = os.path.join( + os.path.dirname(__file__), "../data/pyfit/data/monte_carlo.csv" +) + +PARSER = memory.Memory(False, True) + +FUNCTIONS_FOR_TEST = os.path.join( + os.path.dirname(__file__), + "../data/source_files/functions_without_math.py" +) + + +@pytest.fixture +def data_with_qfactor(): + loader = loaders.DataLoading( + PARSER, DATA, qfactor=QFACTOR, monte_carlo=MONTE_CARLO + ) + return loader + + +@pytest.fixture +def data_without_qfactor(): + loader = loaders.DataLoading(PARSER, DATA, monte_carlo=MONTE_CARLO) + return loader + + +@pytest.fixture +def data_without_extra(): + loader = loaders.DataLoading(PARSER, MONTE_CARLO) + return loader + + +@pytest.fixture +def data_with_internal_names(): + loader = loaders.DataLoading(PARSER, INTERNAL_NAMES, INTERNAL_NAMES_DICT) + return loader + + +def test_qfactor_sum_embedded(data_without_qfactor): + assert numpy.sum(data_without_qfactor.qfactor) == 9.1540205293413841 + + +def test_qfactor_sum_file(data_with_qfactor): + assert numpy.sum(data_with_qfactor.qfactor) == 10.794689011836818 + + +def test_qfactor_sum_ones(data_without_extra): + assert numpy.sum(data_without_extra.qfactor) == \ + len(data_without_extra.qfactor) + + +def test_monte_carlo_empty(data_without_extra): + assert not data_without_extra.monte_carlo + + +def test_extras_not_in_data(data_without_qfactor): + assert ["qfactor, BinN"] not in data_without_qfactor.data.dtype.names + + +def test_qfactor_size_is_correct(data_without_extra): + multiplier = data_without_extra.qfactor * data_without_extra.data['x'] + for index, value in enumerate(multiplier): + assert value == data_without_extra.data['x'][index] + + +def test_qfactor_sum_with_internal_names(data_with_internal_names): + assert numpy.sum(data_with_internal_names.qfactor) == 4.3227260998520247 + + +def test_binned_sum_with_internal_names(data_with_internal_names): + assert numpy.sum(data_with_internal_names.binned) == 4.7429487930395018 + + +def test_error_sum_with_internal_names(data_with_internal_names): + assert numpy.sum(data_with_internal_names.event_errors) == \ + 4.2857024214064667 + + +def test_expected_sum_with_internal_names(data_with_internal_names): + assert numpy.sum(data_with_internal_names.expected_values) == \ + 5.673049557244684 + + +@pytest.fixture +def function_without_math(): + loader = loaders.FunctionLoader( + FUNCTIONS_FOR_TEST, "processing", "setup" + ) + return loader + + +@pytest.fixture +def function_without_math_or_setup(): + loader = loaders.FunctionLoader( + FUNCTIONS_FOR_TEST, "processing", "A dirty lie" + ) + return loader + + +def test_function_and_setup_return_true(function_without_math): + processing = function_without_math.process + setup = function_without_math.setup + assert processing(1, 1) + assert setup() + + +def test_function_without_setup_is_none(function_without_math_or_setup): + setup = function_without_math_or_setup.setup + assert isinstance(setup(), type(None)) diff --git a/tests/test_full_app_run.py b/tests/test_full_app_run.py new file mode 100644 index 00000000..063774da --- /dev/null +++ b/tests/test_full_app_run.py @@ -0,0 +1,58 @@ +import os +import logging + +import pytest + +from PyPWA.core.shared import initial_logging +from PyPWA.core.configurator.execute import start + +FIT_CONFIG_LOCATION = os.path.join( + os.path.dirname(__file__), "data/pyfit/rho/RHOfit" +) + + +SIM_CONFIG_LOCATION = os.path.join( + os.path.dirname(__file__), "data/pyfit/rho/RHOsim" +) + + +PYFIT_CONFIG = { + "main": "shell fitting method", + "main name": "General Fitting", +} + + +PYSIM_CONFIG = { + "main": "shell simulation", + "main name": "Simulator", + "main options": { + "the type": "full", + "max intensity": None + } +} + + +@classmethod +def override_get_level(cls): + return logging.DEBUG + + +@pytest.fixture() +def force_logging_off(monkeypatch): + # PyTest breaks the internal logging mechanism, so we have to bypass it. + monkeypatch.setattr( + initial_logging.InternalLogger, "get_level", override_get_level + ) + + +def test_full_pyfit_run(force_logging_off): + executor = start.Execute() + executor.run(PYFIT_CONFIG, FIT_CONFIG_LOCATION) + os.remove("outputRHOFIT.npy") + os.remove("outputRHOFIT.txt") + + +def test_full_pysim_run(force_logging_off): + executor = start.Execute() + executor.run(PYSIM_CONFIG, SIM_CONFIG_LOCATION) + os.remove("outputRHO_rejection.txt") diff --git a/tests/test_option_objects.py b/tests/test_option_objects.py deleted file mode 100644 index af10d092..00000000 --- a/tests/test_option_objects.py +++ /dev/null @@ -1,45 +0,0 @@ -from PyPWA.builtin_plugins import process, data, minuit -from PyPWA.core.configurator import configurator - - -def options_test(options): - required = options.request_options("required") - optional = options.request_options("optional") - advanced = options.request_options("advanced") - template = options.request_options("template") - - assert isinstance(required, bool) or isinstance(required, dict) - assert isinstance(optional, bool) or isinstance(optional, dict) - assert isinstance(advanced, bool) or isinstance(advanced, dict) - - name = options.request_metadata("name") - interface = options.request_metadata("interface") - provides = options.request_metadata("provides") - requires_function = options.request_metadata("user functions") - - assert isinstance(name, str) - - -def test_ConfiguratorOptions_AllOptionsValid(): - configurator_options = configurator.ConfiguratorOptions() - options_test(configurator_options) - - -def test_MinuitOptions_AllOptionsValid(): - minuit_options = minuit.MinuitOptions() - options_test(minuit_options) - - -def test_Processing_AllOptionsValid(): - processing_options = process.Processing() - options_test(processing_options) - - -def test_DataParser_AllOptionsValid(): - memory_options = data.DataParser() - options_test(memory_options) - - -def test_DataIterator_AllOptionsValid(): - iterator_options = data.DataIterator() - options_test(iterator_options)