├── .gitattributes ├── .gitignore ├── .todo ├── .travis.yml ├── .yamllint ├── CHANGELOG.md ├── CITATION.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── citation.jsonld ├── configure.py ├── data ├── h2_pasr_output.npy ├── h2o2.cti ├── h2o2.inp ├── h2o2_performance │ ├── h2_pasr_output.npy │ ├── h2o2.cti │ └── h2o2.dat └── pasr_input.yaml ├── docs ├── Makefile ├── conf.py ├── data_ordering.rst ├── driver_functions.rst ├── examples.rst ├── faqs.rst ├── index.rst ├── installing.rst ├── overview.rst └── src │ ├── index.rst │ ├── modules.rst │ ├── pyjac.core.CParams.rst │ ├── pyjac.core.CUDAParams.rst │ ├── pyjac.core.cache_optimizer.rst │ ├── pyjac.core.chem_utilities.rst │ ├── pyjac.core.create_jacobian.rst │ ├── pyjac.core.mech_auxiliary.rst │ ├── pyjac.core.mech_interpret.rst │ ├── pyjac.core.rate_subs.rst │ ├── pyjac.core.rst │ ├── pyjac.core.shared_memory.rst │ ├── pyjac.functional_tester.partially_stirred_reactor.rst │ ├── pyjac.functional_tester.rst │ ├── pyjac.functional_tester.test.rst │ ├── pyjac.libgen.libgen.rst │ ├── pyjac.libgen.rst │ ├── pyjac.performance_tester.performance_tester.rst │ ├── pyjac.performance_tester.rst │ ├── pyjac.pywrap.parallel_compiler.rst │ ├── pyjac.pywrap.pywrap_gen.rst │ ├── pyjac.pywrap.rst │ ├── pyjac.rst │ └── pyjac.utils.rst ├── npy_convert.py ├── optional-requirements.txt ├── pyjac ├── __init__.py ├── __main__.py ├── _version.py ├── core │ ├── __init__.py │ ├── array_creator.py │ ├── chem_model.py │ ├── create_jacobian.py │ ├── driver_kernels.py │ ├── enum_types.py │ ├── exceptions.py │ ├── instruction_creator.py │ ├── mech_auxiliary.py │ ├── mech_interpret.py │ ├── rate_subs.py │ └── unit_conversions.py ├── examples │ ├── __init__.py │ ├── codegen_platform.yaml │ ├── mem_limits_example.yaml │ ├── site_conf_example.py │ ├── test_matrix.yaml │ └── test_platforms.yaml ├── functional_tester │ ├── __init__.py │ ├── __main__.py │ ├── partially_stirred_reactor.py │ ├── pasr_input.yaml │ └── test.py ├── kernel_utils │ ├── __init__.py │ ├── c │ │ ├── error_check.cpp │ │ ├── error_check.hpp │ │ ├── memcpy_2d.hpp │ │ └── wrapping_kernel.cpp.in │ ├── common │ │ ├── kernel.cpp.in │ │ ├── kernel.hpp.in │ │ ├── read_initial_conditions.cpp.in │ │ ├── read_initial_conditions.hpp.in │ │ ├── timer.cpp │ │ ├── timer.hpp │ │ └── write_data.hpp │ ├── file_writers.py │ ├── kernel_gen.py │ ├── memory_limits.py │ ├── memory_tools.py │ ├── opencl │ │ ├── error_check.ocl │ │ ├── error_check.oclh │ │ ├── memcpy_2d.oclh │ │ ├── opencl_kernel_compiler.cpp.in │ │ └── wrapping_kernel.ocl.in │ └── tools.py ├── libgen │ ├── __init__.py │ ├── __main__.py │ └── libgen.py ├── logging.yaml ├── loopy_utils │ ├── __init__.py │ ├── adept_edit_script.py.in │ ├── loopy_edit_script.py │ ├── loopy_utils.py │ └── preambles_and_manglers.py ├── performance_tester │ ├── __init__.py │ ├── __main__.py │ └── performance_tester.py ├── pywrap │ ├── __init__.py │ ├── __main__.py │ ├── adjacob_setup.py.in │ ├── adjacob_wrapper.pyx │ ├── parallel_compiler.py │ ├── py_tchem.c │ ├── py_tchem.h │ ├── pyjacob.cu │ ├── pyjacob.cuh │ ├── pyjacob_cuda_setup.py.in │ ├── pyjacob_cuda_wrapper.pyx │ ├── pyjacob_setup.py.in │ ├── pyjacob_wrapper.pyx.in │ ├── pytchem_setup.py.in │ ├── pytchem_wrapper.pyx │ └── pywrap_gen.py ├── schemas │ ├── __init__.py │ ├── codegen_platform.yaml │ ├── common_schema.yaml │ ├── test_matrix_schema.yaml │ └── test_platform_schema.yaml ├── tests │ ├── __init__.py │ ├── test.cti │ ├── test.inp │ ├── test_array_creator.py │ ├── test_array_splitter.py │ ├── test_chem_model.py │ ├── test_chem_utils.py │ ├── test_conversions.py │ ├── test_driver_kernels.py │ ├── test_functional_tester.py │ ├── test_instruction_creator.py │ ├── test_jacobian.py │ ├── test_kernel_compilation.py │ ├── test_kernel_generator.py │ ├── test_kernel_utils.py │ ├── test_libgen.py │ ├── test_mech_interpret.py │ ├── test_memory_tools.py │ ├── test_misc.py │ ├── test_performance_tester.py │ ├── test_pywrap.py │ ├── test_rate_subs.py │ ├── test_schemas.py │ ├── test_utils │ │ ├── __init__.py │ │ ├── data_bin_writer.py │ │ ├── get_test_matrix.py │ │ ├── read_ic_setup.py.in │ │ ├── read_ic_wrapper.pyx │ │ ├── ric_tester.py.in │ │ ├── test_import.py.in │ │ └── test_run.py.in │ └── test_version.py └── utils.py ├── requirements.txt ├── setup.cfg ├── setup.py ├── setup_helper.py ├── test-environment.yaml └── test_setup.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Basic .gitattributes for a python repo. 2 | 3 | # Source files 4 | # ============ 5 | *.pxd text diff=python 6 | *.py text diff=python 7 | *.py3 text diff=python 8 | *.pyw text diff=python 9 | *.pyx text diff=python 10 | 11 | # Binary files 12 | # ============ 13 | *.db binary 14 | *.p binary 15 | *.pkl binary 16 | *.pyc binary 17 | *.pyd binary 18 | *.pyo binary 19 | 20 | # Note: .db, .p, and .pkl files are associated 21 | # with the python modules ``pickle``, ``dbm.*``, 22 | # ``shelve``, ``marshal``, ``anydbm``, & ``bsddb`` 23 | # (among others). -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | bin/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # Installer logs 26 | pip-log.txt 27 | pip-delete-this-directory.txt 28 | 29 | # Unit test / coverage reports 30 | htmlcov/ 31 | .tox/ 32 | .coverage 33 | .cache 34 | nosetests.xml 35 | coverage.xml 36 | 37 | # Translations 38 | *.mo 39 | 40 | # Mr Developer 41 | .mr.developer.cfg 42 | .project 43 | .pydevproject 44 | 45 | # Rope 46 | .ropeproject 47 | 48 | # Django stuff: 49 | *.log 50 | *.pot 51 | 52 | # Sphinx documentation 53 | docs/_build/ 54 | 55 | #Pycharm stuff 56 | .idea/ 57 | 58 | #Mechanism files 59 | *.txt 60 | *.dat 61 | *.cti 62 | *.xml 63 | *.inp 64 | 65 | #out folder 66 | out/ 67 | 68 | #mechanisms folder 69 | mechs/ 70 | 71 | #Figures folder 72 | Figures/ 73 | 74 | # generated wrappers 75 | pyjacob_wrapper.c 76 | pytchem_wrapper.c 77 | 78 | # configuration files 79 | pyjac/siteconf.py 80 | run_performance.sh 81 | run_validation.sh 82 | 83 | # paper matricies 84 | pyjac/examples/paper_*_matrix.yaml 85 | -------------------------------------------------------------------------------- /.todo: -------------------------------------------------------------------------------- 1 | Beta release tasks: 2 | 🗹 Figure out how to properly emit fast_powi / fast_powf automagically depending 3 | on data type 4 | 🗹 Get the rest of the write race warnings 5 | 🗹 Get the new ambiguous dependency warnings as well 6 | ☐ Make platform specification completely independent of pyopencl -- currently, it requires the opencl platform to be installed on the generating machine, but it should only require a platform file. 7 | 🗹 In progress, need to do a full test on a machine w/o pyopencl installed 8 | ☐ Documentation 9 | Improvements: 10 | 🗹 Make libgen use codepy, since we depend on it already 11 | ☐ Fusion of similar kernels (e.g., the different Troe / SRI / Lindemann falloff derivative variants) 12 | ☐ Preload of commonly reused data into __local mem for deep-vectorizations on GPUs 13 | ☐ Note: the utility of this is limited at the moment, as NVIDIA doesn't yet support atomics 14 | hence, this will become more pressing when CUDA support is enabled 15 | ☐ New targets: ISPC, CUDA, Vectorized OpenMP 16 | Add-ons: 17 | ☐ Add common BLAS / LAPACK implementations (e.g. matrix mul, inversion, etc.), particularly 18 | for sparse matrices 19 | Codegen: 20 | ☐ Find a way to unify kernels, such that a single library / pywrapper exposes 21 | all available code 22 | 🗹 In progress -- we have the ability to generate different classes that can call 23 | each respective kernel, but we don't (yet) put a class for each possiblty kernel 24 | in the calling program 25 | 🗹 Reimplement wrapper generation using Cog 26 | ☐ Make the wrapper a C++ interface, such that we can embed useful info (species ordering, etc.), as well as simplify kernel exection / memory allocation 27 | 🗹 In progress, need to add more information variables / array creators 28 | 🗹 Serialize the pre-initialize memory manager, and load in Cog generation to simplify this 29 | ☐ Leave stubs for extension to CUDA / ISPC / etc. 30 | 🗹 Unit tests of code-gen should be make to accompany 31 | ☐ Longer-term: define use fstrings for loopy-code generation 32 | ☐ Also, implement a compiler pre-define in loopy to make life easier 33 | 🗹 Much more in-depth codegen tests 34 | ☐ Implement long-running tests on Travis 35 | ☐ At very least, implement a 'very-long' (only) test on Travis 36 | ☐ Running of performance / validation tester would be nice as well 37 | misc: 38 | ☐ Better tests of instruction creator 39 | ☐ Figure out Adept packaging bug for Conda on older servers 40 | Schemas: 41 | ☐ Figure out how to directly coerce schemas into optionloops / dicts to save trouble 42 | ☐ Various improvements 43 | 🗹 Allow memory-limit specification in a variable/codegen-platform to implement overrides of global 44 | 45 | 46 | Near-term plans: 47 | 🗹 Allow memory-limit specification in a variable/codegen-platform to implement overrides of global 48 | 🗹 Tag pre-print version 49 | 🗹 explict-simd 50 | 🗹 mechanism sorting 51 | 🗹 Change data pre-allocation for non-inputs / outputs to only use vector-size * num_threads * array size 52 | 🗹 Along these lines, allow for fixed-size allocations / fully implement "interface" mode for Hekki 53 | ☐ Switch to int64 to avoid overflow limiting 54 | 🗹 This is currently possible, but I haven't tested yet. 55 | ☐ Unify the command-line flags w/ the oploops for the test-matrix to make that more sane 56 | 🗹 This has at been somewhat mitigated (the depth / width options have been converted) 57 | ☐ In this vein, change the text matrix to an object that can be coerced from yaml input directly via ceberus 58 | ☐ Simplify split vector size division to right-shift and test 59 | 🗹 This is partially resolved, at least for explicit simd 60 | ☐ Fix linting errors 61 | ☐ Interface with Chris' RK / ROS solvers for accelerInt 62 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Use new trusty images, should yield newer compilers and packages 2 | sudo: required 3 | dist: trusty 4 | 5 | # safelist 6 | branches: 7 | only: 8 | - master 9 | - spyJac 10 | 11 | # language & environment and matrix spec 12 | language: python 13 | matrix: 14 | include: 15 | - python: "3.6" 16 | env: PYJAC_TEST_LANGS="opencl" 17 | - python: "3.6" 18 | env: PYJAC_TEST_LANGS="c" 19 | - python: "3.6" 20 | env: PYJAC_TEST_LANGS="c" PYJAC_RXN_SORTING="simd" 21 | - python: "3.6" 22 | env: PYJAC_TEST_LANGS="opencl" RUN_LONG_TESTS="1" 23 | - python: "3.6" 24 | env: PYJAC_TEST_LANGS="opencl" RUN_LONG_TESTS="1" PYJAC_UNIQUE_POINTERS="1" 25 | - python: "3.6" 26 | env: PYJAC_TEST_LANGS="c" RUN_LONG_TESTS="1" 27 | - python: "3.6" 28 | env: PYJAC_TEST_LANGS="c" RUN_LONG_TESTS="1" PYJAC_UNIQUE_POINTERS="1" 29 | - python: "3.6" 30 | env: ISFLAKE="1" 31 | 32 | # additional packages 33 | addons: 34 | apt: 35 | sources: 36 | - ubuntu-toolchain-r-test 37 | packages: 38 | - python-dev 39 | - python-numpy 40 | - python-pip 41 | - python3-dev 42 | - python3-numpy 43 | - python3-setuptools 44 | - libsundials-serial-dev 45 | - liblapack-dev 46 | - libblas-dev 47 | - libboost-dev 48 | 49 | # install dependencies 50 | before_install: 51 | - sudo apt-get update -qq 52 | - sudo apt-get install -qq libltdl3-dev libhwloc-dev 53 | # get conda 54 | - if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then 55 | wget https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh -O miniconda.sh; 56 | else 57 | wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; 58 | fi 59 | - bash miniconda.sh -b -p $HOME/miniconda 60 | - export PATH="$HOME/miniconda/bin:$PATH" 61 | - hash -r 62 | - conda config --set always_yes yes --set changeps1 no 63 | - conda update -q conda 64 | # Useful for debugging any issues with conda 65 | - conda info -a 66 | # add channels 67 | - conda config --add channels conda-forge 68 | - conda config --add channels cantera 69 | # create env 70 | - conda create -y -n test-environment python=$TRAVIS_PYTHON_VERSION llvmdev clangdev cantera ocl-icd=*=h14c3975_1001 islpy pyyaml scipy pyopencl numpy Cython pytables flake8 pep8-naming pocl adept=*=he6fcbdd_3 71 | - source activate test-environment 72 | # get vendor dir 73 | - export OCL_ICD_VENDORS=$CONDA_PREFIX/etc/OpenCL/vendors 74 | # and go back to pyjac 75 | - cd $TRAVIS_BUILD_DIR 76 | # install pyjac 77 | install: 78 | # read from requirements -- install via conda if available 79 | - pip install -r requirements.txt 80 | - pip install -r optional-requirements.txt 81 | # build siteconf.py 82 | - python configure.py --cl-inc-dir="$CONDA_PREFIX/include" --cl-lib-dir="$CONDA_PREFIX/lib" --adept-lib-dir="$CONDA_PREFIX/lib" --adept-inc-dir="$CONDA_PREFIX/include" 83 | # copy in siteconf 84 | - cp siteconf.py pyjac/ 85 | - pip install . 86 | before_script: 87 | # openmp 88 | - export OMP_NUM_THREADS=4 89 | - mkdir -p $TRAVIS_BUILD_DIR/working/ 90 | - export TMPDIR=$TRAVIS_BUILD_DIR/working/ 91 | # run test 92 | script: 93 | if [[ -z "$ISFLAKE" && -z "$RUN_LONG_TESTS" ]]; then 94 | nosetests -A 'not fullkernel and not verylong' -s --with-timer; 95 | elif [[ -z "$ISFLAKE" && -n "$RUN_LONG_TESTS" ]]; then 96 | nosetests -A 'fullkernel' -s --with-timer; 97 | else 98 | python -m flake8 pyjac/ --count; 99 | fi 100 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | # linting rules for yaml 2 | 3 | --- 4 | extends: default 5 | 6 | rules: 7 | truthy: disable 8 | line-length: 9 | max: 500 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | ## [1.0.6] - 2018-02-21 8 | ### Added 9 | - DOI for 1.0.4 10 | 11 | ### Fixed 12 | - Syntax errors in readme.md 13 | - Conda install instructions in install.md 14 | - Corrected TRange columns in parser 15 | - Minor documentation fixes 16 | 17 | ### Added 18 | - Add check to reactions to test that all species exist 19 | - Duplicate warning from falloff->chemically-activated TROE reactions for zero-parameters 20 | - Add handling of non-unity default third body efficiency 21 | 22 | ### Changed 23 | - Bump internal version to 1.0.5.c 24 | 25 | ## [1.0.5.b0] - 2017-06-02 26 | ### Added 27 | - Added usergroup info to README and documentation 28 | 29 | ### Fixed 30 | 31 | ### Changed 32 | - Now strip whitespace from mechanism file lines prior to parsing keywords 33 | 34 | ### Removed 35 | - Removed plotting scripts specific to first paper on pyJac 36 | 37 | ## [1.0.4] - 2017-04-18 38 | ### Added 39 | - Adds Travis config for automatic PyPI and conda builds 40 | - Adds minimal unittest test suite for module imports 41 | - Adds code of conduct 42 | 43 | ### Changed 44 | - Changed README back to Markdown for simplicity 45 | - Updated citation instructions 46 | 47 | ## [1.0.3] - 2017-04-01 48 | ### Fixed 49 | - Fix for SRI Falloff functions with non-default third bodies ([issue #12](https://github.com/SLACKHA/pyJac/issues/12)) 50 | - Fixed removal of jac/rate lists before libgen of functional_tester 51 | - Fixed pywrap module import 52 | 53 | ### Changed 54 | - Issue warning in Cantera parsing if the installed version doesn't have access to species thermo properties. 55 | 56 | ### Added 57 | - Added significantly more documentation and examples for data ordering, 58 | the state vector / Jacobian, and using the python interface 59 | 60 | ## [1.0.2] - 2017-01-18 61 | ### Added 62 | - Added CHANGELOG 63 | - Added documentation for libgen / pywrap features 64 | 65 | ### Changed 66 | - Minor compilation fixes for including OpenMP 67 | - Updated github links to point to SLACKHA / Niemeyer Research Group 68 | 69 | ### Deprecated 70 | - Shared library creation for CUDA disabled, as CUDA does not allow linkage of SO's into another CUDA kernel 71 | 72 | ### Fixed 73 | - Explicitly conserve mass in PaSR 74 | - Minor path fixes 75 | - Division by zero in some TROE parameter cases 76 | 77 | ## [1.0.1] - 2016-05-25 78 | ### Added 79 | - Added GPU macros, e.g., THREAD_ID, GRID_SIZE 80 | 81 | ### Changed 82 | - Much better handling of removal of files created during testing 83 | 84 | ### Fixed 85 | - Bugfix that generates data.bin files correctly from .npy files for performance testing (**important**) 86 | - Explicit setting of OpenMP # threads for performance testing 87 | 88 | ## [1.0] - 2016-05-07 89 | ### Added 90 | - pyJac is now a Python package 91 | - pyJac can now create a static/shared library for a mechanism (for external linkage) 92 | - Added documentation 93 | - Added examples 94 | 95 | ### Changed 96 | - Handles CUDA compilation better via Cython 97 | - pointers are now restricted where appropriate 98 | - better Python3 compatibility 99 | 100 | ### Fixed 101 | - other minor bugfixes 102 | 103 | ## [0.9.1-beta] - 2015-10-29 104 | ### Changed 105 | - Implemented the strict mass conservation formulation 106 | - Updated CUDA implementation such that it is testable vs. pyJac c-version (and Cantera where applicable) 107 | - More robust build folder management 108 | - More robust mapping for strict mass conservation 109 | 110 | ## 0.9-beta - 2015-10-02 111 | ### Added 112 | - First working / tested version of pyJac 113 | 114 | 115 | [Unreleased]: https://github.com/slackha/pyJac/compare/v1.0.4...HEAD 116 | [1.0.4]: https://github.com/slackha/pyJac/compare/v1.0.3...v1.0.4 117 | [1.0.3]: https://github.com/slackha/pyJac/compare/v1.0.2...v1.0.3 118 | [1.0.2]: https://github.com/slackha/pyJac/compare/v1.0.1...v1.0.2 119 | [1.0.1]: https://github.com/slackha/pyJac/compare/v1.0...v1.0.1 120 | [1.0]: https://github.com/slackha/pyJac/compare/v0.9.1-beta...v1.0 121 | [0.9.1-beta]: https://github.com/slackha/pyJac/compare/v0.9-beta...v0.9.1-beta 122 | -------------------------------------------------------------------------------- /CITATION.md: -------------------------------------------------------------------------------- 1 | # Citation of pyJac 2 | 3 | [![DOI](https://zenodo.org/badge/19829533.svg)](https://zenodo.org/badge/latestdoi/19829533) 4 | 5 | If you use pyJac in a scholarly article, please cite it directly as 6 | 7 | > Kyle E. Niemeyer and Nicholas J. Curtis (2017). pyJac v1.0.4 [Software]. Zenodo. 8 | 9 | 10 | A BibTeX entry for LaTeX users is 11 | 12 | ## BibTeX entry: 13 | 14 | ```TeX 15 | @misc{pyJac, 16 | author = {Kyle E Niemeyer and Nicholas J Curtis}, 17 | year = 2017, 18 | title = {{pyJac} v1.0.4}, 19 | doi = {10.5281/zenodo.######}, 20 | url = {https://github.com/slackha/pyJac}, 21 | } 22 | ``` 23 | 24 | In both cases, please update the entry with the version used. The DOI for the 25 | latest version can be found in the badge at the top. If you would like to cite 26 | a specific, older version, the DOIs for each release are: 27 | 28 | * v1.0.4: [10.5281/zenodo.555950](https://doi.org/10.5281/zenodo.555950) 29 | * v1.0.3: [10.5281/zenodo.439682](https://doi.org/10.5281/zenodo.439682) 30 | * v1.0.2: [10.5281/zenodo.251144](https://doi.org/10.5281/zenodo.251144) 31 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project project lead, 59 | [@kyleniemeyer](https://github.com/kyleniemeyer), at . All 60 | complaints will be reviewed and investigated and will result in a response that 61 | is deemed necessary and appropriate to the circumstances. The project team is 62 | obligated to maintain confidentiality with regard to the reporter of an incident. 63 | Further details of specific enforcement policies may be posted separately. 64 | 65 | Project maintainers who do not follow or enforce the Code of Conduct in good 66 | faith may face temporary or permanent repercussions as determined by other 67 | members of the project's leadership. 68 | 69 | ## Attribution 70 | 71 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 72 | available at [http://contributor-covenant.org/version/1/4][version] 73 | 74 | [homepage]: http://contributor-covenant.org 75 | [version]: http://contributor-covenant.org/version/1/4/ 76 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We welcome contributions in the form of bug reports, bug fixes, improvements to the documentation, ideas for enhancements (or the enhancements themselves!). 4 | 5 | You can find a [list of current issues](https://github.com/slackha/pyJac/issues) in the project's GitHub repo. Feel free to tackle any existing bugs or enhancement ideas by submitting a [pull request](https://github.com/slackha/pyJac/pulls). 6 | 7 | ## Bug Reports 8 | 9 | * Please include a short (but detailed) Python snippet or explanation for reproducing the problem. Attach or include a link to any input files (e.g., reaction mechanism) that will be needed to reproduce the error. 10 | * Explain the behavior you expected, and how what you got differed. 11 | 12 | ## Pull Requests 13 | 14 | * Please reference relevant GitHub issues in your commit message using `GH123` or `#123`. 15 | * Changes should be [PEP8](http://www.python.org/dev/peps/pep-0008/) compatible. 16 | * Keep style fixes to a separate commit to make your pull request more readable. 17 | * Docstrings are required and should follow the [NumPy style](http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html#example-numpy). 18 | * When you start working on a pull request, start by creating a new branch pointing at the latest commit on [GitHub master](https://github.com/slackha/pyJac/tree/master). 19 | * The pyJac copyright policy is detailed in the [`LICENSE`](https://github.com/slackha/pyJac/blob/master/LICENSE). 20 | 21 | ## Tests 22 | 23 | Since pyJac (unfortunately) does not currently employ unit tests, functional testing is somewhat involved. However, the necessary framework is available in `pyjac.functional_tester`, and we ask that pull requests demonstrate that the changes do not invalidate these tests. 24 | 25 | We also enthusiastically welcome contributions in the form of unit tests! 26 | 27 | ## Meta 28 | 29 | Thanks to the useful [contributing guide of pyrk](https://github.com/pyrk/pyrk/blob/master/CONTRIBUTING.md), which served as an inspiration and starting point for this guide. 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016, Kyle E Niemeyer, Nicholas J Curtis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include MANIFEST.in 2 | include LICENSE 3 | include README.md 4 | include CODE_OF_CONDUCT.md 5 | include CITATION.md 6 | include CONTRIBUTING.md 7 | include citation.jsonld 8 | include setup.py 9 | include setup.cfg 10 | 11 | include pyjac/utils.py 12 | include pyjac/siteconf.py 13 | include pyjac/__init__.py 14 | include pyjac/__main__.py 15 | include pyjac/_version.py 16 | include pyjac/siteconf.py 17 | include pyjac/logging.yaml 18 | recursive-include pyjac/core *.py 19 | recursive-include pyjac/functional_tester *.py *.yaml 20 | recursive-include pyjac/loopy_utils *.py *.in 21 | recursive-include pyjac/libgen *.py 22 | recursive-include pyjac/kernel_utils *.py *.in *.hpp *.cpp *.oclh *.ocl 23 | recursive-include pyjac/performance_tester *.py 24 | recursive-include pyjac/pywrap *.py *.in 25 | recursive-include pyjac/tests *.py *.inp * .cti *.in *.yaml 26 | include test_platforms_example.yaml 27 | include pyjac/site_conf_example.py 28 | recursive-include data/ *.npy *.cti *.inp *.yaml 29 | recursive-include pyjac/examples *.yaml *.py 30 | recursive-include pyjac/schemas *.yaml *.py 31 | 32 | global-exclude *.so 33 | global-exclude *.pyd 34 | global-exclude *.pyc 35 | global-exclude *~ 36 | global-exclude \#* 37 | global-exclude .git* 38 | global-exclude .DS_Store 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pyJac 2 | 3 | [![DOI](https://zenodo.org/badge/19829533.svg)](https://zenodo.org/badge/latestdoi/19829533) 4 | [![Code of Conduct](https://img.shields.io/badge/code%20of%20conduct-contributor%20covenant-green.svg)](http://contributor-covenant.org/version/1/4/) 5 | [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT) 6 | [![PyPI](https://badge.fury.io/py/pyJac.svg)](https://badge.fury.io/py/pyJac) 7 | [![Anaconda](https://anaconda.org/slackha/pyjac/badges/version.svg)](https://anaconda.org/slackha/pyjac) 8 | 9 | This utility creates source code to calculate the Jacobian matrix analytically 10 | for a chemical reaction mechanism. 11 | 12 | ## Documentation 13 | 14 | The full documentation for pyJac can be found at . 15 | 16 | ## User Group 17 | 18 | Further support can be found at our [user group](https://groups.io/g/slackha-users), 19 | or by [opening an issue](https://github.com/SLACKHA/pyJac/issues) on our github repo. 20 | 21 | ## Installation 22 | 23 | Detailed installation instructions can be found in the 24 | [full documentation](http://slackha.github.io/pyJac/). 25 | The easiest way to install pyJac is via `conda`. You can install to your 26 | environment with 27 | ``` 28 | > conda install -c slackha pyjac 29 | ``` 30 | 31 | pyJac can also be installed from PyPI using pip: 32 | ``` 33 | pip install pyjac 34 | ``` 35 | or, using the downloaded source code, installed as a Python module: 36 | ``` 37 | > python setup.py install 38 | ``` 39 | 40 | ## Usage 41 | 42 | pyJac can be run as a python module: 43 | ``` 44 | > python -m pyjac [options] 45 | ``` 46 | 47 | The generated source code is placed within the `out` (by default) directory, 48 | which is created if it doesn't exist initially. 49 | See the documentation or use `python pyjac -h` for the full list of options. 50 | 51 | ## Theory 52 | 53 | Theory, derivations, validation and performance testing can be found in the paper 54 | fully describing version 1.0.2 of pyJac: , 55 | now published via and available 56 | openly via [`arXiv:1605.03262 [physics.comp-ph]`](https://arxiv.org/abs/1605.03262). 57 | 58 | ## License 59 | 60 | pyJac is released under the MIT license; see the 61 | [LICENSE](https://github.com/slackha/pyJac/blob/master/LICENSE) for details. 62 | 63 | If you use this package as part of a scholarly publication, please see 64 | [CITATION.md](https://github.com/slackha/pyJac/blob/master/CITATION.md) 65 | for the appropriate citation(s). 66 | 67 | ## Contributing 68 | 69 | We welcome contributions to pyJac! Please see the guide to making contributions 70 | in the [CONTRIBUTING.md](https://github.com/slackha/pyJac/blob/master/CONTRIBUTING.md) 71 | file. 72 | 73 | ## Code of Conduct 74 | 75 | In order to have a more open and welcoming community, pyJac adheres to a code of conduct adapted from the [Contributor Covenant](http://contributor-covenant.org) code of conduct. 76 | 77 | Please adhere to this code of conduct in any interactions you have in the pyJac community. It is strictly enforced on all official pyJac repositories, websites, and resources. If you encounter someone violating these terms, please let a maintainer ([@kyleniemeyer](https://github.com/kyleniemeyer) or [@arghdos](https://github.com/arghdos), via email at ) know and we will address it as soon as possible. 78 | 79 | ## Authors 80 | 81 | Created by [Kyle Niemeyer](http://kyleniemeyer.com) () and 82 | Nicholas Curtis () 83 | -------------------------------------------------------------------------------- /citation.jsonld: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "https://raw.githubusercontent.com/mbjones/codemeta/master/codemeta.jsonld", 3 | "@type": "Code", 4 | "author": [ 5 | { 6 | "@id": "http://orcid.org/0000-0003-4425-7097", 7 | "@type": "Person", 8 | "email": "kyle.niemeyer@oregonstate.edu", 9 | "name": "Kyle Niemeyer", 10 | "affiliation": "Oregon State University" 11 | }, 12 | { 13 | "@id": "http://orcid.org/0000-0002-0303-4711", 14 | "@type": "Person", 15 | "email": "nicholas.curtis@uconn.edu", 16 | "name": "Nicholas Curtis", 17 | "affiliation": "University of Connecticut" 18 | } 19 | ], 20 | "identifier": "http://dx.doi.org/10.5281/zenodo.439682", 21 | "codeRepository": "https://github.com/slackha/pyJac", 22 | "datePublished": "2015-", 23 | "description": "pyJac creates code for CPU and GPU chemical kinetics Jacobian matrices", 24 | "keywords": "Jacobian, chemical kinetics, SIMD, GPU", 25 | "license": "https://opensource.org/licenses/MIT", 26 | "title": "pyJac", 27 | "version": "1.0.3", 28 | "uploadedBy": 29 | { 30 | "@id": "http://orcid.org/0000-0003-4425-7097", 31 | "@type": "Person", 32 | "email": "kyle.niemeyer@oregonstate.edu", 33 | "name": "Kyle Niemeyer", 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /configure.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | from __future__ import absolute_import 4 | 5 | from setup_helper import configure_frontend 6 | configure_frontend() 7 | -------------------------------------------------------------------------------- /data/h2_pasr_output.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SLACKHA/pyJac-v2/1cdd67bc4bdfdde37c9fa73674428187d5f875a8/data/h2_pasr_output.npy -------------------------------------------------------------------------------- /data/h2o2.inp: -------------------------------------------------------------------------------- 1 | ELEMENTS 2 | O H AR 3 | END 4 | SPECIES 5 | H2 H O O2 OH H2O HO2 H2O2 AR 6 | END 7 | THERMO ALL 8 | 300.000 1000.000 5000.000 9 | O L 1/90O 1 00 00 00G 200.000 3500.000 1000.000 1 10 | 2.56942078E+00-8.59741137E-05 4.19484589E-08-1.00177799E-11 1.22833691E-15 2 11 | 2.92175791E+04 4.78433864E+00 3.16826710E+00-3.27931884E-03 6.64306396E-06 3 12 | -6.12806624E-09 2.11265971E-12 2.91222592E+04 2.05193346E+00 4 13 | O2 TPIS89O 2 00 00 00G 200.000 3500.000 1000.000 1 14 | 3.28253784E+00 1.48308754E-03-7.57966669E-07 2.09470555E-10-2.16717794E-14 2 15 | -1.08845772E+03 5.45323129E+00 3.78245636E+00-2.99673416E-03 9.84730201E-06 3 16 | -9.68129509E-09 3.24372837E-12-1.06394356E+03 3.65767573E+00 4 17 | H L 7/88H 1 00 00 00G 200.000 3500.000 1000.000 1 18 | 2.50000001E+00-2.30842973E-11 1.61561948E-14-4.73515235E-18 4.98197357E-22 2 19 | 2.54736599E+04-4.46682914E-01 2.50000000E+00 7.05332819E-13-1.99591964E-15 3 20 | 2.30081632E-18-9.27732332E-22 2.54736599E+04-4.46682853E-01 4 21 | H2 TPIS78H 2 00 00 00G 200.000 3500.000 1000.000 1 22 | 3.33727920E+00-4.94024731E-05 4.99456778E-07-1.79566394E-10 2.00255376E-14 2 23 | -9.50158922E+02-3.20502331E+00 2.34433112E+00 7.98052075E-03-1.94781510E-05 3 24 | 2.01572094E-08-7.37611761E-12-9.17935173E+02 6.83010238E-01 4 25 | OH RUS 78O 1H 1 00 00G 200.000 3500.000 1000.000 1 26 | 3.09288767E+00 5.48429716E-04 1.26505228E-07-8.79461556E-11 1.17412376E-14 2 27 | 3.85865700E+03 4.47669610E+00 3.99201543E+00-2.40131752E-03 4.61793841E-06 3 28 | -3.88113333E-09 1.36411470E-12 3.61508056E+03-1.03925458E-01 4 29 | H2O L 8/89H 2O 1 00 00G 200.000 3500.000 1000.000 1 30 | 3.03399249E+00 2.17691804E-03-1.64072518E-07-9.70419870E-11 1.68200992E-14 2 31 | -3.00042971E+04 4.96677010E+00 4.19864056E+00-2.03643410E-03 6.52040211E-06 3 32 | -5.48797062E-09 1.77197817E-12-3.02937267E+04-8.49032208E-01 4 33 | HO2 L 5/89H 1O 2 00 00G 200.000 3500.000 1000.000 1 34 | 4.01721090E+00 2.23982013E-03-6.33658150E-07 1.14246370E-10-1.07908535E-14 2 35 | 1.11856713E+02 3.78510215E+00 4.30179801E+00-4.74912051E-03 2.11582891E-05 3 36 | -2.42763894E-08 9.29225124E-12 2.94808040E+02 3.71666245E+00 4 37 | H2O2 L 7/88H 2O 2 00 00G 200.000 3500.000 1000.000 1 38 | 4.16500285E+00 4.90831694E-03-1.90139225E-06 3.71185986E-10-2.87908305E-14 2 39 | -1.78617877E+04 2.91615662E+00 4.27611269E+00-5.42822417E-04 1.67335701E-05 3 40 | -2.15770813E-08 8.62454363E-12-1.77025821E+04 3.43505074E+00 4 41 | AR 120186AR 1 G 300.000 5000.000 1000.000 1 42 | 0.02500000E+02 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 2 43 | -0.07453750E+04 0.04366000E+02 0.02500000E+02 0.00000000E+00 0.00000000E+00 3 44 | 0.00000000E+00 0.00000000E+00-0.07453750E+04 0.04366000E+02 4 45 | END 46 | REACTIONS 47 | 2O+M<=>O2+M 1.200E+17 -1.000 .00 48 | H2/ 2.40/ H2O/15.40/ AR/ .83/ 49 | O+H+M<=>OH+M 5.000E+17 -1.000 .00 50 | H2/2.00/ H2O/6.00/ AR/ .70/ 51 | O+H2<=>H+OH 3.870E+04 2.700 6260.00 52 | O+HO2<=>OH+O2 2.000E+13 .000 .00 53 | O+H2O2<=>OH+HO2 9.630E+06 2.000 4000.00 54 | H+O2+M<=>HO2+M 2.800E+18 -.860 .00 55 | O2/ .00/ H2O/ .00/ AR/ .00/ 56 | H+2O2<=>HO2+O2 2.080E+19 -1.240 .00 57 | H+O2+H2O<=>HO2+H2O 11.26E+18 -.760 .00 58 | H+O2+AR<=>HO2+AR 7.000E+17 -.800 .00 59 | H+O2<=>O+OH 2.650E+16 -.6707 17041.00 60 | 2H+M<=>H2+M 1.000E+18 -1.000 .00 61 | H2/ .00/ H2O/ .00/ AR/ .63/ 62 | 2H+H2<=>2H2 9.000E+16 -.600 .00 63 | 2H+H2O<=>H2+H2O 6.000E+19 -1.250 .00 64 | H+OH+M<=>H2O+M 2.200E+22 -2.000 .00 65 | H2/ .73/ H2O/3.65/ AR/ .38/ 66 | H+HO2<=>O+H2O 3.970E+12 .000 671.00 67 | H+HO2<=>O2+H2 4.480E+13 .000 1068.00 68 | H+HO2<=>2OH 0.840E+14 .000 635.00 69 | H+H2O2<=>HO2+H2 1.210E+07 2.000 5200.00 70 | H+H2O2<=>OH+H2O 1.000E+13 .000 3600.00 71 | OH+H2<=>H+H2O 2.160E+08 1.510 3430.00 72 | 2OH(+M)<=>H2O2(+M) 7.400E+13 -.370 .00 73 | LOW / 2.300E+18 -.900 -1700.00/ 74 | TROE/ .7346 94.00 1756.00 5182.00 / 75 | H2/2.00/ H2O/6.00/ AR/ .70/ 76 | 2OH<=>O+H2O 3.570E+04 2.400 -2110.00 77 | OH+HO2<=>O2+H2O 1.450E+13 .000 -500.00 78 | DUPLICATE 79 | OH+H2O2<=>HO2+H2O 2.000E+12 .000 427.00 80 | DUPLICATE 81 | OH+H2O2<=>HO2+H2O 1.700E+18 .000 29410.00 82 | DUPLICATE 83 | 2HO2<=>O2+H2O2 1.300E+11 .000 -1630.00 84 | DUPLICATE 85 | 2HO2<=>O2+H2O2 4.200E+14 .000 12000.00 86 | DUPLICATE 87 | OH+HO2<=>O2+H2O 0.500E+16 .000 17330.00 88 | DUPLICATE 89 | END 90 | -------------------------------------------------------------------------------- /data/h2o2_performance/h2_pasr_output.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SLACKHA/pyJac-v2/1cdd67bc4bdfdde37c9fa73674428187d5f875a8/data/h2o2_performance/h2_pasr_output.npy -------------------------------------------------------------------------------- /data/h2o2_performance/h2o2.dat: -------------------------------------------------------------------------------- 1 | ELEMENTS 2 | O H AR 3 | END 4 | SPECIES 5 | H2 H O O2 OH H2O HO2 H2O2 AR 6 | END 7 | THERMO ALL 8 | 300.000 1000.000 5000.000 9 | O L 1/90O 1 00 00 00G 200.000 3500.000 1000.000 1 10 | 2.56942078E+00-8.59741137E-05 4.19484589E-08-1.00177799E-11 1.22833691E-15 2 11 | 2.92175791E+04 4.78433864E+00 3.16826710E+00-3.27931884E-03 6.64306396E-06 3 12 | -6.12806624E-09 2.11265971E-12 2.91222592E+04 2.05193346E+00 4 13 | O2 TPIS89O 2 00 00 00G 200.000 3500.000 1000.000 1 14 | 3.28253784E+00 1.48308754E-03-7.57966669E-07 2.09470555E-10-2.16717794E-14 2 15 | -1.08845772E+03 5.45323129E+00 3.78245636E+00-2.99673416E-03 9.84730201E-06 3 16 | -9.68129509E-09 3.24372837E-12-1.06394356E+03 3.65767573E+00 4 17 | H L 7/88H 1 00 00 00G 200.000 3500.000 1000.000 1 18 | 2.50000001E+00-2.30842973E-11 1.61561948E-14-4.73515235E-18 4.98197357E-22 2 19 | 2.54736599E+04-4.46682914E-01 2.50000000E+00 7.05332819E-13-1.99591964E-15 3 20 | 2.30081632E-18-9.27732332E-22 2.54736599E+04-4.46682853E-01 4 21 | H2 TPIS78H 2 00 00 00G 200.000 3500.000 1000.000 1 22 | 3.33727920E+00-4.94024731E-05 4.99456778E-07-1.79566394E-10 2.00255376E-14 2 23 | -9.50158922E+02-3.20502331E+00 2.34433112E+00 7.98052075E-03-1.94781510E-05 3 24 | 2.01572094E-08-7.37611761E-12-9.17935173E+02 6.83010238E-01 4 25 | OH RUS 78O 1H 1 00 00G 200.000 3500.000 1000.000 1 26 | 3.09288767E+00 5.48429716E-04 1.26505228E-07-8.79461556E-11 1.17412376E-14 2 27 | 3.85865700E+03 4.47669610E+00 3.99201543E+00-2.40131752E-03 4.61793841E-06 3 28 | -3.88113333E-09 1.36411470E-12 3.61508056E+03-1.03925458E-01 4 29 | H2O L 8/89H 2O 1 00 00G 200.000 3500.000 1000.000 1 30 | 3.03399249E+00 2.17691804E-03-1.64072518E-07-9.70419870E-11 1.68200992E-14 2 31 | -3.00042971E+04 4.96677010E+00 4.19864056E+00-2.03643410E-03 6.52040211E-06 3 32 | -5.48797062E-09 1.77197817E-12-3.02937267E+04-8.49032208E-01 4 33 | HO2 L 5/89H 1O 2 00 00G 200.000 3500.000 1000.000 1 34 | 4.01721090E+00 2.23982013E-03-6.33658150E-07 1.14246370E-10-1.07908535E-14 2 35 | 1.11856713E+02 3.78510215E+00 4.30179801E+00-4.74912051E-03 2.11582891E-05 3 36 | -2.42763894E-08 9.29225124E-12 2.94808040E+02 3.71666245E+00 4 37 | H2O2 L 7/88H 2O 2 00 00G 200.000 3500.000 1000.000 1 38 | 4.16500285E+00 4.90831694E-03-1.90139225E-06 3.71185986E-10-2.87908305E-14 2 39 | -1.78617877E+04 2.91615662E+00 4.27611269E+00-5.42822417E-04 1.67335701E-05 3 40 | -2.15770813E-08 8.62454363E-12-1.77025821E+04 3.43505074E+00 4 41 | AR 120186AR 1 G 300.000 5000.000 1000.000 1 42 | 0.02500000E+02 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 2 43 | -0.07453750E+04 0.04366000E+02 0.02500000E+02 0.00000000E+00 0.00000000E+00 3 44 | 0.00000000E+00 0.00000000E+00-0.07453750E+04 0.04366000E+02 4 45 | END 46 | REACTIONS 47 | 2O+M<=>O2+M 1.200E+17 -1.000 .00 48 | H2/ 2.40/ H2O/15.40/ AR/ .83/ 49 | O+H+M<=>OH+M 5.000E+17 -1.000 .00 50 | H2/2.00/ H2O/6.00/ AR/ .70/ 51 | O+H2<=>H+OH 3.870E+04 2.700 6260.00 52 | O+HO2<=>OH+O2 2.000E+13 .000 .00 53 | O+H2O2<=>OH+HO2 9.630E+06 2.000 4000.00 54 | H+O2+M<=>HO2+M 2.800E+18 -.860 .00 55 | O2/ .00/ H2O/ .00/ AR/ .00/ 56 | H+2O2<=>HO2+O2 2.080E+19 -1.240 .00 57 | H+O2+H2O<=>HO2+H2O 11.26E+18 -.760 .00 58 | H+O2+AR<=>HO2+AR 7.000E+17 -.800 .00 59 | H+O2<=>O+OH 2.650E+16 -.6707 17041.00 60 | 2H+M<=>H2+M 1.000E+18 -1.000 .00 61 | H2/ .00/ H2O/ .00/ AR/ .63/ 62 | 2H+H2<=>2H2 9.000E+16 -.600 .00 63 | 2H+H2O<=>H2+H2O 6.000E+19 -1.250 .00 64 | H+OH+M<=>H2O+M 2.200E+22 -2.000 .00 65 | H2/ .73/ H2O/3.65/ AR/ .38/ 66 | H+HO2<=>O+H2O 3.970E+12 .000 671.00 67 | H+HO2<=>O2+H2 4.480E+13 .000 1068.00 68 | H+HO2<=>2OH 0.840E+14 .000 635.00 69 | H+H2O2<=>HO2+H2 1.210E+07 2.000 5200.00 70 | H+H2O2<=>OH+H2O 1.000E+13 .000 3600.00 71 | OH+H2<=>H+H2O 2.160E+08 1.510 3430.00 72 | 2OH(+M)<=>H2O2(+M) 7.400E+13 -.370 .00 73 | LOW / 2.300E+18 -.900 -1700.00/ 74 | TROE/ .7346 94.00 1756.00 5182.00 / 75 | H2/2.00/ H2O/6.00/ AR/ .70/ 76 | 2OH<=>O+H2O 3.570E+04 2.400 -2110.00 77 | OH+HO2<=>O2+H2O 1.450E+13 .000 -500.00 78 | DUPLICATE 79 | OH+H2O2<=>HO2+H2O 2.000E+12 .000 427.00 80 | DUPLICATE 81 | OH+H2O2<=>HO2+H2O 1.700E+18 .000 29410.00 82 | DUPLICATE 83 | 2HO2<=>O2+H2O2 1.300E+11 .000 -1630.00 84 | DUPLICATE 85 | 2HO2<=>O2+H2O2 4.200E+14 .000 12000.00 86 | DUPLICATE 87 | OH+HO2<=>O2+H2O 0.500E+16 .000 17330.00 88 | DUPLICATE 89 | END 90 | -------------------------------------------------------------------------------- /data/pasr_input.yaml: -------------------------------------------------------------------------------- 1 | # Input parameters for PaSR simulation. 2 | case: premixed 3 | temperature: 300.0 4 | pressure: 1.0 5 | equivalence ratio: 1.0 6 | fuel: 7 | H2: 1.0 8 | oxidizer: 9 | O2: 1.0 10 | N2: 3.76 11 | complete products: 12 | - H2O 13 | - N2 14 | number of particles: 10 15 | residence time: 10.e-3 16 | mixing time: 1.e-3 17 | pairing time: 1.e-3 18 | number of residence times: 1 19 | -------------------------------------------------------------------------------- /docs/data_ordering.rst: -------------------------------------------------------------------------------- 1 | Data Ordering 2 | ############# 3 | 4 | pyJac can utilize C (row-major) or F (column-major) data layouts, and additionally implements a vectorized data ordering to improve caching & performance on various platforms. 5 | 6 | .. _array_ordering: 7 | 8 | ============== 9 | Array Ordering 10 | ============== 11 | 12 | Consider the array of species concentrations at in index :math:`\left(j, k\right)`, :math:`[C]_{j, k}`. 13 | The array has :math:`N_{\text{state}}` (:math:`j = 1 \ldots N_{\text{state}}`) rows corresponding to the number of thermo-chemical states being evaluated and :math:`N_{\text{sp}}` columns (:math:`k = 1 \ldots N_{\text{sp}}`) corresponding to a chemical model with :math:`N_{\text{sp}}` species. 14 | 15 | This row / column layout is the one applied for the row-major / column-major layout. 16 | 17 | 18 | ======================================================= 19 | Data Ordering for use with Python or Executable Library 20 | ======================================================= 21 | 22 | When calling pyJac from either the generated Python wrapper or executable library (See :ref:`interface_vs_exe`), the state vectors / Jacobians should be interpreted using standard "C" \ "F"-ordering. 23 | For example, to apply an F-ordering for a CONV state vector in `numpy`_: 24 | 25 | ``` 26 | # create phi array 27 | phi = np.zeros(n_state, n_spec + 1) 28 | # populate the phi array 29 | # index 0 is the temperature 30 | phi[:, 0] = temperatures[:] 31 | # index 1 is the pressure 32 | phi[:, 1] = pressures[:] 33 | # and indicies 2...n_spec are the moles of the species in the model (excluding the last species) 34 | phi[:, 2:] = moles[:, :-1] 35 | # and finally, convert to F-order 36 | phi = np.copy(phi, order='F') 37 | ``` 38 | 39 | .. _numpy: http://numpy.org 40 | .. _interface_vs_exe: `Difference between Interface and Executable Libraries` 41 | 42 | .. _vector_split: 43 | 44 | ================================================================= 45 | Data Ordering for Calling pyJac from Other Codes (Interface Mode) 46 | ================================================================= 47 | 48 | When calling pyJac's generated source-term \ Jacobian codes directly from another code (see :ref:`interface_vs_exe`), the supplied data must be in pyJac's own internal data-format. 49 | 50 | As described in the pyJac-v2 paper (:ref:`paper`), pyJac uses a vectorized data-ordering for some cases. Here we will define some terms to improve clarity: 51 | 52 | * The **split_axis** is the axis in the array (**Note: before the split is applied**) that will be split into two new axes, a vector axis and another axis (which may or may not be important). 53 | * The **vector_axis** results from the splitting, and is of length :ref:`vector-width`. 54 | * The **grow_axis** is the array axis that will grow with increasing numbers of initial conditions. 55 | 56 | For example purposes, we will consider in this section an array of species concentrations (see :cref:`array_ordering`) for 1000 thermo-chemical states for a model with 20 chemical species and a vector width of 8. 57 | The array's shape before splitting is: :math:`\left(1000, 20\right)`. 58 | 59 | There are currently three situations where pyJac will automatically utilize a vectorized data ordering: 60 | 61 | 1) A shallow-vectorized, C-ordered code is generated. In this case: 62 | 63 | * The **split_axis** corresponds to the initial conditions axis (i.e., zero, in zero-based indexing). 64 | * After the split, the array will be converted to shape :math:`\left(125, 20, 8\right)`, 65 | * the **vector_axis** will be the last axis in the array (after the species axis in :ref:`array_ordering`, and of length :ref:`vector-width`, 66 | * and the **grow_axis** will be axis zero, and will be size `np.ceil(n_state / vector_width)`. 67 | 68 | This corresponds to ordering: 69 | 70 | .. math:: 71 | [C]_{0, 0}, \ldots [C]_{vw, 0}, [C]_{0, 1}, \ldots [C]_{vw, 1} \ldots, \text{etc.} 72 | 73 | for a vector width ":math:`vw`". This data-layout orders the concentrations for a given species :math:`k` for :math:`vw` thermo-chemical states sequentially in memory, followed by the concentrations of species :math:`k + 1` for the same states. This is important so that SIMD-instructions do not need to perform expensive gather / scatter operations. 74 | 75 | 2) A deep-vectorized, F-ordered code is generated. This is similar to case #1. 76 | 77 | * The **split_axis** corresponds to the last axis in the array, i.e., the species axis (axis one). 78 | * After the split, the array will be converted to shape :math:`\left(8, 1000, 3\right)`, 79 | * the **vector_axis** is the first axis in the array (axis 0), and of length :math:`vw`, 80 | * and the **grow_axis** is the initial-conditions axis (the size of which is unchanged in this case), i.e., axis one. 81 | 82 | This corresponds to ordering: 83 | 84 | .. math:: 85 | [C]_{0, 0}, \ldots [C]_{0, vw}, [C]_{1, 0}, \ldots [C]_{1, vw} \ldots, \text{etc.} 86 | 87 | for a vector width ":math:`vw`". This data-layout orders the concentrations for a given thermo-chemical state :math:`j` for :math:`vw` species sequentially in memory, followed by the thermo-chemical state :math:`j + 1` for the same species. This is important to ensure coalesced memory accesses on the GPU. 88 | 89 | 90 | 3) Explicit-SIMD (:ref:`simd`) is used, and neither of the previous two cases apply. In this case, the axes of the array may be padded (but not re-ordered) to ensure that the array can properly be vectorized. For example, again using the species concentration array from :ref:`array_ordering`, let us consider an array of 20 species, for 1000 thermo-chemical states, and a vector-width of 8. If a "C"-ordering is used: 91 | 92 | * The **split_axis** will be the species axis in unsplit array (axis one). 93 | * After the split, the array will be resized to shape :math:`\left(1000, 3, 8\right)` such that the species axis can be properly vectorized, and: 94 | * The **vector_axis** is the last axis of the array of the split array (axis two). 95 | * The **grow_axis** is axis zero. 96 | 97 | Conversely, if a "F"-ordering is used: 98 | 99 | * The **split_axis** will be the initial condition axis in unsplit array (axis zero). 100 | * After the split, the array will be resized to shape :math:`\left(8, 125, 20\right)` such that the initial condition axis is properly vectorized, and: 101 | * The **vector_axis** is the first axis of the array of the split array (axis zero). 102 | * The **grow_axis** is axis one. 103 | 104 | .. _paper: `dummy` 105 | .. _simd: `dummy2` 106 | .. _vecwidth: `vector-width` 107 | -------------------------------------------------------------------------------- /docs/faqs.rst: -------------------------------------------------------------------------------- 1 | Frequently asked Questions 2 | ########################## 3 | 4 | I get an error stating: 5 | ``` 6 | OSError: dlopen: cannot load any more object with static TLS 7 | ``` 8 | when running validation testing. 9 | ---------------------------------------------------------------------- 10 | 11 | This has been known to occur in SLURM or related 12 | job-batch systems when loading the Adept library for auto-differentiation execution. 13 | To work around this, [you should set the environment variable `LD_PRELOAD`](https://stackoverflow.com/a/45640803/1667311), e.g.: 14 | ``` 15 | LD_PRELOAD=/path/to/adept/install/lib/libadept.so python -m pyjac.functional_tester ... 16 | ``` 17 | 18 | I get an error complaining that the function `timersub` doesn't exist! 19 | ---------------------------------------------------------------------- 20 | 21 | Whoo-boy, congrats on using a very old server! For reference, I've run into this as well. 22 | To fix this, add the following to your `siteconf.py`: 23 | 24 | ``` 25 | CC_FLAGS = ['-D_BSD_SOURCE -D_SVID_SOURCE -D_POSIX_C_SOURCE=200809'] 26 | `` 27 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. pyJac documentation master file, created by 2 | sphinx-quickstart on Tue Apr 12 16:33:22 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | pyJac 7 | ===== 8 | 9 | **pyJac** is a Python package that generates source code used to analytically 10 | calculate chemical kinetics Jacobian matrices, customized for a particular 11 | model/reaction mechanism. 12 | 13 | **pyJac** welcomes your feedback and/or contributions. It relies heavily on 14 | the `numpy`_ libraries for core functionality, and other libraries including 15 | the `Cython`_ language and `Cantera`_ for functional and performance testing. 16 | 17 | .. _numpy: http://numpy.org 18 | .. _Cython: http://cython.org 19 | .. _Cantera: http://www.cantera.org 20 | 21 | Documentation 22 | ------------- 23 | 24 | .. toctree:: 25 | :maxdepth: 1 26 | 27 | overview 28 | faqs 29 | examples 30 | installing 31 | src/index 32 | 33 | 34 | Indices and tables 35 | ------------------ 36 | 37 | * :ref:`genindex` 38 | * :ref:`modindex` 39 | * :ref:`search` 40 | 41 | Citation 42 | -------- 43 | 44 | Up-to-date information about citing **pyJac** can be found within the 45 | `CITATION.md`_ file. 46 | 47 | .. _CITATION.md: https://github.com/slackha/pyJac/blob/master/CITATION.md 48 | 49 | See also 50 | -------- 51 | 52 | - The published `pyJac v1 paper`_ 53 | - Kyle Niemeyer, Nick Curtis, and Chih-Jen Sung's `WSSCI Fall 2015 paper`_ introducing 54 | - The associated `WSSCI Fall 2015 slides`_ 55 | 56 | .. _pyJac v1 paper: https://arxiv.org/abs/1605.03262 57 | .. _WSSCI Fall 2015 paper: https://dx.doi.org/10.6084/m9.figshare.2075515.v1 58 | .. _WSSCI Fall 2015 slides: http://www.slideshare.net/kyleniemeyer/initial-investigation-of-pyjac-an-analytical-jacobian-generator-for-chemical-kinetics 59 | 60 | Get in touch 61 | ------------ 62 | 63 | - Please report bugs, suggest feature ideas, and browse the source code `on GitHub`_. 64 | - There, new contributors can also find `a guide to contributing`_. 65 | - Additionally, you may join our `user group`_ for further support and to be notified of new releases, features, etc. 66 | - You can also contact Kyle `on Twitter`_. 67 | 68 | .. _on GitHub: https://github.com/slackha/pyJac 69 | .. _a guide to contributing: https://github.com/slackha/pyJac/blob/master/CONTRIBUTING.md 70 | .. _user group: https://groups.io/g/slackha-users 71 | .. _on Twitter: http://twitter.com/kyleniemeyer 72 | 73 | 74 | License 75 | ------- 76 | 77 | **pyJac** is available under the open-source `MIT License`__. 78 | 79 | __ https://raw.githubusercontent.com/kyleniemeyer/pyJac/master/LICENSE 80 | -------------------------------------------------------------------------------- /docs/installing.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ############ 3 | 4 | A setup.py file is provided with pyJac. To install pyJac, call 5 | 6 | .. code-block:: bash 7 | 8 | python setup.py install 9 | 10 | You can also easily install (including dependencies) using ``pip``: 11 | 12 | .. code-block:: bash 13 | 14 | pip install pyjac 15 | 16 | If installing via ``pip``, necessary Python dependencies will be installed if 17 | not already present. 18 | 19 | However, you will also need to separately install `Cantera`_ to read mechanism 20 | files in that format or run the partially stirred reactor (PaSR) module 21 | (``pyjac.functional_tester.partially_stirred_reactor``). 22 | 23 | Please let us know if you run into trouble installing pyJac. 24 | 25 | ======= 26 | Testing 27 | ======= 28 | 29 | Functional testing of the routines generated by pyJac (provided by the 30 | ``pyjac.functional_tester`` module) requires the installation of `Adept`_, 31 | a C++-based automatic differentiation library. For now, this should be 32 | installed into ``/usr/local/include``. 33 | 34 | .. _Cantera: http://www.cantera.org 35 | .. _Adept: https://github.com/rjhogan/Adept 36 | -------------------------------------------------------------------------------- /docs/overview.rst: -------------------------------------------------------------------------------- 1 | Overview 2 | ######## 3 | 4 | .. _state-vector: 5 | 6 | pyJac creates the C or CUDA source code files necessary to evaluate the 7 | analytical Jacobian matrix for a constant-pressure reacting system. 8 | 9 | .. _state_vec: 10 | 11 | ============ 12 | State Vector 13 | ============ 14 | 15 | Briefly, a thermochemical state is described using a composition vector: 16 | 17 | .. math:: 18 | \Phi = \left \lbrace T, Y_1, Y_2, \dotsc, 19 | Y_{N_{\text{sp}} - 1} \right \rbrace^{\text{T}} 20 | 21 | where *T* is the temperature, :math:`Y_i` are the mass fractions, and 22 | :math:`N_{\text{sp}}` is the number of species in the model. The mass fraction 23 | of the final species is determined through conservation of mass: 24 | 25 | .. math:: 26 | Y_{N_{\text{sp}}} = 1 - \sum_{k=1}^{N_{\text{sp}} - 1} Y_k 27 | 28 | .. _jacobian_formulation: 29 | 30 | ==================== 31 | Jacobian Formulation 32 | ==================== 33 | 34 | The governing equations of chemical kinetics include ordinary differential 35 | equations for the rate of change of temperature and the species' mass fractions: 36 | 37 | .. math:: 38 | f &= \frac{\partial \Phi}{\partial t} \\ 39 | &= \left \lbrace \frac{\partial T}{\partial t}, 40 | \frac{\partial Y_1}{\partial t}, \frac{\partial Y_2}{\partial t}, 41 | \dotsc, \frac{\partial Y_{N_{\text{sp}} - 1}}{\partial t} 42 | \right \rbrace^{\text{T}} 43 | 44 | where 45 | 46 | .. math:: 47 | \frac{\partial T}{\partial t} &= \frac{-1}{\rho c_p} 48 | \sum_{k=1}^{N_{\text{sp}}} h_k W_k \dot{\omega}_k \\ 49 | \frac{\partial Y_k}{\partial t} &= \frac{1}{\rho} W_k 50 | \dot{\omega}_k \quad k = 1, \dotsc, N_{\text{sp}} - 1 51 | 52 | where :math:`c_p` is the mass-averaged constant-pressure specific heat, 53 | :math:`h_k` is the specific enthalpy of species *k*, and :math:`\dot{\omega}_k` 54 | is the overall production rate of species *k*. 55 | 56 | The Jacobian matrix is then filled by the partial derivaties 57 | :math:`\partial f / \partial \Phi`, such that 58 | 59 | .. math:: 60 | \mathcal{J}_{i,j} = \frac{\partial f_i}{\partial \Phi_j} 61 | 62 | More details can be found in the paper fully describing version 1.0.3 of pyJac: 63 | https://Niemeyer-Research-Group.github.io/pyJac-paper/ -------------------------------------------------------------------------------- /docs/src/index.rst: -------------------------------------------------------------------------------- 1 | pyJac API 2 | ========= 3 | 4 | This is automaticaly generated API documentation from pyJac source files. 5 | 6 | Click the "modules" (:ref:`modindex`) link to browse the modules. 7 | Or, dive right into the autogenerated :doc:`pyjac` docs. 8 | -------------------------------------------------------------------------------- /docs/src/modules.rst: -------------------------------------------------------------------------------- 1 | pyjac 2 | ===== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | pyjac 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.core.CParams.rst: -------------------------------------------------------------------------------- 1 | pyjac.core.CParams module 2 | ========================= 3 | 4 | .. automodule:: pyjac.core.CParams 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.core.CUDAParams.rst: -------------------------------------------------------------------------------- 1 | pyjac.core.CUDAParams module 2 | ============================ 3 | 4 | .. automodule:: pyjac.core.CUDAParams 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.core.cache_optimizer.rst: -------------------------------------------------------------------------------- 1 | pyjac.core.cache_optimizer module 2 | ================================= 3 | 4 | .. automodule:: pyjac.core.cache_optimizer 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.core.chem_utilities.rst: -------------------------------------------------------------------------------- 1 | pyjac.core.chem_utilities module 2 | ================================ 3 | 4 | .. automodule:: pyjac.core.chem_utilities 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.core.create_jacobian.rst: -------------------------------------------------------------------------------- 1 | pyjac.core.create_jacobian module 2 | ================================= 3 | 4 | .. automodule:: pyjac.core.create_jacobian 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.core.mech_auxiliary.rst: -------------------------------------------------------------------------------- 1 | pyjac.core.mech_auxiliary module 2 | ================================ 3 | 4 | .. automodule:: pyjac.core.mech_auxiliary 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.core.mech_interpret.rst: -------------------------------------------------------------------------------- 1 | pyjac.core.mech_interpret module 2 | ================================ 3 | 4 | .. automodule:: pyjac.core.mech_interpret 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.core.rate_subs.rst: -------------------------------------------------------------------------------- 1 | pyjac.core.rate_subs module 2 | =========================== 3 | 4 | .. automodule:: pyjac.core.rate_subs 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.core.rst: -------------------------------------------------------------------------------- 1 | pyjac.core package 2 | ================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | 9 | pyjac.core.CParams 10 | pyjac.core.CUDAParams 11 | pyjac.core.cache_optimizer 12 | pyjac.core.chem_utilities 13 | pyjac.core.create_jacobian 14 | pyjac.core.mech_auxiliary 15 | pyjac.core.mech_interpret 16 | pyjac.core.rate_subs 17 | pyjac.core.shared_memory 18 | 19 | Module contents 20 | --------------- 21 | 22 | .. automodule:: pyjac.core 23 | :members: 24 | :undoc-members: 25 | :show-inheritance: 26 | -------------------------------------------------------------------------------- /docs/src/pyjac.core.shared_memory.rst: -------------------------------------------------------------------------------- 1 | pyjac.core.shared_memory module 2 | =============================== 3 | 4 | .. automodule:: pyjac.core.shared_memory 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.functional_tester.partially_stirred_reactor.rst: -------------------------------------------------------------------------------- 1 | pyjac.functional_tester.partially_stirred_reactor module 2 | ======================================================== 3 | 4 | .. automodule:: pyjac.functional_tester.partially_stirred_reactor 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.functional_tester.rst: -------------------------------------------------------------------------------- 1 | pyjac.functional_tester package 2 | =============================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | 9 | pyjac.functional_tester.partially_stirred_reactor 10 | pyjac.functional_tester.test 11 | 12 | Module contents 13 | --------------- 14 | 15 | .. automodule:: pyjac.functional_tester 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | -------------------------------------------------------------------------------- /docs/src/pyjac.functional_tester.test.rst: -------------------------------------------------------------------------------- 1 | pyjac.functional_tester.test module 2 | =================================== 3 | 4 | .. automodule:: pyjac.functional_tester.test 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.libgen.libgen.rst: -------------------------------------------------------------------------------- 1 | pyjac.libgen.libgen module 2 | ========================== 3 | 4 | .. automodule:: pyjac.libgen.libgen 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.libgen.rst: -------------------------------------------------------------------------------- 1 | pyjac.libgen package 2 | ==================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | 9 | pyjac.libgen.libgen 10 | 11 | Module contents 12 | --------------- 13 | 14 | .. automodule:: pyjac.libgen 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | -------------------------------------------------------------------------------- /docs/src/pyjac.performance_tester.performance_tester.rst: -------------------------------------------------------------------------------- 1 | pyjac.performance_tester.performance_tester module 2 | ================================================== 3 | 4 | .. automodule:: pyjac.performance_tester.performance_tester 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.performance_tester.rst: -------------------------------------------------------------------------------- 1 | pyjac.performance_tester package 2 | ================================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | 9 | pyjac.performance_tester.performance_tester 10 | 11 | Module contents 12 | --------------- 13 | 14 | .. automodule:: pyjac.performance_tester 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | -------------------------------------------------------------------------------- /docs/src/pyjac.pywrap.parallel_compiler.rst: -------------------------------------------------------------------------------- 1 | pyjac.pywrap.parallel_compiler module 2 | ===================================== 3 | 4 | .. automodule:: pyjac.pywrap.parallel_compiler 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.pywrap.pywrap_gen.rst: -------------------------------------------------------------------------------- 1 | pyjac.pywrap.pywrap_gen module 2 | ============================== 3 | 4 | .. automodule:: pyjac.pywrap.pywrap_gen 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/src/pyjac.pywrap.rst: -------------------------------------------------------------------------------- 1 | pyjac.pywrap package 2 | ==================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | 9 | pyjac.pywrap.parallel_compiler 10 | pyjac.pywrap.pywrap_gen 11 | 12 | Module contents 13 | --------------- 14 | 15 | .. automodule:: pyjac.pywrap 16 | :members: 17 | :undoc-members: 18 | :show-inheritance: 19 | -------------------------------------------------------------------------------- /docs/src/pyjac.rst: -------------------------------------------------------------------------------- 1 | pyjac package 2 | ============= 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | 9 | pyjac.core 10 | pyjac.functional_tester 11 | pyjac.libgen 12 | pyjac.performance_tester 13 | pyjac.pywrap 14 | 15 | Submodules 16 | ---------- 17 | 18 | .. toctree:: 19 | 20 | pyjac.utils 21 | 22 | Module contents 23 | --------------- 24 | 25 | .. automodule:: pyjac 26 | :members: 27 | :undoc-members: 28 | :show-inheritance: 29 | -------------------------------------------------------------------------------- /docs/src/pyjac.utils.rst: -------------------------------------------------------------------------------- 1 | pyjac.utils module 2 | ================== 3 | 4 | .. automodule:: pyjac.utils 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /npy_convert.py: -------------------------------------------------------------------------------- 1 | """A simple utility script that converts saved numpy files 2 | from a Temperature, Pressure, Mass Fraction format to 3 | Temperature, Pressure, Concentrations""" 4 | 5 | import numpy as np 6 | import cantera as ct 7 | import os 8 | import argparse 9 | 10 | 11 | def main(input_dir='', output_dir='', mech=''): 12 | assert input_dir != output_dir, 'Cannot convert in same folder' 13 | gas = ct.Solution(mech) 14 | 15 | npy_files = [f for f in os.listdir(input_dir)] 16 | npy_files = [f for f in npy_files if f.endswith('.npy') 17 | and os.path.isfile(os.path.join(input_dir, f))] 18 | for npy in sorted(npy_files): 19 | state_data = np.load(os.path.join(input_dir, npy)) 20 | state_data = state_data.reshape(state_data.shape[0] * 21 | state_data.shape[1], 22 | state_data.shape[2] 23 | ) 24 | out_data = np.zeros((state_data.shape[0], gas.n_species + 2)) 25 | for i in range(state_data.shape[0]): 26 | # convert to T, P, C 27 | gas.TPY = state_data[i, 1], state_data[i, 2], state_data[i, 3:] 28 | out_data[i, 0] = gas.T 29 | out_data[i, 1] = gas.P 30 | out_data[i, 2:] = gas.concentrations[:] 31 | 32 | np.save(os.path.join(output_dir, 33 | npy), out_data) 34 | 35 | 36 | if __name__ == '__main__': 37 | parser = argparse.ArgumentParser(description=( 38 | 'A simple utility script that converts saved numpy files' 39 | 'from a Temperature, Pressure, Mass Fraction format to' 40 | 'Temperature, Pressure, Concentrations')) 41 | parser.add_argument('-i', '--input_dir', 42 | type=str, 43 | required=True, 44 | help='The directory to scan for .npy files.' 45 | ) 46 | parser.add_argument('-o', '--output_dir', 47 | type=str, 48 | required=True, 49 | help='The directory to place the converted .npy files.' 50 | ) 51 | parser.add_argument('-m', '--mech', 52 | type=str, 53 | required=True, 54 | help='The Cantera format mechanism to use.') 55 | args = parser.parse_args() 56 | main(input_dir=args.input_dir, 57 | output_dir=args.output_dir, 58 | mech=args.mech) 59 | -------------------------------------------------------------------------------- /optional-requirements.txt: -------------------------------------------------------------------------------- 1 | nose 2 | nose-exclude 3 | nose-testconfig 4 | nose-timer 5 | parameterized 6 | optionloop >= 1.0.7 7 | cantera >= 2.3.0 8 | scipy 9 | tables 10 | psutil 11 | pyopencl 12 | -------------------------------------------------------------------------------- /pyjac/__init__.py: -------------------------------------------------------------------------------- 1 | from pyjac._version import __version__, __version_info__ 2 | from pyjac.core.create_jacobian import create_jacobian 3 | from pyjac import siteconf 4 | from pyjac import utils 5 | 6 | __all__ = ['__version__', '__version_info__', 'create_jacobian', 7 | 'siteconf', 'utils'] 8 | -------------------------------------------------------------------------------- /pyjac/__main__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from pyjac import utils 4 | 5 | 6 | def main(args=None): 7 | if args is None: 8 | utils.create() 9 | 10 | 11 | if __name__ == '__main__': 12 | sys.exit(main()) 13 | -------------------------------------------------------------------------------- /pyjac/_version.py: -------------------------------------------------------------------------------- 1 | __version_info__ = (2, 0, 0, 'beta', 1) 2 | __version__ = '.'.join(map(str, __version_info__[:3])) 3 | -------------------------------------------------------------------------------- /pyjac/core/__init__.py: -------------------------------------------------------------------------------- 1 | from pyjac.core.create_jacobian import create_jacobian, determine_jac_inds, \ 2 | find_last_species 3 | from pyjac.core.rate_subs import assign_rates 4 | from pyjac.core.mech_interpret import read_mech, read_mech_ct 5 | 6 | __all__ = ["create_jacobian", "determine_jac_inds", "find_last_species", 7 | "assign_rates", "read_mech", "read_mech_ct"] 8 | -------------------------------------------------------------------------------- /pyjac/core/enum_types.py: -------------------------------------------------------------------------------- 1 | from enum import Enum, IntEnum 2 | 3 | 4 | class reaction_type(Enum): 5 | """ 6 | The reaction type 7 | """ 8 | elementary = 1 9 | thd = 2 10 | fall = 3 11 | chem = 4 12 | plog = 5 13 | cheb = 6 14 | 15 | def __int__(self): 16 | return self.value 17 | 18 | 19 | class thd_body_type(Enum): 20 | """ 21 | The form of the third body concentration modification 22 | """ 23 | none = 0 24 | mix = 1 25 | species = 2 26 | unity = 3 27 | 28 | def __int__(self): 29 | return self.value 30 | 31 | def __long__(self): 32 | return self.value 33 | 34 | 35 | class falloff_form(Enum): 36 | """ 37 | The form of the falloff reaction type 38 | """ 39 | none = 0 40 | lind = 1 41 | troe = 2 42 | sri = 3 43 | 44 | def __int__(self): 45 | return self.value 46 | 47 | 48 | class reversible_type(Enum): 49 | """ 50 | Whether the reaction is reversible or not 51 | """ 52 | non_reversible = 1 53 | explicit = 2 54 | non_explicit = 3 55 | 56 | def __int__(self): 57 | return self.value 58 | 59 | 60 | class reaction_sorting(Enum): 61 | """ 62 | The reaction sorting scheme 63 | """ 64 | none = 0, 65 | simd = 1 66 | 67 | 68 | class RateSpecialization(IntEnum): 69 | """ 70 | The form of reaction rate specialization, see 71 | :func:`pyjac.core.rate_subs.assign_rates` 72 | """ 73 | fixed = 0, 74 | hybrid = 1, 75 | full = 2 76 | 77 | 78 | class JacobianType(IntEnum): 79 | """ 80 | The Jacobian type to be constructed. 81 | 82 | - An exact Jacobian has no approximations for reactions including the last 83 | species, 84 | - An approximate Jacobian ignores the derivatives of these reactions from 85 | species not directly involved (i.e. fwd/rev stoich coeff == 0, and not a third 86 | body species) while in a reaction including the last species 87 | - A finite differnce Jacobian is constructed from finite differences of the 88 | species rate kernel 89 | """ 90 | exact = 0, 91 | approximate = 1, 92 | finite_difference = 2 93 | 94 | # TODO - provide an "approximate" FD? 95 | 96 | 97 | class JacobianFormat(IntEnum): 98 | """ 99 | The Jacobian format to use, full or sparse. 100 | 101 | A full Jacobian will include all zeros, while a sparse Jacobian will use either 102 | a Compressed Row/Column storage based format depending on the data-order ('C' 103 | and 'F' respectively) 104 | """ 105 | full = 0, 106 | sparse = 1 107 | 108 | 109 | class FiniteDifferenceMode(IntEnum): 110 | """ 111 | The mode of finite differences--forwards, backwards or central--used to create 112 | the finite difference Jacobian 113 | """ 114 | forward = 0, 115 | central = 1, 116 | backward = 2 117 | 118 | 119 | class KernelType(Enum): 120 | """ 121 | The kernel type being generated. 122 | """ 123 | chem_utils = 1, 124 | species_rates = 2, 125 | jacobian = 3 126 | dummy = 4 127 | 128 | def __int__(self): 129 | return self.value 130 | 131 | 132 | class DriverType(Enum): 133 | """ 134 | The type of kernel driver to generate for evaluation of the kernel over many 135 | initial conditions 136 | """ 137 | queue = 0, 138 | lockstep = 1 139 | 140 | 141 | class DeviceMemoryType(Enum): 142 | """ 143 | The type of memory to use for platforms with separate device memory pools 144 | (e.g., CUDA, OpenCL) 145 | """ 146 | pinned = 0, 147 | mapped = 1 148 | 149 | def __int__(self): 150 | return self.value 151 | -------------------------------------------------------------------------------- /pyjac/core/exceptions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Contains custom errors / exceptions / error processing 3 | """ 4 | 5 | 6 | import six 7 | 8 | 9 | class MissingPlatformError(Exception): 10 | """ 11 | The pyopencl platform requested for testing could not be found 12 | """ 13 | 14 | def __init__(self, platform): 15 | self.platform = platform 16 | self.message = 'PyOpenCL platform {} requested for testing not found'.format( 17 | self.platform) 18 | super(MissingPlatformError, self).__init__(self.message) 19 | 20 | 21 | class MissingDeviceError(Exception): 22 | """ 23 | No devices found on the specified pyopencl platform 24 | """ 25 | 26 | def __init__(self, device_type, platform): 27 | self.device_type = device_type 28 | self.platform = platform 29 | self.message = 'Cannot find devices of type {} on platform {}'.format( 30 | self.device_type, self.platform) 31 | super(MissingDeviceError, self).__init__(self.message) 32 | 33 | 34 | class CompilationError(Exception): 35 | """ 36 | Error during compilation 37 | """ 38 | 39 | def __init__(self, files): 40 | if isinstance(files, str): 41 | files = [files] 42 | self.message = 'Error compiling file(s): {}.'.format(','.join(files)) 43 | super(CompilationError, self).__init__(self.message) 44 | 45 | 46 | class LinkingError(Exception): 47 | """ 48 | Error during linking 49 | """ 50 | 51 | def __init__(self, files): 52 | if isinstance(files, str): 53 | files = [files] 54 | self.message = 'Error linking file(s): {}.'.format(','.join(files)) 55 | super(LinkingError, self).__init__(self.message) 56 | 57 | 58 | class LibraryGenerationError(Exception): 59 | """ 60 | Error during library generation 61 | """ 62 | 63 | def __init__(self): 64 | self.message = 'Error generating pyJac library.' 65 | super(LibraryGenerationError, self).__init__(self.message) 66 | 67 | 68 | class BrokenPlatformError(Exception): 69 | """ 70 | The combination of platform and vectorization options is broken 71 | """ 72 | 73 | def __init__(self, loopy_opts): 74 | platform = loopy_opts.platform 75 | options = 'wide = {}, deep = {}, explicit simd = {}'.format( 76 | bool(loopy_opts.width), 77 | bool(loopy_opts.depth), 78 | bool(loopy_opts.is_simd)) 79 | self.message = ('The platform {} is currently broken for' 80 | ' vectorization options {}'.format(platform, options)) 81 | super(BrokenPlatformError, self).__init__(self.message) 82 | 83 | 84 | def validation_error_to_string(error): 85 | """ 86 | Responsible for converting a :class:`cerberus.ValidatonError` to something human 87 | readable 88 | 89 | Returns 90 | ------- 91 | error: str 92 | The stringified error 93 | """ 94 | 95 | def __stringify(root): 96 | error_list = [] 97 | for k, v in six.iteritems(root): 98 | if isinstance(v, list) and any(isinstance(x, dict) for x in v): 99 | error_list.extend(__stringify(x) for x in v) 100 | elif isinstance(v, dict): 101 | error_list.extend(__stringify(v)) 102 | else: 103 | error_list.append('{}: {}'.format(k, ' | '.join( 104 | vi for vi in v))) 105 | return error_list 106 | 107 | message = 'Error validating document:\n' 108 | message += '\n'.join(['\t{}'.format(e) for e in __stringify(error)]) 109 | 110 | return message 111 | 112 | 113 | class ValidationError(Exception): 114 | """ 115 | Raised if a user-specified platform or test matrix fails to validate against 116 | our internal schemas 117 | """ 118 | 119 | def __init__(self, file, schemaname): 120 | self.message = ( 121 | 'File {} failed to validate against schema {}, see ' 122 | 'debug output for more info.'.format(file, schemaname)) 123 | super(ValidationError, self).__init__(self.message) 124 | 125 | 126 | class UnknownOverrideException(Exception): 127 | def __init__(self, otype, path): 128 | self.message = ( 129 | 'Override type "{}" for path {} is unknown'.format(otype, path)) 130 | super(UnknownOverrideException, self).__init__(self.message) 131 | 132 | 133 | class InvalidOverrideException(Exception): 134 | def __init__(self, otype, value, allowed): 135 | from pyjac.utils import stringify_args 136 | self.message = ( 137 | 'Value "{}" for override type "{}" is not allowed. ' 138 | 'Allowed values are: {}'.format(otype, value, stringify_args( 139 | allowed))) 140 | super(InvalidOverrideException, self).__init__(self.message) 141 | 142 | 143 | class OverrideCollisionException(Exception): 144 | def __init__(self, override_type, path): 145 | self.message = ('Conflicting/duplicate overrides of "{}" specified. ' 146 | 'Dectected for "{}"'.format( 147 | override_type, path)) 148 | super(OverrideCollisionException, self).__init__(self.message) 149 | 150 | 151 | class DuplicateTestException(Exception): 152 | def __init__(self, rtype, etype, filename): 153 | self.message = ('Multiple test types of "{}"" for evaluation type "{}" ' 154 | 'detected in test matrix file {}'.format( 155 | rtype, etype, filename)) 156 | super(DuplicateTestException, self).__init__(self.message) 157 | 158 | 159 | class InvalidTestEnvironmentException(Exception): 160 | def __init__(self, ttype, key, file, envvar): 161 | self.message = ('Test type "{}"" has overrides for key "{}"" specified in' 162 | 'test matrix file "{}", however this override cannot be ' 163 | 'applied, as it would invalidate the test environment ' 164 | 'key "{}"'.format(ttype, key, file, envvar)) 165 | super(InvalidTestEnvironmentException, self).__init__(self.message) 166 | 167 | 168 | class InvalidInputSpecificationException(Exception): 169 | def __init__(self, bad_inputs): 170 | from pyjac.utils import stringify_args, listify 171 | self.message = ('Inputs: ({}) were incorrectly, or conflictingly specified. ' 172 | 'See debug output for more information'.format( 173 | stringify_args(listify(bad_inputs)))) 174 | super(InvalidInputSpecificationException, self).__init__(self.message) 175 | -------------------------------------------------------------------------------- /pyjac/core/mech_auxiliary.py: -------------------------------------------------------------------------------- 1 | """Writes mechanism header and output testing files 2 | """ 3 | 4 | # Python 2 compatibility 5 | from __future__ import division 6 | from __future__ import print_function 7 | 8 | # Standard libraries 9 | import os 10 | 11 | # Local imports 12 | from pyjac import utils 13 | from pyjac.kernel_utils import file_writers as filew 14 | 15 | 16 | def write_aux(path, loopy_opts, specs, reacs): 17 | write_mechanism_header(path, loopy_opts.lang, specs, reacs) 18 | write_vec_header(path, loopy_opts.lang, loopy_opts) 19 | 20 | 21 | def write_mechanism_header(path, lang, specs, reacs): 22 | with filew.get_header_file( 23 | os.path.join(path, 'mechanism' + utils.header_ext[lang]), lang) as file: 24 | # define NR, NS, NN, etc. 25 | file.add_define('NS', len(specs)) 26 | file.add_define('NR', len(reacs)) 27 | file.add_define('NN', len(specs) + 1) 28 | 29 | 30 | def write_vec_header(path, lang, loopy_opts): 31 | with filew.get_header_file( 32 | os.path.join(path, 'vectorization' + utils.header_ext[lang]), 33 | lang) as file: 34 | # define deep / wide / vecwidth 35 | if loopy_opts.width: 36 | file.add_define('WIDE') 37 | file.add_define('VECWIDTH', loopy_opts.width) 38 | elif loopy_opts.depth: 39 | file.add_define('DEEP') 40 | file.add_define('VECWIDTH', loopy_opts.depth) 41 | if loopy_opts.is_simd: 42 | file.add_define('EXPLICIT_SIMD') 43 | -------------------------------------------------------------------------------- /pyjac/core/unit_conversions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """Module for converting various input formats into pyJac's internal format""" 3 | 4 | # Python 2 compatibility 5 | from __future__ import division 6 | from __future__ import print_function 7 | 8 | # Standard libraries 9 | from string import Template 10 | 11 | # Non-standard librarys 12 | import numpy as np 13 | 14 | # Local imports 15 | from pyjac.kernel_utils import kernel_gen as k_gen 16 | from pyjac.core import array_creator as arc 17 | from pyjac.core import instruction_creator as ic 18 | from pyjac.core.array_creator import (global_ind, var_name, default_inds) 19 | 20 | 21 | def mass_to_mole_factions(loopy_opts, namestore, conp=True, test_size=None): 22 | """Converts input state vector from mass fractions to mole fractions and state 23 | variables depending on constant pressure vs constant volue assumption 24 | 25 | Parameters 26 | ---------- 27 | loopy_opts : `loopy_options` object 28 | A object containing all the loopy options to execute 29 | namestore : :class:`array_creator.NameStore` 30 | The namestore / creator for this method 31 | conp : bool 32 | If true, generate equations using constant pressure assumption 33 | If false, use constant volume equations 34 | test_size : int 35 | If not none, this kernel is being used for testing. 36 | Hence we need to size the arrays accordingly 37 | 38 | Notes 39 | ----- 40 | Assumes that this is being called at input only! 41 | This allows us to make the (generally) unsafe assumption that the mole factions 42 | are _equivalent_ to the moles, as the total number of moles will adjust to 43 | satisfy the ideal gas relation. 44 | 45 | 46 | Returns 47 | ------- 48 | knl_list : list of :class:`knl_info` 49 | The generated infos for feeding into the kernel generator for both 50 | equation types 51 | """ 52 | 53 | # first kernel, determine molecular weight 54 | mapstore = arc.MapStore(loopy_opts, namestore.num_specs_no_ns, test_size) 55 | 56 | # first, create all arrays 57 | kernel_data = [] 58 | 59 | # add problem size 60 | kernel_data.extend(arc.initial_condition_dimension_vars(loopy_opts, test_size)) 61 | 62 | # need "Yi" and molecular weight / factor arrays 63 | 64 | # add / apply maps 65 | mapstore.check_and_add_transform(namestore.n_arr, 66 | namestore.phi_spec_inds, 67 | force_inline=True) 68 | mapstore.check_and_add_transform(namestore.mw_post_arr, 69 | namestore.num_specs_no_ns, 70 | force_inline=True) 71 | 72 | Yi_arr, Yi_str = mapstore.apply_maps(namestore.n_arr, *default_inds) 73 | mw_inv_arr, mw_inv_str = mapstore.apply_maps(namestore.mw_inv, var_name) 74 | mw_work_arr, mw_work_str = mapstore.apply_maps(namestore.mw_work, global_ind) 75 | 76 | # add arrays 77 | kernel_data.extend([Yi_arr, mw_inv_arr, mw_work_arr]) 78 | 79 | # initialize molecular weight 80 | pre_instructions = Template( 81 | """ 82 | ${mw_work_str} = W_ns_inv {id=init} 83 | <> work = 0 {id=init_work} 84 | """ 85 | ).safe_substitute(**locals()) 86 | 87 | instructions = Template( 88 | """ 89 | work = work + (${mw_inv_str} - W_ns_inv) * ${Yi_str} \ 90 | {id=update, dep=init*} 91 | """).safe_substitute(**locals()) 92 | 93 | barrier = ic.get_barrier(loopy_opts, local_memory=False, 94 | id='break', dep='update') 95 | post_instructions = Template( 96 | """ 97 | ${barrier} 98 | ${mw_work_str} = (${mw_work_str} + work) {id=final, dep=break, nosync=init} 99 | """).substitute(**locals()) 100 | 101 | can_vectorize, vec_spec = ic.get_deep_specializer( 102 | loopy_opts, atomic_ids=['final'], init_ids=['init']) 103 | 104 | mw_kernel = k_gen.knl_info(name='molecular_weight_inverse', 105 | pre_instructions=[pre_instructions], 106 | instructions=instructions, 107 | post_instructions=[post_instructions], 108 | mapstore=mapstore, 109 | var_name=var_name, 110 | kernel_data=kernel_data, 111 | can_vectorize=can_vectorize, 112 | vectorization_specializer=vec_spec, 113 | parameters={'W_ns_inv': 1. / np.float64( 114 | namestore.mw_arr[-1])}, 115 | silenced_warnings=['write_race(final)', 116 | 'write_race(init)']) 117 | 118 | # now convert to moles 119 | mapstore = arc.MapStore(loopy_opts, namestore.num_specs_no_ns, test_size) 120 | 121 | # first, create all arrays 122 | kernel_data = [] 123 | 124 | # add problem size 125 | kernel_data.extend(arc.initial_condition_dimension_vars(loopy_opts, test_size)) 126 | 127 | # need input "Yi", molecular weight, and moles array 128 | 129 | # add / apply maps 130 | mapstore.check_and_add_transform(namestore.n_arr, 131 | namestore.phi_spec_inds, 132 | force_inline=True) 133 | 134 | n_arr, n_str = mapstore.apply_maps(namestore.n_arr, *default_inds) 135 | mw_work_arr, mw_work_str = mapstore.apply_maps(namestore.mw_work, global_ind) 136 | mw_inv_arr, mw_inv_str = mapstore.apply_maps(namestore.mw_inv, var_name) 137 | 138 | # add arrays 139 | kernel_data.extend([n_arr, mw_inv_arr, mw_work_arr]) 140 | 141 | pre_instructions = Template( 142 | '<> mw = 1 / ${mw_work_str} {id=init}').safe_substitute(**locals()) 143 | instructions = Template( 144 | """ 145 | ${n_str} = ${n_str} * ${mw_inv_str} * mw {dep=init} 146 | """).safe_substitute(**locals()) 147 | 148 | can_vectorize, vec_spec = ic.get_deep_specializer(loopy_opts) 149 | mf_kernel = k_gen.knl_info(name='mole_fraction', 150 | pre_instructions=[pre_instructions], 151 | instructions=instructions, 152 | mapstore=mapstore, 153 | var_name=var_name, 154 | kernel_data=kernel_data, 155 | can_vectorize=can_vectorize, 156 | vectorization_specializer=vec_spec) 157 | 158 | return [mw_kernel, mf_kernel] 159 | -------------------------------------------------------------------------------- /pyjac/examples/__init__.py: -------------------------------------------------------------------------------- 1 | # define path to examples 2 | import os 3 | examples_dir = os.path.abspath(os.path.dirname(__file__)) 4 | 5 | __all__ = ["examples_dir"] 6 | -------------------------------------------------------------------------------- /pyjac/examples/codegen_platform.yaml: -------------------------------------------------------------------------------- 1 | #################################################################################### 2 | # An example of test platforms specification, e.g., for unit-testing or # 3 | # performance / validation studies # 4 | # # 5 | # To see specification of a platform for codegeneration, see # 6 | # :file:`codegen_platform.yaml` # 7 | #################################################################################### 8 | 9 | 10 | # a CPU platform using POCL, wide vectorization and no atomics 11 | platform: 12 | name: portable 13 | lang: opencl 14 | # use a wide vectorization 15 | width: 4 16 | # Atomics are present in the POCL runtime 17 | atomic_doubles: True 18 | atomic_ints: True 19 | is_simd: True 20 | 21 | # limit memory usage 22 | memory-limits: 23 | # 1 gb of total global memory 24 | global: 1gb 25 | # 1 mb of total constant memory 26 | constant: 1mb 27 | # and a maximum global array size of 100 mb 28 | alloc: 100 Mb 29 | -------------------------------------------------------------------------------- /pyjac/examples/mem_limits_example.yaml: -------------------------------------------------------------------------------- 1 | # an example of appropriate memory limits for an Intel OpenCL platform 2 | # based on values taken from the queried limits 3 | # All units are in bytes [B], other recognized units are [GB, MB, KB] 4 | memory_limits: 5 | constant: 6 | # The maximum constant buffer size, as given by CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE 7 | 131072 B 8 | 9 | #local: 10 | # not specified 11 | 12 | alloc: 13 | # The max size of memory object allocation in bytes for OpenCL, 14 | # given by CL_DEVICE_MAX_MEM_ALLOC_SIZE 15 | 33746508800 B 16 | 17 | global: 18 | # Size of global device memory in bytes for OpenCL 19 | # given by CL_DEVICE_GLOBAL_MEM_SIZE 20 | 134986035200 B 21 | -------------------------------------------------------------------------------- /pyjac/examples/site_conf_example.py: -------------------------------------------------------------------------------- 1 | CL_INC_DIR = ['/opt/opencl-headers/'] 2 | CL_LIBNAME = ['OpenCL'] 3 | CL_VERSION = '1.2' 4 | CL_FLAGS = [] 5 | CC_FLAGS = [] 6 | LD_FLAGS = [] 7 | # relies on OCL-ICD 8 | CL_LIB_DIR = ['/usr/local/lib'] 9 | # Adept is used in functional testing / unit testing for verification of Jacobian 10 | # entries versus autodifferentiated results -- note that a standard install 11 | # (i.e. to /usr/local/lib) probably won't need these specified 12 | ADEPT_INC_DIR = ['/path/to/adept/include'] 13 | ADEPT_LIB_DIR = ['/path/to/adept/lib'] 14 | ADEPT_LIBNAME = ['adept'] 15 | -------------------------------------------------------------------------------- /pyjac/examples/test_matrix.yaml: -------------------------------------------------------------------------------- 1 | # an example of specifying the test matrix for pyJac's performance or validation 2 | 3 | # mechanisms are specified by a name and cantera format mechanism and optional path 4 | model-list: 5 | - name: TestMech 6 | mech: test.cti 7 | # specify the path to the model -- if not specified, the model is assumed to 8 | # be in either validation/name/ or performance/name/ depending on the test type 9 | path: 'pyjac/tests/' 10 | # limit the number of initial conditions tested (usually, due to memory 11 | # limitations) 12 | limits: 13 | species_rates: 10000000 14 | jacobian: 15 | sparse: 16 | 100000 17 | full: 18 | 1000 19 | - name: CH4 20 | # alternatively, one can specify the path to Null in order to load default 21 | # cantera mechnisms 22 | path: 23 | mech: gri30.cti 24 | 25 | # memory limits 26 | memory-limits: 27 | # for intel only 28 | - platforms: [intel] 29 | # 5 gigabyte total on global memory usage 30 | global: 5GB 31 | # 1 megabyte local memory 32 | local: 1MB 33 | # 64 kb constant memory 34 | constant: 64kb 35 | # 1gb limit on allocation of a single array 36 | alloc: 1 gb 37 | # now define one for OpenMP 38 | - platforms: [openmp] 39 | # 50 gig limit on OMP global mem 40 | global: 50 GB 41 | 42 | # list of platforms to use 43 | platform-list: 44 | - name: intel 45 | lang: opencl 46 | # use a wide-vectorization w/ vector-width of 2, 4 & 8 47 | # note: a parallel case will be added by default 48 | width: [2, 4, 8] 49 | atomic_doubles: False 50 | - name: openmp 51 | lang: c 52 | 53 | # test list 54 | test-list: 55 | # a validation test for both source rates & jacobian 56 | - test-type: validation 57 | eval-type: both 58 | # source rate performance test 59 | - test-type: performance 60 | eval-type: species_rates 61 | # overrides, controlling the species_rates test 62 | species_rates: 63 | order: ['F'] 64 | # a performance test for the jacobian 65 | - test-type: performance 66 | # limit to intel 67 | platforms: [intel] 68 | eval-type: jacobian 69 | # overrides, controlling the finite_difference tests 70 | finite_difference: 71 | both: 72 | # limit number of cores 73 | num_cores: [1] 74 | # use only parallel FD-evaluation 75 | width: [] 76 | depth: [] 77 | # C-order only 78 | order: ['C'] 79 | # conp-only 80 | conp: ['conp'] 81 | # overrides for the exact jacobian 82 | exact: 83 | both: 84 | # only test vector width of 4 85 | width: [4] 86 | -------------------------------------------------------------------------------- /pyjac/examples/test_platforms.yaml: -------------------------------------------------------------------------------- 1 | #################################################################################### 2 | # An example of test platforms specification, e.g., for unit-testing or # 3 | # performance / validation studies # 4 | # # 5 | # To see specification of a platform for codegeneration, see # 6 | # :file:`codegen_platform.yaml` # 7 | #################################################################################### 8 | 9 | platform-list: 10 | # a CPU platform using AMD-OpenCL, wide/deep vectorizations and atomics 11 | - name: amd 12 | lang: opencl 13 | # note, a non-vectorized case will be added automatically 14 | width: [2, 4] 15 | depth: [2, 4] 16 | atomic_doubles: True 17 | atomic_ints: True 18 | # use explicit-SIMD vectorization (when available) 19 | is_simd: [True] 20 | # a CPU platform using C and no vectorizations 21 | - name: openmp 22 | lang: c 23 | # only test C-ordered 24 | order: ['C'] 25 | # a GPU platform using OpenCL, wide vectorizations and a vector width of 64 26 | # without atomic (doubles) 27 | - name: nvidia 28 | lang: opencl 29 | width: [64, 128, 256] 30 | atomic_doubles: False 31 | atomic_ints: True 32 | -------------------------------------------------------------------------------- /pyjac/functional_tester/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SLACKHA/pyJac-v2/1cdd67bc4bdfdde37c9fa73674428187d5f875a8/pyjac/functional_tester/__init__.py -------------------------------------------------------------------------------- /pyjac/functional_tester/__main__.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | import sys 3 | from pyjac.functional_tester.test import species_rate_tester, jacobian_tester 4 | from pyjac import utils 5 | # turn off cache 6 | import loopy as lp 7 | 8 | 9 | def main(args=None): 10 | lp.set_caching_enabled(False) 11 | utils.setup_logging() 12 | if args is None: 13 | # command line arguments 14 | parser = ArgumentParser(description='Tests pyJac versus an' 15 | ' autodifferentiated jacobian\n') 16 | parser.add_argument('-w', '--working_directory', 17 | type=str, 18 | default='performance', 19 | help='Directory storing the mechanisms / data.' 20 | ) 21 | parser.add_argument('-t', '--test_matrix', 22 | type=str, 23 | help='The platforms / tests to run, as well as ' 24 | 'possible memory limits. For an example see' 25 | 'the pyjac/examples/test_matrix.yaml included with' 26 | 'pyJac' 27 | ) 28 | parser.add_argument('-r', '--runtype', 29 | choices=['jac', 'spec', 'both'], 30 | default='both', 31 | help='The type of validation test to run, Jacobian [jac]' 32 | ' or species rates [spec], or [both].') 33 | parser.add_argument('-p', '--prefix', 34 | type=str, 35 | default='', 36 | help='A prefix to store the output of this test in' 37 | 'for each mechanism in the working_directory.' 38 | 'This can be a helpful tool on a cluster to ' 39 | 'run multiple tests at once on different platforms') 40 | args = parser.parse_args() 41 | methods = [] 42 | if args.runtype == 'jac': 43 | methods = [jacobian_tester] 44 | elif args.runtype == 'spec': 45 | methods = [species_rate_tester] 46 | else: 47 | methods = [species_rate_tester, jacobian_tester] 48 | 49 | for m in methods: 50 | m(args.working_directory, args.test_matrix, args.prefix) 51 | 52 | 53 | if __name__ == '__main__': 54 | sys.exit(main()) 55 | -------------------------------------------------------------------------------- /pyjac/functional_tester/pasr_input.yaml: -------------------------------------------------------------------------------- 1 | # Input parameters for PaSR simulation. 2 | case: premixed 3 | temperature: 300.0 4 | pressure: 1.0 5 | equivalence ratio: 1.0 6 | fuel: 7 | H2: 1.0 8 | oxidizer: 9 | O2: 1.0 10 | N2: 3.76 11 | complete products: 12 | - H2O 13 | - N2 14 | number of particles: 100 15 | residence time: 10.e-3 16 | mixing time: 1.e-3 17 | pairing time: 1.e-3 18 | number of residence times: 10 19 | -------------------------------------------------------------------------------- /pyjac/kernel_utils/__init__.py: -------------------------------------------------------------------------------- 1 | from pyjac.kernel_utils.kernel_gen import knl_info 2 | 3 | __all__ = ['knl_info'] 4 | -------------------------------------------------------------------------------- /pyjac/kernel_utils/c/error_check.cpp: -------------------------------------------------------------------------------- 1 | /* A set of simple definitions that allow for assert-style error checking in 2 | * C-kernel setup 3 | * 4 | * Nicholas Curtis - 2017 5 | */ 6 | 7 | #include "error_check.hpp" 8 | 9 | void cpu_assert(bool x, const char* message, const char *file, int line) { 10 | if (!x) 11 | { 12 | fprintf(stderr, "cpu_assert: %s %s %d\n", message, file, line); 13 | exit(-1); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /pyjac/kernel_utils/c/error_check.hpp: -------------------------------------------------------------------------------- 1 | /* A set of simple definitions that allow for assert-style error checking in 2 | * C-kernel setup 3 | * 4 | * Nicholas Curtis - 2017 5 | */ 6 | 7 | #ifndef ERROR_CHECK_H 8 | #define ERROR_CHECK_H 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | void cpu_assert(bool x, const char* message, const char *file, int line); 15 | #define cassert(ans, message) { cpu_assert((ans), (message), __FILE__, __LINE__); } 16 | 17 | #endif -------------------------------------------------------------------------------- /pyjac/kernel_utils/c/memcpy_2d.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * memcpy_2d.h 3 | * 4 | * \author Nick Curtis 5 | * \date 2017 6 | * 7 | * Simple 2D memcopy function to enable strided copy of state vectors 8 | * for cases where the maximum allowable number of initial conditions is 9 | * _less_ than the total number of conditions to be tested 10 | * 11 | */ 12 | 13 | #ifndef MEMCPY2D_H 14 | #define MEMCPY2D_H 15 | 16 | #include 17 | #include 18 | 19 | 20 | /** 21 | * \brief A convienience method to copy memory between host pointers of different pitches, widths and heights. 22 | * 23 | * \param[out] dst The destination array 24 | * \param[in] pitch_dst The width (in number of elements) of the destination array. 25 | This corresponds to the padded number of IVPs to be solved. 26 | * \param[in] src The source pointer 27 | * \param[in] pitch_src The width (in number of elements) of the source array. 28 | This corresponds to the (non-padded) number of IVPs read by read_initial_conditions 29 | * \param[in] offset The offset within the source array (IVP index) to copy from. 30 | This is useful in the case (for large models) where the solver and state vector memory will not fit in device memory 31 | and the integration must be split into multiple kernel calls. 32 | * \param[in] width The size (in bytes) of memory to copy for each entry in the state vector 33 | * \param[in] height The number of entries in the state vector 34 | */ 35 | static inline void memcpy2D_in(double* dst, const int pitch_dst, double const * src, const int pitch_src, 36 | const int offset, const size_t width, const int height) { 37 | for (int i = 0; i < height; ++i) 38 | { 39 | memcpy(dst, &src[offset], width); 40 | dst += pitch_dst; 41 | src += pitch_src; 42 | } 43 | } 44 | 45 | /** 46 | * \brief A convienience method to copy memory between host pointers of different pitches, widths and heights. 47 | * 48 | * \param[out] dst The destination array 49 | * \param[in] pitch_dst The width (in number of elements) of the source array. 50 | This corresponds to the (non-padded) number of IVPs read by read_initial_conditions 51 | * \param[in] src The source pointer 52 | * \param[in] pitch_src The width (in number of elements) of the destination array. 53 | This corresponds to the padded number of IVPs to be solved. 54 | * \param[in] offset The offset within the destination array (IVP index) to copy to. 55 | This is useful in the case (for large models) where the solver and state vector memory will not fit in device memory 56 | and the integration must be split into multiple kernel calls. 57 | * \param[in] width The size (in bytes) of memory to copy for each entry in the state vector 58 | * \param[in] height The number of entries in the state vector 59 | */ 60 | static inline void memcpy2D_out(double* dst, const int pitch_dst, double const * src, const int pitch_src, 61 | const int offset, const size_t width, const int height) { 62 | for (int i = 0; i < height; ++i) 63 | { 64 | memcpy(&dst[offset], src, width); 65 | dst += pitch_dst; 66 | src += pitch_src; 67 | } 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /pyjac/kernel_utils/c/wrapping_kernel.cpp.in: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | ${defines} 5 | ${preamble} 6 | 7 | ${extra_kernels} 8 | 9 | ${func_define} 10 | { 11 | ${body} 12 | } 13 | -------------------------------------------------------------------------------- /pyjac/kernel_utils/common/read_initial_conditions.cpp.in: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | A cog-templated skeleton for reading of initial conditions from a binary file 4 | 5 | (C) Nicholas Curtis - 2018 6 | 7 | Global declarations for Cog: 8 | - readgen: path to a serialized ReadgenRecord instance 9 | that may be loaded to generate this file 10 | */ 11 | 12 | /*[[[cog 13 | from six.moves import cPickle as pickle 14 | from pyjac.core.array_creator import pressure_array, volume_array 15 | from pyjac.kernel_utils.tools import get_include 16 | from pyjac.utils import header_ext 17 | 18 | with open(readgen, 'rb') as file: 19 | readgen = pickle.load(file) 20 | 21 | from pyjac.kernel_utils.memory_tools import get_memory 22 | mem = get_memory(readgen) 23 | 24 | # headers 25 | cog.outl(get_include(readgen, 'mechanism')) 26 | cog.outl(get_include(readgen, 'vectorization')) 27 | ]]] 28 | [[[end]]]*/ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | // size of a single input buffer 36 | // total buffer size 37 | #define BUFF_SIZE ((NN + 1)) 38 | 39 | //for sanity, the input data is expected to be in C-order 40 | 41 | void read_initial_conditions(const char* filename, unsigned int NUM, 42 | /*[[[cog 43 | arrys = [] 44 | for arry in readgen.inputs: 45 | arrys.append(mem.get_signature(False, arry) + ',') 46 | cog.outl(' '.join(arrys)) 47 | 48 | assert len(readgen.inputs) == 2 49 | param = next(x for x in readgen.inputs if x.name in [pressure_array, volume_array]).name 50 | phi = next(x for x in readgen.inputs if x.name != param).name 51 | ]]] 52 | [[[end]]]*/ 53 | const char order) { 54 | FILE *fp = fopen (filename, "rb"); 55 | if (fp == NULL) 56 | { 57 | fprintf(stderr, "Could not open file: %s\n", filename); 58 | exit(-1); 59 | } 60 | 61 | double buffer[BUFF_SIZE]; 62 | // load temperature, pressure and concentrations for all (cells) 63 | for (int i = 0; i < NUM; ++i) 64 | { 65 | // read line from data file 66 | int count = fread(buffer, sizeof(double), BUFF_SIZE, fp); 67 | if (count != (BUFF_SIZE)) 68 | { 69 | fprintf(stderr, "File (%s) is incorrectly formatted, %d " 70 | "doubles were expected but only %d were read.\n", 71 | filename, BUFF_SIZE, count); 72 | exit(-1); 73 | } 74 | 75 | //fill the parameter array 76 | /*[[[cog 77 | cog.outl('{param}[i] = buffer[1];'.format(param=param)) 78 | ]]] 79 | [[[end]]]*/ 80 | 81 | // phi fill depends on order 82 | if (order == 'C') 83 | { 84 | //fill in temperature 85 | /*[[[cog 86 | cog.outl('{phi}[i * NN] = buffer[0];'.format(phi=phi)) 87 | ]]] 88 | [[[end]]]*/ 89 | //fill in species moles 90 | for (int j = 0; j < NS; j++) 91 | { 92 | /*[[[cog 93 | cog.outl('{phi}[i * NN + (j + 1)] = buffer[j + 2];'.format(phi=phi)) 94 | ]]] 95 | [[[end]]]*/ 96 | } 97 | } 98 | else 99 | { 100 | //fill in temperature 101 | /*[[[cog 102 | cog.outl('{phi}[i] = buffer[0];'.format(phi=phi)) 103 | ]]] 104 | [[[end]]]*/ 105 | //fill in species moles 106 | for (int j = 0; j < NS; j++) 107 | { 108 | /*[[[cog 109 | cog.outl('{phi}[(j + 1) * NUM + i] = buffer[j + 2];'.format(phi=phi)) 110 | ]]] 111 | [[[end]]]*/ 112 | } 113 | } 114 | 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /pyjac/kernel_utils/common/read_initial_conditions.hpp.in: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | A cog-templated skeleton for reading of initial conditions from a binary file 4 | 5 | (C) Nicholas Curtis - 2018 6 | 7 | Global declarations for Cog: 8 | - readgen: path to a serialized ReadgenRecord instance 9 | that may be loaded to generate this file 10 | */ 11 | 12 | 13 | #ifndef READ_IC_H 14 | #define READ_IC_H 15 | 16 | /*[[[cog 17 | from six.moves import cPickle as pickle 18 | from pyjac.utils import header_ext 19 | from pyjac.utils import indent, stdindent 20 | from pyjac.kernel_utils.tools import get_include 21 | 22 | with open(readgen, 'rb') as file: 23 | readgen = pickle.load(file) 24 | 25 | from pyjac.kernel_utils.memory_tools import get_memory 26 | mem = get_memory(readgen) 27 | 28 | ]]] 29 | [[[end]]]*/ 30 | 31 | 32 | void read_initial_conditions( 33 | const char* filename, unsigned int NUM, 34 | /*[[[cog 35 | arrys = [] 36 | for arry in readgen.inputs: 37 | arrys.append(mem.get_signature(False, arry) + ',') 38 | cog.outl(indent(' '.join(arrys), stdindent), dedent=False) 39 | ]]] 40 | [[[end]]]*/ 41 | const char order); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /pyjac/kernel_utils/common/timer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef WIN32 4 | #define WIN32_LEAN_AND_MEAN 5 | #include 6 | #else 7 | #ifndef __USE_BSD 8 | #define __USE_BSD 9 | #endif 10 | #include 11 | #include 12 | #endif 13 | 14 | #ifdef WIN32 15 | double PCFreq = 0.0; 16 | __int64 timerStart = 0; 17 | #else 18 | struct timeval timerStart; 19 | #endif 20 | 21 | void StartTimer() 22 | { 23 | #ifdef WIN32 24 | LARGE_INTEGER li; 25 | if(!QueryPerformanceFrequency(&li)) 26 | printf("QueryPerformanceFrequency failed!\\n"); 27 | 28 | PCFreq = (double)li.QuadPart/1000.0; 29 | 30 | QueryPerformanceCounter(&li); 31 | timerStart = li.QuadPart; 32 | #else 33 | gettimeofday(&timerStart, NULL); 34 | #endif 35 | } 36 | 37 | // time elapsed in ms 38 | double GetTimer() 39 | { 40 | #ifdef WIN32 41 | LARGE_INTEGER li; 42 | QueryPerformanceCounter(&li); 43 | return (double)(li.QuadPart-timerStart)/PCFreq; 44 | #else 45 | struct timeval timerStop, timerElapsed; 46 | gettimeofday(&timerStop, NULL); 47 | timersub(&timerStop, &timerStart, &timerElapsed); 48 | return timerElapsed.tv_sec*1000.0+timerElapsed.tv_usec/1000.0; 49 | #endif 50 | } -------------------------------------------------------------------------------- /pyjac/kernel_utils/common/timer.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TIMER_H 2 | #define TIMER_H 3 | 4 | void StartTimer(void); 5 | // time elapsed in ms 6 | double GetTimer(void); 7 | 8 | #endif // TIMER_H -------------------------------------------------------------------------------- /pyjac/kernel_utils/common/write_data.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | write_data.h - a shared convenience function to write output of species / 3 | Jacobian kernel calls to file for validation 4 | 5 | \author Nick Curtis 6 | \date Oct 2017 7 | */ 8 | #ifndef WRITE_DATA_H 9 | #define WRITE_DATA_H 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | static void write_data(const char* filename, double* arr, size_t var_size) 16 | { 17 | FILE* fp = fopen(filename, "wb"); 18 | if (fp == NULL) 19 | { 20 | const char* err = "Error opening file for data output: "; 21 | size_t buffsize = strlen(filename) + strlen(err) * sizeof(char); 22 | char* buff = (char*)malloc(buffsize); 23 | snprintf(buff, buffsize, "%s%s", err, filename); 24 | printf("%s\n", buff); 25 | free(buff); 26 | exit(-1); 27 | } 28 | assert(fwrite(arr, sizeof(double), var_size, fp) == var_size 29 | && "Wrong filesize written."); 30 | assert(!fclose(fp) && "Error writing to file"); 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /pyjac/kernel_utils/opencl/error_check.ocl: -------------------------------------------------------------------------------- 1 | #include "error_check.oclh" 2 | 3 | const char* getErrorString(cl_int error) 4 | { 5 | switch(error){ 6 | // run-time and JIT compiler errors 7 | case 0: return "CL_SUCCESS"; 8 | case -1: return "CL_DEVICE_NOT_FOUND"; 9 | case -2: return "CL_DEVICE_NOT_AVAILABLE"; 10 | case -3: return "CL_COMPILER_NOT_AVAILABLE"; 11 | case -4: return "CL_MEM_OBJECT_ALLOCATION_FAILURE"; 12 | case -5: return "CL_OUT_OF_RESOURCES"; 13 | case -6: return "CL_OUT_OF_HOST_MEMORY"; 14 | case -7: return "CL_PROFILING_INFO_NOT_AVAILABLE"; 15 | case -8: return "CL_MEM_COPY_OVERLAP"; 16 | case -9: return "CL_IMAGE_FORMAT_MISMATCH"; 17 | case -10: return "CL_IMAGE_FORMAT_NOT_SUPPORTED"; 18 | case -11: return "CL_BUILD_PROGRAM_FAILURE"; 19 | case -12: return "CL_MAP_FAILURE"; 20 | case -13: return "CL_MISALIGNED_SUB_BUFFER_OFFSET"; 21 | case -14: return "CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST"; 22 | case -15: return "CL_COMPILE_PROGRAM_FAILURE"; 23 | case -16: return "CL_LINKER_NOT_AVAILABLE"; 24 | case -17: return "CL_LINK_PROGRAM_FAILURE"; 25 | case -18: return "CL_DEVICE_PARTITION_FAILED"; 26 | case -19: return "CL_KERNEL_ARG_INFO_NOT_AVAILABLE"; 27 | 28 | // compile-time errors 29 | case -30: return "CL_INVALID_VALUE"; 30 | case -31: return "CL_INVALID_DEVICE_TYPE"; 31 | case -32: return "CL_INVALID_PLATFORM"; 32 | case -33: return "CL_INVALID_DEVICE"; 33 | case -34: return "CL_INVALID_CONTEXT"; 34 | case -35: return "CL_INVALID_QUEUE_PROPERTIES"; 35 | case -36: return "CL_INVALID_COMMAND_QUEUE"; 36 | case -37: return "CL_INVALID_HOST_PTR"; 37 | case -38: return "CL_INVALID_MEM_OBJECT"; 38 | case -39: return "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR"; 39 | case -40: return "CL_INVALID_IMAGE_SIZE"; 40 | case -41: return "CL_INVALID_SAMPLER"; 41 | case -42: return "CL_INVALID_BINARY"; 42 | case -43: return "CL_INVALID_BUILD_OPTIONS"; 43 | case -44: return "CL_INVALID_PROGRAM"; 44 | case -45: return "CL_INVALID_PROGRAM_EXECUTABLE"; 45 | case -46: return "CL_INVALID_KERNEL_NAME"; 46 | case -47: return "CL_INVALID_KERNEL_DEFINITION"; 47 | case -48: return "CL_INVALID_KERNEL"; 48 | case -49: return "CL_INVALID_ARG_INDEX"; 49 | case -50: return "CL_INVALID_ARG_VALUE"; 50 | case -51: return "CL_INVALID_ARG_SIZE"; 51 | case -52: return "CL_INVALID_KERNEL_ARGS"; 52 | case -53: return "CL_INVALID_WORK_DIMENSION"; 53 | case -54: return "CL_INVALID_WORK_GROUP_SIZE"; 54 | case -55: return "CL_INVALID_WORK_ITEM_SIZE"; 55 | case -56: return "CL_INVALID_GLOBAL_OFFSET"; 56 | case -57: return "CL_INVALID_EVENT_WAIT_LIST"; 57 | case -58: return "CL_INVALID_EVENT"; 58 | case -59: return "CL_INVALID_OPERATION"; 59 | case -60: return "CL_INVALID_GL_OBJECT"; 60 | case -61: return "CL_INVALID_BUFFER_SIZE"; 61 | case -62: return "CL_INVALID_MIP_LEVEL"; 62 | case -63: return "CL_INVALID_GLOBAL_WORK_SIZE"; 63 | case -64: return "CL_INVALID_PROPERTY"; 64 | case -65: return "CL_INVALID_IMAGE_DESCRIPTOR"; 65 | case -66: return "CL_INVALID_COMPILER_OPTIONS"; 66 | case -67: return "CL_INVALID_LINKER_OPTIONS"; 67 | case -68: return "CL_INVALID_DEVICE_PARTITION_COUNT"; 68 | 69 | // extension errors 70 | case -1000: return "CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR"; 71 | case -1001: return "CL_PLATFORM_NOT_FOUND_KHR"; 72 | case -1002: return "CL_INVALID_D3D10_DEVICE_KHR"; 73 | case -1003: return "CL_INVALID_D3D10_RESOURCE_KHR"; 74 | case -1004: return "CL_D3D10_RESOURCE_ALREADY_ACQUIRED_KHR"; 75 | case -1005: return "CL_D3D10_RESOURCE_NOT_ACQUIRED_KHR"; 76 | default: return "Unknown OpenCL error"; 77 | } 78 | } 79 | 80 | void ocl_assert(cl_int x, const char *file, int line) { 81 | if (x != CL_SUCCESS) 82 | { 83 | fprintf(stderr,"ocl_assert: %s %s %d\n", getErrorString(x), file, line); 84 | exit(x); 85 | } 86 | } 87 | 88 | void cpu_assert(bool x, const char* message, const char *file, int line) { 89 | if (!x) 90 | { 91 | fprintf(stderr, "cpu_assert: %s %s %d\n", message, file, line); 92 | exit(-1); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /pyjac/kernel_utils/opencl/error_check.oclh: -------------------------------------------------------------------------------- 1 | #ifndef OCL_ERR_CHECK_H 2 | #define OCL_ERR_CHECK_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void ocl_assert(cl_int x, const char *file, int line); 9 | void cpu_assert(bool ans, const char *message, const char *file, int line); 10 | #define check_err(ans) { ocl_assert((ans), __FILE__, __LINE__); } 11 | #define cassert(ans, message) { cpu_assert((ans), (message), __FILE__, __LINE__); } 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /pyjac/kernel_utils/opencl/memcpy_2d.oclh: -------------------------------------------------------------------------------- 1 | /** 2 | * memcpy_2d.oclh 3 | * 4 | * \author Nick Curtis 5 | * \date 11-06-2017 6 | * 7 | * A C-imlementation of the clEnqueueWriteBufferRect/clEnqueueReadBufferRect 8 | * memcopy function to enable copying to / from pinned memory pointers 9 | * 10 | * These implementations are based on pocl_basic_write/read_rect, 11 | * from the wonderful open source OpenCL implementation 12 | * Portable OpenCL (Pocl) https://github.com/pocl/pocl 13 | * 14 | */ 15 | 16 | #ifndef MEMCPY2D_H 17 | #define MEMCPY2D_H 18 | 19 | #include 20 | #include 21 | 22 | 23 | /** 24 | * \brief A C-imlementation of the clEnqueueWriteBufferRect 25 | memcopy function to enable copying to / from pinned memory pointers 26 | * 27 | * \param[in] host_ptr The source (host) data array 28 | * \param[out] device_ptr The destination (mapped device) data array 29 | * \param[in] host_origin The origin of the host buffer in {bytes, items, ite,s} 30 | Note: the first entry should be in bytes, while the subsecuent entries should be in number of array entries 31 | to make the units of host_origin[0] + host_row_pitch * host_origin[1] + host_slice_pitch === bytes 32 | * \param[in] region The region to copy in {bytes, items, items} 33 | Note: the first entry should be in bytes, while the subsecuent entries should be in number of array entries 34 | to make the units of region[0] + host_row_pitch * region[1] + host_slice_pitch === bytes 35 | * \param[in] buffer_row_pitch The width (in bytes) of the second dimension of the device_ptr 36 | * \param[in] buffer_slice_pitch The width (in bytes) of the third dimension of the device_ptr 37 | * \param[in] host_row_pitch The width (in bytes) of the second dimension of the host_ptr 38 | * \param[in] host_slice_pitch The width (in bytes) of the third dimension of the host_ptr 39 | */ 40 | static inline void memcpy2D_in(const void *__restrict__ const host_ptr, 41 | void *__restrict__ const device_ptr, 42 | const size_t *__restrict__ const host_origin, 43 | const size_t *__restrict__ const region, 44 | size_t const buffer_row_pitch, 45 | size_t const buffer_slice_pitch, 46 | size_t const host_row_pitch, 47 | size_t const host_slice_pitch) 48 | { 49 | /* 50 | the device buffer origin is zero by definition 51 | */ 52 | size_t buffer_origin [3] = {0, 0, 0}; 53 | char *__restrict const adjusted_device_ptr = 54 | (char*)device_ptr + 55 | buffer_origin[0] + buffer_row_pitch * buffer_origin[1] + buffer_slice_pitch * buffer_origin[2]; 56 | char const *__restrict__ const adjusted_host_ptr = 57 | (char const*)host_ptr + 58 | host_origin[0] + host_row_pitch * host_origin[1]; 59 | 60 | size_t j, k; 61 | 62 | /* TODO: handle overlaping regions */ 63 | 64 | for (k = 0; k < region[2]; ++k) 65 | for (j = 0; j < region[1]; ++j) 66 | memcpy (adjusted_device_ptr + buffer_row_pitch * j + buffer_slice_pitch * k, 67 | adjusted_host_ptr + host_row_pitch * j + host_slice_pitch * k, 68 | region[0]); 69 | } 70 | /** 71 | * \brief A C-imlementation of the clEnqueueReadBufferRect 72 | memcopy function to enable copying to / from pinned memory pointers 73 | * 74 | * \param[in] host_ptr The source (host) data array 75 | * \param[out] device_ptr The destination (mapped device) data array 76 | * \param[in] host_origin The origin of the host buffer in {bytes, items, ite,s} 77 | Note: the first entry should be in bytes, while the subsecuent entries should be in number of array entries 78 | to make the units of host_origin[0] + host_row_pitch * host_origin[1] + host_slice_pitch === bytes 79 | * \param[in] region The region to copy in {bytes, items, items} 80 | Note: the first entry should be in bytes, while the subsecuent entries should be in number of array entries 81 | to make the units of region[0] + host_row_pitch * region[1] + host_slice_pitch === bytes 82 | * \param[in] buffer_row_pitch The width (in bytes) of the second dimension of the device_ptr 83 | * \param[in] buffer_slice_pitch The width (in bytes) of the third dimension of the device_ptr 84 | * \param[in] host_row_pitch The width (in bytes) of the second dimension of the host_ptr 85 | * \param[in] host_slice_pitch The width (in bytes) of the third dimension of the host_ptr 86 | */ 87 | static inline void memcpy2D_out(const void *__restrict__ const host_ptr, 88 | void *__restrict__ const device_ptr, 89 | const size_t *__restrict__ const host_origin, 90 | const size_t *__restrict__ const region, 91 | size_t const buffer_row_pitch, 92 | size_t const buffer_slice_pitch, 93 | size_t const host_row_pitch, 94 | size_t const host_slice_pitch) 95 | { 96 | /* 97 | the device buffer origin is zero by definition 98 | */ 99 | size_t buffer_origin [3] = {0, 0, 0}; 100 | char *__restrict const adjusted_device_ptr = 101 | (char*)device_ptr + 102 | buffer_origin[0] + buffer_row_pitch * buffer_origin[1] + buffer_slice_pitch * buffer_origin[2]; 103 | char *__restrict__ const adjusted_host_ptr = 104 | (char*)host_ptr + 105 | host_origin[2] * host_slice_pitch + host_origin[1] * host_row_pitch + host_origin[0]; 106 | 107 | size_t j, k; 108 | 109 | /* TODO: handle overlaping regions */ 110 | 111 | for (k = 0; k < region[2]; ++k) 112 | for (j = 0; j < region[1]; ++j) 113 | memcpy (adjusted_host_ptr + host_row_pitch * j + host_slice_pitch * k, 114 | adjusted_device_ptr + buffer_row_pitch * j + buffer_slice_pitch * k, 115 | region[0]); 116 | } 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /pyjac/kernel_utils/opencl/opencl_kernel_compiler.cpp.in: -------------------------------------------------------------------------------- 1 | /* 2 | kernel.c 3 | A cog-templated skeleton for pyJac OpenCL-kernel compilation 4 | (C) Nicholas Curtis - 2018 5 | 6 | Global declarations for Cog: 7 | - compgen: path to a serialized CompilationGenerationResult instance 8 | that may be loaded to generate this file 9 | */ 10 | 11 | /*[[[cog 12 | from six.moves import cPickle as pickle 13 | with open(compgen, 'rb') as file: 14 | compgen = pickle.load(file) 15 | num_source = len(compgen.source_names) 16 | 17 | #include main header to get kernel def'n 18 | cog.outl('#include "{}_main.oclh"'.format(compgen.name)) 19 | ]]] 20 | [[[end]]]*/ 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #define MAX_DEVICE (16) 27 | #define MAX_PLATFORM (16) 28 | 29 | //[[[cog cog.outl('void {name}Kernel::compile()'.format(name=compgen.name.title()))]]] 30 | //[[[end]]] 31 | { 32 | cl_platform_id platform_id[MAX_PLATFORM]; 33 | cl_device_id device_id = NULL; 34 | cl_context context = NULL; 35 | cl_command_queue command_queue = NULL; 36 | cl_program program = NULL; 37 | cl_uint ret_num_platforms; 38 | cl_uint ret_num_devices; 39 | 40 | cl_int return_code; 41 | 42 | 43 | /*[[[cog 44 | # write variables 45 | cog.outl('const char* filename[{}] = {{ {} }};'.format(num_source, 46 | ', '.join(['"{}"'.format(name) for name in compgen.source_names]))) 47 | cog.outl('const char* platform = "{}";'.format(compgen.platform)) 48 | cog.outl('const char* out_name = "{}";'.format(compgen.outname)) 49 | cog.outl('const char* build_options = "{}";'.format(compgen.build_options)) 50 | ]]] 51 | [[[end]]]*/ 52 | 53 | FILE *fp; 54 | /*[[[cog 55 | cog.outl('char* source_str[{}];'.format(num_source)) 56 | cog.outl('size_t source_size[{}];'.format(num_source)) 57 | ]]] 58 | [[[end]]]*/ 59 | 60 | /* Load kernel source code */ 61 | //[[[cog cog.outl('for (int i = 0; i < {}; ++i)'.format(num_source)) ]]] 62 | //[[[end]]] 63 | { 64 | fp = fopen(filename[i], "r"); 65 | if (!fp) { 66 | printf("Kernel source: %s could not be opened.", filename[i]); 67 | exit(-1); 68 | } 69 | //find file size 70 | fseek(fp, 0L, SEEK_END); 71 | source_size[i] = ftell(fp); 72 | rewind(fp); 73 | 74 | //read file 75 | source_str[i] = (char*)malloc(source_size[i]); 76 | cassert(fread(source_str[i], 1, source_size[i], fp) == source_size[i], "Error reading in source strings."); 77 | fclose(fp); 78 | } 79 | 80 | /* Get platform/device information */ 81 | check_err(clGetPlatformIDs(MAX_PLATFORM, platform_id, &ret_num_platforms)); 82 | cl_platform_id pid = NULL; 83 | for (int i = 0; i < ret_num_platforms; ++i) 84 | { 85 | //check if intel 86 | char pvendor[100]; 87 | size_t psize = 100 * sizeof(char); 88 | check_err(clGetPlatformInfo(platform_id[i], CL_PLATFORM_VENDOR, psize, pvendor, NULL)); 89 | if(strstr(pvendor, platform) != NULL) 90 | { 91 | pid = platform_id[i]; 92 | break; 93 | } 94 | } 95 | cassert(pid != NULL, "Platform not found"); 96 | 97 | 98 | //get the device to compile for 99 | cl_uint num_devices = 1; //only need one for compilation 100 | check_err(clGetDeviceIDs(pid, CL_DEVICE_TYPE_ALL, num_devices, &device_id, &ret_num_devices)); 101 | 102 | //create context 103 | context = clCreateContext(NULL, num_devices, &device_id, NULL, NULL, &return_code); 104 | check_err(return_code); 105 | 106 | //create queue 107 | command_queue = clCreateCommandQueue(context, device_id, 0, &return_code); 108 | check_err(return_code); 109 | 110 | /* Create Kernel program from the source */ 111 | /*[[[cog 112 | cog.outl('program = clCreateProgramWithSource(context, {}, (const char **)source_str, ' 113 | '(const size_t *)source_size, &return_code);'.format(num_source)) 114 | ]]] 115 | [[[end]]]*/ 116 | check_err(return_code); 117 | 118 | /* Build Kernel Program */ 119 | return_code = clBuildProgram(program, num_devices, &device_id, build_options, NULL, NULL); 120 | if (return_code != CL_SUCCESS) 121 | { 122 | printf("OpenCL failed to build the program...\n"); 123 | } 124 | size_t len; 125 | char *buffer; 126 | check_err(clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, 0, NULL, &len)); 127 | buffer = (char*)calloc(len, sizeof(char)); 128 | check_err(clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_LOG, len * sizeof(char), buffer, NULL)); 129 | printf("%s\n", buffer); 130 | free(buffer); 131 | 132 | clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_STATUS, sizeof(char*), NULL, &len); 133 | buffer = (char*)calloc(len, sizeof(char)); 134 | clGetProgramBuildInfo(program, device_id, CL_PROGRAM_BUILD_STATUS, len * sizeof(char), buffer, NULL); 135 | printf("%s\n", buffer); 136 | free(buffer); 137 | check_err(return_code); 138 | 139 | // Get compiled binary from runtime 140 | 141 | //get # of programs 142 | size_t num_prog; 143 | size_t expected_progs = 1; 144 | check_err(clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), NULL, &num_prog)); 145 | num_prog /= sizeof(size_t); 146 | cassert(num_prog == expected_progs, "Incorrect number of programs found."); 147 | 148 | //get program size 149 | size_t bin_size[expected_progs]; 150 | check_err(clGetProgramInfo(program, CL_PROGRAM_BINARY_SIZES, num_prog * sizeof(size_t), bin_size, NULL)); 151 | 152 | //get binary 153 | unsigned char* binary[expected_progs]; 154 | for (int i = 0; i < expected_progs; ++i) 155 | binary[i] = (unsigned char*)malloc(bin_size[i]); 156 | check_err(clGetProgramInfo(program, CL_PROGRAM_BINARIES, sizeof(binary), binary, NULL)); 157 | 158 | for (int i = 0; i < expected_progs; ++i) 159 | { 160 | // Then write binary to file 161 | fp = fopen(out_name, "wb"); 162 | if (!fp) { 163 | exit(-1); 164 | } 165 | size_t bytes = bin_size[i] / sizeof(unsigned char); 166 | cassert(fwrite(binary[i], sizeof(unsigned char), bytes, fp) == bytes, "Error writing program binaries."); 167 | //close file 168 | fclose(fp); 169 | free(binary[i]); 170 | free(source_str[i]); 171 | } 172 | 173 | // mark compiled 174 | this->compiled=true; 175 | } 176 | -------------------------------------------------------------------------------- /pyjac/kernel_utils/opencl/wrapping_kernel.ocl.in: -------------------------------------------------------------------------------- 1 | ${defines} 2 | ${preamble} 3 | 4 | ${extra_kernels} 5 | 6 | ${func_define} 7 | { 8 | ${body} 9 | } 10 | -------------------------------------------------------------------------------- /pyjac/kernel_utils/tools.py: -------------------------------------------------------------------------------- 1 | """ 2 | A small collection of tools used in code-generation by the Cogger 3 | """ 4 | 5 | import re 6 | from textwrap import dedent 7 | 8 | import loopy as lp 9 | import numpy as np 10 | from pyjac.utils import partition, is_integer, header_ext, subs_at_indent 11 | 12 | 13 | def get_include(callgen, file): 14 | """ 15 | Return an inclusion string for this language / filename 16 | """ 17 | return '#include "{}"'.format(file + header_ext[callgen.lang]) 18 | 19 | 20 | def make_parameter_docs(callgen, argnames): 21 | docs = [] 22 | for arg in argnames: 23 | dtype, desc = callgen.get_docs(arg) 24 | try: 25 | name = arg.name 26 | except AttributeError: 27 | assert isinstance(arg, str) 28 | name = arg 29 | docs.append('{} : {}'.format(name, dtype)) 30 | docs.append('\t{}'.format(desc)) 31 | return '\n'.join(docs) 32 | 33 | 34 | def make_doc_str(callgen, argnames, func_desc, comment_type='c'): 35 | """ 36 | Returns a documentation string for the given :param:`argnames` for the 37 | function w/ description :param:`func_desc` 38 | """ 39 | 40 | if comment_type == 'c': 41 | start = '/*' 42 | end = '*/' 43 | elif comment_type == 'python': 44 | start = '"""' 45 | end = start 46 | parameters = make_parameter_docs(callgen, argnames) 47 | return dedent(subs_at_indent( 48 | """ 49 | ${start} 50 | ${func_desc} 51 | 52 | Parameters 53 | ---------- 54 | ${parameters} 55 | ${end} 56 | """, parameters=parameters, func_desc=func_desc, start=start, end=end)) 57 | 58 | 59 | def get_kernel_args(mem, args): 60 | """ 61 | Parameters 62 | ---------- 63 | mem: :class:`memory_tools` 64 | The current memory tool object 65 | args: list of :class:`loopy.KernelArg` 66 | The arguments to stringify 67 | 68 | Returns 69 | ------- 70 | args: str 71 | a comma separated list of arguments for definition of a kernel function 72 | """ 73 | return ', '.join([mem.get_signature(False, arr) for arr in args]) 74 | 75 | 76 | def get_temporaries(mem, args): 77 | """ 78 | Determine which type of temporary variables are required 79 | for this kernel 80 | 81 | Parameters 82 | ---------- 83 | mem: :class:`memory_tools` 84 | The current memory tool object 85 | args: list of :class:`loopy.KernelArg` 86 | The arguments to check while determining temporary types 87 | 88 | Returns 89 | ------- 90 | temps: list of str 91 | A list of temporary variable definitions for implementation in a kernel 92 | class 93 | """ 94 | # always have a double-precision temp 95 | temps = [lp.GlobalArg('temp_d', dtype=np.float64)] 96 | if any([x.dtype.is_integral() and isinstance(x, lp.ArrayArg) 97 | for x in args]): 98 | # need integer temporary 99 | arr = next(x for x in args if x.dtype.is_integral()) 100 | temps.append(lp.GlobalArg('temp_i', dtype=arr.dtype)) 101 | 102 | return [mem.define(False, temp) for temp in temps] 103 | 104 | 105 | def max_size(mem, args): 106 | """ 107 | Find the maximum size (for allocation of a zero-ing buffer) of the given 108 | arguments 109 | 110 | Parameters 111 | ---------- 112 | mem: :class:`memory_tools` 113 | The current memory tool object 114 | args: list of :class:`loopy.KernelArg` 115 | The arguments to determine the sizes of 116 | 117 | Returns 118 | ------- 119 | size: str 120 | The stringified size 121 | """ 122 | max_size = [mem.non_ic_size(arr) for arr in args 123 | if not isinstance(arr, lp.ValueArg)] 124 | 125 | problem_sizes, work_sizes = partition(max_size, is_integer) 126 | problem_size = '{} * problem_size'.format(max([int(x) for x in problem_sizes])) 127 | # make sure work sizes are what we expect 128 | regex = re.compile(r'work_size\s*\*\s*(\d+)') 129 | assert all(regex.search(x) for x in work_sizes) 130 | # next, extract the work sizes 131 | work_size = [int(regex.search(x).group(1)) for x in work_sizes] 132 | if not work_size: 133 | # fixed work size 134 | return '({})'.format(problem_size) 135 | work_size = '{} * work_size'.format(max(work_size)) 136 | return '({0} > {1} ? {0} : {1})'.format(problem_size, work_size) 137 | 138 | 139 | def get_num_bytes(mem, arg): 140 | """ 141 | Return the size (in bytes) of an argument -- note, there _must_ not be any 142 | string sizes in the arguments' shape. Intended to determine the size of the 143 | __local buffer for deep arrays 144 | """ 145 | 146 | return int(mem.non_ic_size(arg, subs={})) * arg.dtype.itemsize 147 | -------------------------------------------------------------------------------- /pyjac/libgen/__init__.py: -------------------------------------------------------------------------------- 1 | from pyjac.libgen.libgen import generate_library, lib_ext, get_toolchain, compile 2 | 3 | __all__ = ['generate_library', 'lib_ext', 'get_toolchain', 'compile'] 4 | -------------------------------------------------------------------------------- /pyjac/libgen/__main__.py: -------------------------------------------------------------------------------- 1 | from argparse import ArgumentParser 2 | 3 | from pyjac.libgen import generate_library 4 | from pyjac.core.enum_types import KernelType 5 | from pyjac import utils 6 | 7 | if __name__ == '__main__': 8 | parser = ArgumentParser( 9 | description='Generates a shared/static library ' 10 | 'from previously generated pyJac files using gcc/nvcc.' 11 | ) 12 | parser.add_argument('-l', '--lang', 13 | type=str, 14 | choices=utils.langs, 15 | required=True, 16 | help='Programming language for source files' 17 | ) 18 | parser.add_argument('-so', '--source_dir', 19 | type=str, 20 | required=True, 21 | help='Path of directory with existing pyJac files.' 22 | ) 23 | parser.add_argument('-ob', '--obj_dir', 24 | type=str, 25 | required=False, 26 | default=None, 27 | help='Path of directory for generated object files.' 28 | ) 29 | parser.add_argument('-out', '--out_dir', 30 | type=str, 31 | required=False, 32 | default=None, 33 | help='Path of directory for generated library' 34 | ) 35 | parser.add_argument('-st', '--static', 36 | required=False, 37 | default=False, 38 | action='store_true', 39 | help='If specified, the generated library will be' 40 | 'a static library (required for CUDA).' 41 | ) 42 | parser.add_argument('-kt', '--kernel_type', 43 | required=False, 44 | type=utils.EnumType(KernelType), 45 | default='jacobian', 46 | help='The type of library to build: {type}'.format( 47 | type=str(utils.EnumType(KernelType)))) 48 | parser.add_argument('-e', '--executable', 49 | required=False, 50 | default=False, 51 | action='store_true', 52 | help='If supplied, convert the generated library to an ' 53 | 'executable shared library (cannot be supplied w/ ' 54 | '--static switch)') 55 | 56 | args = parser.parse_args() 57 | generate_library(args.lang, args.source_dir, args.obj_dir, args.out_dir, 58 | not args.static, args.kernel_type, args.executable) 59 | -------------------------------------------------------------------------------- /pyjac/logging.yaml: -------------------------------------------------------------------------------- 1 | # https://fangpenlin.com/posts/2012/08/26/good-logging-practice-in-python/ 2 | version: 1 3 | disable_existing_loggers: False 4 | formatters: 5 | simple: 6 | format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s" 7 | 8 | handlers: 9 | console: 10 | class: logging.StreamHandler 11 | level: DEBUG 12 | formatter: simple 13 | stream: ext://sys.stdout 14 | 15 | info_file_handler: 16 | class: logging.handlers.RotatingFileHandler 17 | level: INFO 18 | formatter: simple 19 | filename: info.log 20 | maxBytes: 10485760 # 10MB 21 | backupCount: 20 22 | encoding: utf8 23 | 24 | error_file_handler: 25 | class: logging.handlers.RotatingFileHandler 26 | level: ERROR 27 | formatter: simple 28 | filename: errors.log 29 | maxBytes: 10485760 # 10MB 30 | backupCount: 20 31 | encoding: utf8 32 | 33 | loggers: 34 | pyjac: 35 | level: INFO 36 | handlers: [console] 37 | propagate: no 38 | 39 | root: 40 | level: INFO 41 | handlers: [console, info_file_handler, error_file_handler] 42 | -------------------------------------------------------------------------------- /pyjac/loopy_utils/__init__.py: -------------------------------------------------------------------------------- 1 | from pyjac.loopy_utils.loopy_utils import loopy_options, load_platform 2 | 3 | __all__ = ["loopy_options", "load_platform"] 4 | -------------------------------------------------------------------------------- /pyjac/loopy_utils/loopy_edit_script.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | """ 4 | A simple script that acts as the 'EDITOR' for loopy code generation, 5 | changing simple code-generation patterns that cause errors for various 6 | OpenCL implementations (mostly Intel) 7 | """ 8 | 9 | import sys 10 | import re 11 | from collections import OrderedDict 12 | 13 | swaps = OrderedDict([ 14 | # replace "bad" lid()/gid() subtractions in for loop clauses 15 | # re: https://software.intel.com/en-us/forums/opencl/topic/704155 16 | (r'(for.+)\+\s*-1\s*\*\s*((?:lid|gid)\((?:\d+)\))([^;]+)', r'\1\3 - \2'), 17 | # replace "bad" lid()/gid() subtractions in general 18 | # re: https://software.intel.com/en-us/forums/opencl/topic/709578 19 | (r'(\+\s*-\s*)(\d+)\s*\*\s*((?:lid|gid)\((?:\d+)\))', r'- \2 * \3'), 20 | # edit in &'s for atomic add/div/etc operators 21 | (r'([^\s]+)\b\s*=\s*(atomic\w+_\w+\s*\(\s*)\1', r'\2&\1') 22 | ]) 23 | 24 | 25 | def __get_file(filename, text_in=None): 26 | if filename.lower() == 'stdin': 27 | lines = text_in.split('\n') 28 | else: 29 | with open(filename, 'r') as file: 30 | lines = file.readlines() 31 | return lines 32 | 33 | 34 | def __save_file(filename, lines): 35 | if filename.lower() != 'stdin': 36 | with open(filename, 'w') as file: 37 | file.writelines(lines) 38 | 39 | 40 | def substitute(filename, text_in=None, extra_subs={}): 41 | lines = __get_file(filename, text_in=text_in) 42 | 43 | # grab any platform specific substitutions 44 | lswaps = swaps.copy() 45 | lswaps.update(extra_subs) 46 | # do any replacements 47 | for swap in lswaps: 48 | lines = [re.sub(swap, lswaps[swap], line) for line in lines] 49 | 50 | __save_file(filename, lines) 51 | return '\n'.join(lines) 52 | 53 | 54 | if __name__ == '__main__': 55 | substitute(sys.argv[1], sys.argv[2:]) 56 | -------------------------------------------------------------------------------- /pyjac/performance_tester/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SLACKHA/pyJac-v2/1cdd67bc4bdfdde37c9fa73674428187d5f875a8/pyjac/performance_tester/__init__.py -------------------------------------------------------------------------------- /pyjac/performance_tester/__main__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from argparse import ArgumentParser 3 | 4 | import loopy as lp 5 | 6 | from pyjac.performance_tester.performance_tester import species_performance_tester, \ 7 | jacobian_performance_tester 8 | from pyjac import utils 9 | 10 | 11 | def main(args=None): 12 | lp.set_caching_enabled(False) 13 | utils.setup_logging() 14 | if args is None: 15 | # command line arguments 16 | parser = ArgumentParser(description='performance_tester.py: ' 17 | 'tests pyJac performance') 18 | parser.add_argument('-w', '--working_directory', 19 | type=str, 20 | default='performance', 21 | help='Directory storing the mechanisms / data.' 22 | ) 23 | parser.add_argument('-t', '--test_matrix', 24 | type=str, 25 | help='The platforms / tests to run, as well as ' 26 | 'possible memory limits. For an example see' 27 | 'the pyjac/examples/test_matrix.yaml included with' 28 | 'pyJac' 29 | ) 30 | parser.add_argument('-r', '--runtype', 31 | choices=['jac', 'spec', 'both'], 32 | default='both', 33 | help='The type of validation test to run, Jacobian [jac]' 34 | ' or species rates [spec], or [both].') 35 | parser.add_argument('-p', '--prefix', 36 | type=str, 37 | default='', 38 | help='A prefix to store the output of this test in' 39 | 'for each mechanism in the working_directory.' 40 | 'This can be a helpful tool on a cluster to ' 41 | 'run multiple tests at once on different platforms') 42 | args = parser.parse_args() 43 | methods = [] 44 | if args.runtype == 'jac': 45 | methods = [jacobian_performance_tester] 46 | elif args.runtype == 'spec': 47 | methods = [species_performance_tester] 48 | else: 49 | methods = [species_performance_tester, jacobian_performance_tester] 50 | 51 | for m in methods: 52 | m(args.working_directory, args.test_matrix, args.prefix) 53 | 54 | 55 | if __name__ == '__main__': 56 | sys.exit(main()) 57 | -------------------------------------------------------------------------------- /pyjac/pywrap/__init__.py: -------------------------------------------------------------------------------- 1 | from pyjac.pywrap.pywrap_gen import pywrap 2 | 3 | __all__ = ['pywrap'] 4 | -------------------------------------------------------------------------------- /pyjac/pywrap/__main__.py: -------------------------------------------------------------------------------- 1 | """Main module for pywrap module. 2 | """ 3 | from argparse import ArgumentParser 4 | 5 | from pyjac import utils 6 | from pyjac.pywrap.pywrap_gen import pywrap 7 | from pyjac.core.enum_types import KernelType 8 | 9 | if __name__ == '__main__': 10 | parser = ArgumentParser( 11 | description='Generates a python wrapper for pyJac via Cython' 12 | ) 13 | parser.add_argument('-l', '--lang', 14 | type=str, 15 | choices=utils.langs, 16 | required=True, 17 | help='Programming language for output ' 18 | 'source files' 19 | ) 20 | parser.add_argument('-so', '--source_dir', 21 | type=str, 22 | required=True, 23 | help='The folder that contains the generated pyJac ' 24 | 'files.') 25 | parser.add_argument('-out', '--out_dir', 26 | type=str, 27 | required=False, 28 | default=None, 29 | help='The folder to place the generated library in') 30 | parser.add_argument('-kt', '--kernel_type', 31 | required=False, 32 | type=utils.EnumType(KernelType), 33 | default='jacobian', 34 | help='The type of library to build: {type}'.format( 35 | type=str(utils.EnumType(KernelType)))) 36 | 37 | args = parser.parse_args() 38 | pywrap(args.lang, args.source_dir, args.out_dir, 39 | ktype=args.kernel_type) 40 | -------------------------------------------------------------------------------- /pyjac/pywrap/adjacob_setup.py.in: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | import distutils.ccompiler 3 | 4 | from Cython.Distutils import build_ext 5 | from Cython.Build import cythonize 6 | import parallel_compiler as pcc 7 | import numpy 8 | import os 9 | 10 | sources = ['$homepath/adjacob_wrapper.pyx'] 11 | includes = ['$buildpath/', '$homepath/'] 12 | 13 | distutils.ccompiler.CCompiler.compile = pcc.parallel_compile 14 | 15 | os.environ["CC"] = "g++" 16 | os.environ["CXX"] = "g++" 17 | 18 | ext = [Extension("adjacob", 19 | sources=sources, 20 | include_dirs=includes + [numpy.get_include()], 21 | extra_compile_args=['-frounding-math', '-fsignaling-nans', 22 | '-DADEPT_STACK_THREAD_UNSAFE', '-fopenmp'], 23 | language='c++', 24 | libraries=['adept'], 25 | extra_link_args=['-fopenmp'], 26 | extra_objects=[os.path.join('$outpath', '$libname')] 27 | )] 28 | 29 | setup( 30 | name='adjacob', 31 | ext_modules=ext, 32 | cmdclass={'build_ext': build_ext}, 33 | ) 34 | -------------------------------------------------------------------------------- /pyjac/pywrap/adjacob_wrapper.pyx: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | # distutils: language = c++ 3 | 4 | cimport numpy as np 5 | 6 | cdef extern from "ad_jacob.h": 7 | void eval_jacob (const double t, const double pres, const double* y, double* jac) 8 | 9 | def ad_eval_jacobian(np.double_t t, 10 | np.double_t pres, 11 | np.ndarray[np.double_t] y, 12 | np.ndarray[np.double_t] jac): 13 | eval_jacob(t, pres, &y[0], &jac[0]) -------------------------------------------------------------------------------- /pyjac/pywrap/parallel_compiler.py: -------------------------------------------------------------------------------- 1 | """Module for performing parallel compilation of source code files. 2 | """ 3 | 4 | import multiprocessing 5 | from multiprocessing import Pool 6 | import distutils.ccompiler 7 | 8 | N = multiprocessing.cpu_count() 9 | 10 | # monkey-patch for parallel compilation 11 | def parallel_compile(self, sources, output_dir=None, macros=None, 12 | include_dirs=None, debug=False, extra_preargs=None, 13 | extra_postargs=None, depends=None 14 | ): 15 | """Compile source files in parallel. 16 | 17 | Parameters 18 | ---------- 19 | sources : list of `str` 20 | List of source files 21 | output_dir : str 22 | Optional; path to directory for object files 23 | macros : list of `tuple` 24 | Optional; list of macro definitions, like (name, value) or (name,) 25 | include_dirs : list of `str` 26 | Optional; list of directories to add to default include file search path 27 | debug : bool 28 | Optional; if ``True``, instruct compiler to output debug signals 29 | extra_preargs : list of `str` 30 | Optional; extra command-line arguments to prepend to compiler command 31 | extra_postargs : list of `str` 32 | Optional; extra command-line arguments to append to compiler command 33 | depends : list of `str` 34 | Optional; list of filenames that target depends on 35 | 36 | Returns 37 | ------- 38 | objects : list of `str` 39 | List of object files generated 40 | 41 | """ 42 | # those lines are copied from distutils.ccompiler.CCompiler directly 43 | macros, objects, extra_postargs, pp_opts, build = self._setup_compile( 44 | output_dir, macros, include_dirs, sources, depends, extra_postargs 45 | ) 46 | cc_args = self._get_cc_args(pp_opts, debug, extra_preargs) 47 | 48 | # number of parallel compilations 49 | 50 | def _single_compile(obj): 51 | """Compile single file. 52 | """ 53 | try: 54 | src, ext = build[obj] 55 | except KeyError: 56 | return 57 | self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) 58 | 59 | pool = Pool(N) 60 | pool.imap(_single_compile, objects) 61 | pool.close() 62 | pool.join() 63 | 64 | return objects 65 | -------------------------------------------------------------------------------- /pyjac/pywrap/py_tchem.c: -------------------------------------------------------------------------------- 1 | /* wrapper to interface with TChem */ 2 | 3 | #include "header.h" 4 | #include "TC_interface.h" 5 | 6 | void tc_eval_jacob (char* mechfile, char* thermofile, const int num, 7 | const double* pres, double* y, double* conc, 8 | double* fwd_rates, double* rev_rates, double* spec_rates, 9 | double* dydt, double* jac) { 10 | 11 | /* Initialize TC library */ 12 | int withtab = 0; 13 | TC_initChem (mechfile, thermofile, withtab, 1.0); 14 | 15 | for (int tid = 0; tid < num; ++tid) { 16 | // set pressure 17 | TC_setThermoPres (pres[tid]); 18 | 19 | // get concentration 20 | TC_getMs2Cc (&y[tid * NN], NN, &conc[tid*NSP]); 21 | 22 | // get reaction rates of progress 23 | double rxn_rates[2 * FWD_RATES]; 24 | TC_getRfrb (&y[tid * NN], NN, rxn_rates); 25 | for (int i = 0; i < FWD_RATES; ++i) { 26 | fwd_rates[tid*FWD_RATES + i] = rxn_rates[i]; 27 | rev_rates[tid*FWD_RATES + i] = rxn_rates[FWD_RATES + i]; 28 | } 29 | 30 | // get species production rates 31 | TC_getTY2RRml (&y[tid * NN], NN, &spec_rates[tid*NSP]); 32 | 33 | // get derivative 34 | TC_getSrc (&y[tid * NN], NN, &dydt[tid*NN]); 35 | 36 | // get reduced Jacobian matrix 37 | TC_getJacTYNm1anl (&y[tid * NN], NSP, &jac[tid*NSP*NSP]); 38 | } 39 | 40 | TC_reset(); 41 | 42 | return; 43 | } 44 | -------------------------------------------------------------------------------- /pyjac/pywrap/py_tchem.h: -------------------------------------------------------------------------------- 1 | /* wrapper to TChem interface */ 2 | 3 | #ifndef PY_TCHEM_HEAD 4 | #define PY_TCHEM_HEAD 5 | 6 | void tc_eval_jacob (char* mech, char* thermo, const int num, 7 | const double* pres, double* y, double* conc, 8 | double* fwd_rates, double* rev_rates, 9 | double* spec_rates, double* dydt, double* jac); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /pyjac/pywrap/pyjacob.cu: -------------------------------------------------------------------------------- 1 | /* wrapper to translate to cuda arrays */ 2 | 3 | #include "header.cuh" 4 | #include "gpu_memory.cuh" 5 | #include "launch_bounds.cuh" 6 | #include "chem_utils.cuh" 7 | #include "rates.cuh" 8 | #include "jacob.cuh" 9 | #include "dydt.cuh" 10 | #include 11 | #include 12 | #include 13 | 14 | #define T_ID (threadIdx.x + (blockDim.x * blockIdx.x)) 15 | 16 | #define ECHECK 17 | 18 | __global__ 19 | void k_dydt(const int num, const double* pres, const double* y, double * dy, const mechanism_memory* d_mem) 20 | { 21 | if (T_ID < num) 22 | { 23 | dydt(0, pres[T_ID], y, dy, d_mem); 24 | } 25 | } 26 | 27 | 28 | __global__ 29 | void k_eval_jacob(const int num, const double* pres, const double* y, double * jac, const mechanism_memory* d_mem) 30 | { 31 | if (T_ID < num) 32 | { 33 | eval_jacob(0, pres[T_ID], y, jac, d_mem); 34 | } 35 | } 36 | 37 | inline void check_err() 38 | { 39 | #ifdef ECHECK 40 | cudaErrorCheck( cudaPeekAtLastError() ); 41 | cudaErrorCheck( cudaDeviceSynchronize() ); 42 | #endif 43 | } 44 | 45 | inline void memcpy2D_out(double* dst, const int pitch_dst, double const * src, const int pitch_src, 46 | const int offset, const size_t width, const int height) { 47 | for (int i = 0; i < height; ++i) 48 | { 49 | memcpy(&dst[offset], src, width); 50 | dst += pitch_dst; 51 | src += pitch_src; 52 | } 53 | } 54 | 55 | inline void memcpy2D_in(double* dst, const int pitch_dst, double const * src, const int pitch_src, 56 | const int offset, const size_t width, const int height) { 57 | for (int i = 0; i < height; ++i) 58 | { 59 | memcpy(dst, &src[offset], width); 60 | dst += pitch_dst; 61 | src += pitch_src; 62 | } 63 | } 64 | 65 | mechanism_memory * d_mem = 0; 66 | mechanism_memory * h_mem = 0; 67 | double* y_temp = 0; 68 | double* pres_temp = 0; 69 | double* conc_temp = 0; 70 | double* fwd_temp = 0; 71 | #if REV_RATES > 0 72 | double* rev_temp = 0; 73 | #endif 74 | #if PRES_MOD_RATES > 0 75 | double* pres_mod_temp = 0; 76 | #endif 77 | double* spec_temp = 0; 78 | double* dy_temp = 0; 79 | double* jac_temp = 0; 80 | int device = 0; 81 | 82 | #define USE_MEM (0.8) 83 | 84 | int init(int num) 85 | { 86 | cudaErrorCheck( cudaSetDevice(device) ); 87 | //reset device 88 | cudaErrorCheck( cudaDeviceReset() ); 89 | #ifdef PREFERL1 90 | //prefer L1 for speed 91 | cudaErrorCheck(cudaDeviceSetCacheConfig(cudaFuncCachePreferL1)); 92 | cudaFuncCache L1type; 93 | cudaErrorCheck(cudaDeviceGetCacheConfig(&L1type)); 94 | assert(L1type == cudaFuncCachePreferL1); 95 | printf("L1 Cache size increased...\n"); 96 | #endif 97 | //determine maximum # of threads for this mechanism 98 | //bytes per thread 99 | size_t mech_size = required_mechanism_size(); 100 | size_t free_mem = 0; 101 | size_t total_mem = 0; 102 | cudaErrorCheck( cudaMemGetInfo (&free_mem, &total_mem) ); 103 | //conservatively estimate the maximum allowable threads 104 | int max_threads = int(floor(USE_MEM * ((double)free_mem) / ((double)mech_size))); 105 | int padded = min(num, max_threads); 106 | //padded is next factor of block size up 107 | padded = int(ceil(padded / float(TARGET_BLOCK_SIZE)) * TARGET_BLOCK_SIZE); 108 | if (padded == 0) 109 | { 110 | printf("Mechanism is too large to fit into global CUDA memory... exiting."); 111 | exit(-1); 112 | } 113 | 114 | printf("Initializing CUDA interface...\n"); 115 | printf("%ld free bytes of memory found on Device 0.\n", free_mem); 116 | printf("%ld bytes required per mechanism thread\n", mech_size); 117 | printf("Setting up memory to work on kernels of %d threads, with blocksize %d\n", padded, TARGET_BLOCK_SIZE); 118 | 119 | h_mem = (mechanism_memory*)malloc(sizeof(mechanism_memory)); 120 | initialize_gpu_memory(padded, &h_mem, &d_mem); 121 | return padded; 122 | } 123 | 124 | void cleanup() 125 | { 126 | //clean up 127 | free_gpu_memory(&h_mem, &d_mem); 128 | free(h_mem); 129 | 130 | //reset device 131 | cudaErrorCheck( cudaDeviceReset() ); 132 | } 133 | 134 | void run(int num, int padded, const double* pres, const double* mass_frac, 135 | double* conc, double* fwd_rxn_rates, double* rev_rxn_rates, 136 | double* pres_mod, double* spec_rates, double* dy, double* jac) 137 | { 138 | int grid_num = padded / TARGET_BLOCK_SIZE; 139 | size_t pitch_host = num * sizeof(double); 140 | size_t pitch_device = padded * sizeof(double); 141 | 142 | //copy over our data 143 | cudaErrorCheck( cudaMemcpy(h_mem->var, pres, pitch_host, cudaMemcpyHostToDevice) ); 144 | cudaErrorCheck( cudaMemcpy2D(h_mem->y, pitch_device, mass_frac, 145 | pitch_host, pitch_host, NSP, cudaMemcpyHostToDevice) ); 146 | 147 | size_t smem = 0; 148 | #ifdef SHARED_SIZE 149 | smem = SHARED_SIZE; 150 | #endif 151 | //eval dydt 152 | //this gets us all arrays but the Jacobian 153 | k_dydt<<>>(num, h_mem->var, h_mem->y, h_mem->dy, d_mem); 154 | 155 | check_err(); 156 | 157 | //copy back 158 | cudaErrorCheck( cudaMemcpy2D(conc, pitch_host, h_mem->conc, pitch_device, 159 | pitch_host, NSP, cudaMemcpyDeviceToHost) ); 160 | 161 | cudaErrorCheck( cudaMemcpy2D(fwd_rxn_rates, pitch_host, h_mem->fwd_rates, pitch_device, 162 | pitch_host, FWD_RATES, cudaMemcpyDeviceToHost) ); 163 | 164 | #if REV_RATES != 0 165 | cudaErrorCheck( cudaMemcpy2D(rev_rxn_rates, pitch_host, h_mem->rev_rates, 166 | pitch_device, pitch_host, REV_RATES, cudaMemcpyDeviceToHost) ); 167 | #endif 168 | 169 | #if PRES_MOD_RATES != 0 170 | cudaErrorCheck( cudaMemcpy2D(pres_mod, pitch_host, h_mem->pres_mod, pitch_device, pitch_host, 171 | PRES_MOD_RATES, cudaMemcpyDeviceToHost) ); 172 | #endif 173 | 174 | cudaErrorCheck( cudaMemcpy2D(spec_rates, pitch_host, h_mem->spec_rates, pitch_device, 175 | pitch_host, NSP, cudaMemcpyDeviceToHost) ); 176 | 177 | cudaErrorCheck( cudaMemcpy2D(dy, pitch_host, h_mem->dy, pitch_device, pitch_host, 178 | NSP, cudaMemcpyDeviceToHost) ); 179 | 180 | //jacobian 181 | k_eval_jacob<<>>(num, h_mem->var, h_mem->y, h_mem->jac, d_mem); 182 | 183 | check_err(); 184 | 185 | //copy back 186 | cudaErrorCheck( cudaMemcpy2D(jac, pitch_host, h_mem->jac, pitch_device, 187 | pitch_host, NSP * NSP, cudaMemcpyDeviceToHost) ); 188 | } -------------------------------------------------------------------------------- /pyjac/pywrap/pyjacob.cuh: -------------------------------------------------------------------------------- 1 | /* wrapper to translate to cuda arrays */ 2 | 3 | #ifndef CU_PYJAC_HEAD 4 | #define CU_PYJAC_HEAD 5 | 6 | void run(int, int, const double*, const double*, 7 | double*, double*, double*, 8 | double*, double*, double*, double*); 9 | int init(int); 10 | void cleanup(); 11 | 12 | #endif -------------------------------------------------------------------------------- /pyjac/pywrap/pyjacob_cuda_wrapper.pyx: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | cimport numpy as np 3 | cimport cython 4 | 5 | cdef extern from "pyjacob.cuh": 6 | void run(int num, int padded, const double* pres, const double* mass_frac, 7 | double* conc, double* fwd_rxn_rates, double* rev_rxn_rates, 8 | double* pres_mod, double* spec_rates, double* dy, double* jac); 9 | int init(int); 10 | void cleanup(); 11 | 12 | @cython.boundscheck(False) 13 | def py_cuinit(int num): 14 | return init(num) 15 | 16 | @cython.boundscheck(False) 17 | def py_cuclean(): 18 | cleanup() 19 | 20 | 21 | @cython.boundscheck(False) 22 | def py_cujac(int num, 23 | int padded, 24 | np.ndarray[np.double_t, mode='c'] pres, 25 | np.ndarray[np.double_t, mode='c'] y, 26 | np.ndarray[np.double_t, mode='c'] conc, 27 | np.ndarray[np.double_t, mode='c'] fwd_rates, 28 | np.ndarray[np.double_t, mode='c'] rev_rates, 29 | np.ndarray[np.double_t, mode='c'] pres_mod, 30 | np.ndarray[np.double_t, mode='c'] spec_rates, 31 | np.ndarray[np.double_t, mode='c'] dy, 32 | np.ndarray[np.double_t, mode='c'] jac): 33 | run(num, padded, &pres[0], &y[0], &conc[0], &fwd_rates[0], &rev_rates[0], 34 | &pres_mod[0], &spec_rates[0], &dy[0], &jac[0]) -------------------------------------------------------------------------------- /pyjac/pywrap/pyjacob_setup.py.in: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from distutils.extension import Extension 3 | from Cython.Build import cythonize 4 | import numpy 5 | 6 | """[[[cog 7 | from six.moves import cPickle as pickle 8 | from pyjac.utils import stringify_args, listify 9 | 10 | # unserialize the setupgen object 11 | with open(setupgen, 'rb') as file: 12 | setupgen = pickle.load(file) 13 | 14 | cog.outl('sources = ["{}"]'.format(setupgen.wrapper)) 15 | cog.outl('includes = [{}]'.format(stringify_args( 16 | [setupgen.build_dir] + listify(setupgen.include_dirs), use_quotes=True))) 17 | cog.outl('name = "pyjac_{}"'.format(setupgen.package_lang)) 18 | if setupgen.package_lang == 'c': 19 | # include openmp 20 | cog.outl('compile_args = ["-fopenmp"]') 21 | else: 22 | cog.outl('compile_args = []') 23 | cog.outl('name = "{}_{}"'.format(setupgen.name, setupgen.package_lang)) 24 | cog.outl('libname = "{}"'.format(setupgen.libname)) 25 | cog.outl('libs = [{}]'.format(stringify_args( 26 | setupgen.libraries, use_quotes=True))) 27 | cog.outl('libdirs = [{}]'.format(stringify_args( 28 | setupgen.libdirs, use_quotes=True))) 29 | ]]] 30 | [[[end]]]""" 31 | includes = [x for x in includes if x.strip()] 32 | 33 | ext_module = Extension(name, 34 | sources=sources, 35 | include_dirs=includes + [numpy.get_include()], 36 | language="c++", 37 | extra_compile_args=['-frounding-math', '-fsignaling-nans', 38 | '-std=c++11'] + compile_args, 39 | extra_objects=[libname], 40 | libraries=libs, 41 | library_dirs=libdirs) 42 | 43 | setup( 44 | name=name, 45 | ext_modules=cythonize(ext_module, include_path=includes, 46 | compiler_directives={'language_level': 3}) 47 | ) 48 | -------------------------------------------------------------------------------- /pyjac/pywrap/pyjacob_wrapper.pyx.in: -------------------------------------------------------------------------------- 1 | # distutils: language = c++ 2 | 3 | import cython 4 | import numpy as np 5 | cimport numpy as np 6 | from libcpp cimport bool as bool_t # noqa 7 | from libcpp.string cimport string as string_t # noqa 8 | from libcpp.vector cimport vector # noqa 9 | 10 | '''[[[cog 11 | from six.moves import cPickle as pickle 12 | from pyjac.utils import indent, stdindent, header_ext 13 | from pyjac.kernel_utils.tools import make_doc_str 14 | 15 | with open(wrappergen, 'rb') as file: 16 | wrappergen = pickle.load(file) 17 | 18 | kernel_args = ', '.join(['double* {}'.format(x) for x in wrappergen.kernel_args]) 19 | kernel_name = '{name}Kernel'.format(name=wrappergen.name.title()) 20 | # write Cython defns 21 | cog.outl(""" 22 | cdef extern from "{name}_main{ext}": 23 | cdef cppclass {kernel_name}: 24 | {kernel_name}() except + 25 | {kernel_name}(size_t, size_t, bool_t) except + 26 | 27 | vector[const char*] speciesNames() except+ 28 | vector[const char*] reactionStrings() except+ 29 | unsigned int numSpecies() except + 30 | unsigned int numReactions() except + 31 | unsigned int requiredMemorySize() except + 32 | string_t order() except+ 33 | void resize(size_t, size_t, bool_t) except + 34 | void operator()({args}) except + 35 | """.format(name=wrappergen.name, kernel_name=kernel_name, args=kernel_args, 36 | ext=header_ext[wrappergen.lang]), 37 | trimblanklines=True, dedent=False) 38 | ]]] 39 | [[[end]]]''' 40 | 41 | 42 | '''[[[cog 43 | # and write the python wrapper class 44 | # get args 45 | numpy_args = [] 46 | args = [] 47 | for arg in wrappergen.kernel_args: 48 | numpy_args.append('np.ndarray[np.float64_t] {name}'.format(name=arg)) 49 | args.append('&{arg}[0]'.format(arg=arg)) 50 | numpy_args = ', '.join(numpy_args) 51 | args = ', '.join(args) 52 | 53 | cog.out(""" 54 | cdef class Py{name}: 55 | cdef {name} kernel # hold our kernel 56 | 57 | def __cinit__(self, size_t problem_size, size_t work_size, 58 | bool_t do_not_compile=False, **kwargs): 59 | if not kwargs.pop('testing_only_skip_compilation', False): 60 | self.kernel.resize(problem_size, work_size, do_not_compile) 61 | 62 | def species_names(self): 63 | species = self.kernel.speciesNames() 64 | return [x.decode('UTF-8') for x in species] 65 | 66 | def reaction_strings(self): 67 | rxns = self.kernel.reactionStrings() 68 | return [x.decode('UTF-8') for x in rxns] 69 | 70 | def num_reactions(self): 71 | return self.kernel.numReactions() 72 | 73 | def num_species(self): 74 | return self.kernel.numSpecies() 75 | 76 | def required_working_memory(self): 77 | return self.kernel.requiredMemorySize() 78 | 79 | def resize(self, np.uint_t problem_size, np.uint_t work_size, 80 | bool_t do_not_compile=False):""".format(name=kernel_name)) 81 | cog.out(indent( 82 | make_doc_str(wrappergen, ['problem_size', 'work_size', 'do_not_compile'], 83 | 'Resize the {} memory buffers'.format(wrappergen.lang.title()), 84 | comment_type='python'), 2 * stdindent)) 85 | cog.outl(""" 86 | self.kernel.resize(problem_size, work_size, do_not_compile) 87 | 88 | def __call__(self, {numpy_args}): 89 | self.kernel({args}) 90 | """.format(numpy_args=numpy_args, args=args)) 91 | ]]] 92 | [[[end]]]''' 93 | -------------------------------------------------------------------------------- /pyjac/pywrap/pytchem_setup.py.in: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | from setuptools import setup 4 | from distutils.extension import Extension 5 | from Cython.Distutils import build_ext 6 | import numpy 7 | 8 | import distutils.ccompiler 9 | import parallel_compiler as pcc 10 | distutils.ccompiler.CCompiler.compile = pcc.parallel_compile 11 | 12 | if os.getenv('TCHEM_HOME'): 13 | tchem_home = os.getenv('TCHEM_HOME') 14 | else: 15 | raise SystemError('TCHEM_HOME environment variable must be set in order to test with TChem.') 16 | 17 | # Need to copy periodic table file into local directory... for some reason 18 | shutil.copy(os.path.join(tchem_home, 'data', 'periodictable.dat'), 19 | 'periodictable.dat' 20 | ) 21 | 22 | sources = ['$homepath/pytchem_wrapper.pyx', '$homepath/py_tchem.c'] 23 | includes = ['$buildpath', '$homepath'] 24 | 25 | ext = Extension('py_tchem', 26 | sources=sources, 27 | library_dirs=[os.path.join(tchem_home, 'lib')], 28 | libraries=['c', 'tchem'], 29 | language='c', 30 | include_dirs=includes + [numpy.get_include(), 31 | os.path.join(tchem_home, 'include') 32 | ], 33 | extra_compile_args=['-frounding-math', '-fsignaling-nans', '-std=c99'] 34 | ) 35 | 36 | setup(name='py_tchem', 37 | ext_modules=[ext], 38 | cmdclass={'build_ext': build_ext}, 39 | # since the package has c code, the egg cannot be zipped 40 | zip_safe=False 41 | ) 42 | -------------------------------------------------------------------------------- /pyjac/pywrap/pytchem_wrapper.pyx: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | cimport numpy as np 3 | cimport cython 4 | 5 | cdef extern from "py_tchem.h": 6 | void tc_eval_jacob (char* mechname, char* thermoname, 7 | const int num, const double* pres, 8 | double* y, double* conc, double* fwd_rates, 9 | double* rev_rates, double* spec_rates, 10 | double* dydt, double* jac 11 | ) 12 | 13 | @cython.boundscheck(False) 14 | def py_eval_jacobian(str mechname, str thermoname, int num, 15 | np.ndarray[np.double_t, mode='c'] pres, 16 | np.ndarray[np.double_t, mode='c'] y, 17 | np.ndarray[np.double_t, mode='c'] conc, 18 | np.ndarray[np.double_t, mode='c'] fwd_rates, 19 | np.ndarray[np.double_t, mode='c'] rev_rates, 20 | np.ndarray[np.double_t, mode='c'] spec_rates, 21 | np.ndarray[np.double_t, mode='c'] dydt, 22 | np.ndarray[np.double_t, mode='c'] jac 23 | ): 24 | cdef bytes py_bytes_mech = mechname.encode() 25 | cdef char* c_mech = py_bytes_mech 26 | cdef bytes py_bytes_therm = thermoname.encode() 27 | cdef char* c_therm = py_bytes_therm 28 | 29 | tc_eval_jacob(c_mech, c_therm, num, &pres[0], &y[0], &conc[0], 30 | &fwd_rates[0], &rev_rates[0], &spec_rates[0], 31 | &dydt[0], &jac[0] 32 | ) 33 | -------------------------------------------------------------------------------- /pyjac/schemas/codegen_platform.yaml: -------------------------------------------------------------------------------- 1 | # A schema to validate platform specification for pyJac 2 | 3 | platform: 4 | type: dict 5 | schema: 6 | # platform name 7 | name: 8 | type: string 9 | required: True 10 | # language 11 | lang: 12 | type: string 13 | isvalidlang: True 14 | required: True 15 | # order 16 | order: 17 | type: string 18 | nullable: True 19 | allowed: ['C', 'F'] 20 | width: 21 | type: integer 22 | isvecsize: True 23 | excludes: 24 | depth 25 | depth: 26 | type: integer 27 | isvecsize: True 28 | excludes: 29 | width 30 | # If True, the platform / language support atomics for deep-vectorization 31 | atomic_doubles: 32 | type: boolean 33 | default: True 34 | # If True, the platform / language supports integer atomics. These may be 35 | # used in the driver kernel queue to reduce global memory usage 36 | atomic_ints: 37 | type: boolean 38 | default: True 39 | # If true, this platform should use explicit-SIMD vectorization, if available 40 | is_simd: 41 | type: boolean 42 | default: False 43 | dependencies: 44 | # can curretly only be specified for wide-vectorizations 45 | width 46 | 47 | # optional memory limits 48 | memory-limits: 49 | type: dict 50 | schema: memory-limits 51 | -------------------------------------------------------------------------------- /pyjac/schemas/common_schema.yaml: -------------------------------------------------------------------------------- 1 | memory-limits: 2 | type: dict 3 | schema: 4 | # limit on total global memory allocation by pyJac 5 | global: 6 | type: bytestr 7 | # limit on total __local/ shared memory allocation by pyJac, only applies to OpenCL / 8 | # CUDA 9 | local: 10 | type: bytestr 11 | # limit on total __constant memory allocation by pyJac, only applies to OpenCL / CUDA 12 | constant: 13 | type: bytestr 14 | # limit on the maximum global memory allocation per array by pyJac, 15 | alloc: 16 | type: bytestr 17 | platforms: 18 | type: list 19 | schema: 20 | type: string 21 | 22 | # platform for testing, allows multiple values for vectype, width, etc. 23 | variable-platform: 24 | type: dict 25 | schema: 26 | # platform name 27 | name: 28 | type: string 29 | required: True 30 | # language 31 | lang: 32 | type: string 33 | isvalidlang: True 34 | required: True 35 | # wide-vectorization sizes 36 | width: 37 | type: list 38 | schema: 39 | isvecsize: True 40 | required: False 41 | # deep-vectorization sizes 42 | depth: 43 | type: list 44 | schema: 45 | isvecsize: True 46 | required: False 47 | # order 48 | order: 49 | type: list 50 | schema: 51 | type: string 52 | allowed: ['C', 'F'] 53 | nullable: True 54 | default: ['C', 'F'] 55 | # If True, the platform / language support atomics for deep-vectorization 56 | atomic_doubles: 57 | type: boolean 58 | default: True 59 | # If True, the platform / language supports integer atomics. These may be 60 | # used in the driver kernel queue to reduce global memory usage 61 | atomic_ints: 62 | type: boolean 63 | default: True 64 | is_simd: 65 | type: list 66 | schema: 67 | type: boolean 68 | 69 | # overrides for individual tests 70 | override: 71 | type: dict 72 | schema: 73 | num_cores: 74 | type: list 75 | schema: 76 | type: integer 77 | order: 78 | type: list 79 | schema: 80 | type: string 81 | allowed: ['C', 'F'] 82 | gpuorder: 83 | type: list 84 | schema: 85 | type: string 86 | allowed: ['C', 'F'] 87 | conp: 88 | type: list 89 | schema: 90 | type: string 91 | allowed: ['conp', 'conv'] 92 | width: 93 | type: list 94 | schema: 95 | isvecsize: True 96 | depth: 97 | type: list 98 | schema: 99 | isvecsize: True 100 | # vector size overrides for GPUs 101 | gpuwidth: 102 | type: list 103 | schema: 104 | isvecsize: True 105 | gpudepth: 106 | type: list 107 | schema: 108 | isvecsize: True 109 | # allow exclusion of models 110 | models: 111 | type: list 112 | schema: 113 | type: string 114 | -------------------------------------------------------------------------------- /pyjac/schemas/test_matrix_schema.yaml: -------------------------------------------------------------------------------- 1 | # A schema to validate test matrix specification for pyJac 2 | 3 | # model specification 4 | model-list: 5 | required: True 6 | type: list 7 | schema: 8 | type: dict 9 | schema: 10 | # mechanism name 11 | name: 12 | type: string 13 | required: True 14 | # cantera format mechanism 15 | mech: 16 | type: string 17 | required: True 18 | regex: '^.+\.(cti|xml)$' 19 | # optional path to mechanism 20 | path: 21 | type: string 22 | nullable: True 23 | # optional limits on number of initial conditions for various runtypes 24 | limits: 25 | type: dict 26 | schema: 27 | # limit on species rate evaluations 28 | species_rates: 29 | type: integer 30 | min: 0 31 | # limit on jacobian evaluations 32 | jacobian: 33 | type: dict 34 | schema: 35 | # sparse jacobian 36 | sparse: 37 | type: integer 38 | min: 0 39 | # dense jacobian 40 | full: 41 | type: integer 42 | min: 0 43 | 44 | # allow for optional specification of memory limits 45 | memory-limits: 46 | type: list 47 | schema: 48 | type: dict 49 | schema: memory-limits 50 | 51 | # and platform list 52 | platform-list: 53 | type: list 54 | schema: variable-platform 55 | required: True 56 | 57 | test-list: 58 | type: list 59 | schema: 60 | type: dict 61 | schema: 62 | # test type specification 63 | test-type: 64 | type: string 65 | required: True 66 | allowed: 67 | - validation 68 | - performance 69 | # evaluation type 70 | eval-type: 71 | type: string 72 | default: both 73 | allowed: 74 | - jacobian 75 | - species_rates 76 | - both 77 | # # allow overrides of platform defaults 78 | species_rates: 79 | type: dict 80 | dependencies: 81 | eval-type: 82 | - species_rates 83 | - both 84 | schema: override 85 | finite_difference: 86 | type: dict 87 | dependencies: 88 | eval-type: 89 | - jacobian 90 | - both 91 | schema: 92 | sparse: 93 | type: dict 94 | schema: override 95 | full: 96 | type: dict 97 | schema: override 98 | both: 99 | type: dict 100 | schema: override 101 | exact: 102 | type: dict 103 | dependencies: 104 | eval-type: 105 | - jacobian 106 | - both 107 | schema: 108 | sparse: 109 | type: dict 110 | schema: override 111 | full: 112 | type: dict 113 | schema: override 114 | both: 115 | type: dict 116 | schema: override 117 | # specify which platforms to use, defaults to whole list 118 | platforms: 119 | type: list 120 | schema: 121 | type: string 122 | nullable: True 123 | -------------------------------------------------------------------------------- /pyjac/schemas/test_platform_schema.yaml: -------------------------------------------------------------------------------- 1 | # A schema to validate platform specification for pyJac 2 | 3 | platform-list: 4 | type: list 5 | required: True 6 | schema: variable-platform 7 | -------------------------------------------------------------------------------- /pyjac/tests/test_chem_model.py: -------------------------------------------------------------------------------- 1 | from pyjac.core.enum_types import falloff_form, reaction_type, reversible_type, \ 2 | thd_body_type 3 | from pyjac.tests import TestClass 4 | 5 | 6 | class SubTest(TestClass): 7 | 8 | def test_finalize(self): 9 | reacs = self.store.reacs 10 | for i, reac in enumerate(reacs): 11 | # for each reaction, test that we have the correct enums 12 | 13 | # test the reaction type 14 | if reac.pdep: 15 | # for falloff/chemically activated 16 | # also test the falloff form 17 | if reac.low: 18 | assert reaction_type.fall in reac.type 19 | assert all(x not in reac.type for x in reaction_type 20 | if x != reaction_type.fall) 21 | else: 22 | assert reaction_type.chem in reac.type 23 | assert all(x not in reac.type for x in reaction_type 24 | if x != reaction_type.chem) 25 | if reac.sri: 26 | assert falloff_form.sri in reac.type 27 | elif reac.troe: 28 | assert falloff_form.troe in reac.type 29 | else: 30 | assert falloff_form.lind in reac.type 31 | elif reac.thd_body: 32 | assert reaction_type.thd in reac.type 33 | assert all(x not in reac.type for x in reaction_type 34 | if x != reaction_type.thd) 35 | elif reac.plog: 36 | assert reaction_type.plog in reac.type 37 | assert all(x not in reac.type for x in reaction_type 38 | if x != reaction_type.plog) 39 | elif reac.cheb: 40 | assert reaction_type.cheb in reac.type 41 | assert all(x not in reac.type for x in reaction_type 42 | if x != reaction_type.cheb) 43 | else: 44 | assert reaction_type.elementary in reac.type 45 | assert all(x not in reac.type for x in reaction_type 46 | if x != reaction_type.elementary) 47 | 48 | # test the reversible type 49 | if reac.rev: 50 | if reac.rev_par: 51 | assert reversible_type.explicit in reac.type 52 | assert all(x not in reac.type for x in reversible_type 53 | if x != reversible_type.explicit) 54 | else: 55 | assert reversible_type.non_explicit in reac.type 56 | assert all(x not in reac.type for x in reversible_type 57 | if x != reversible_type.non_explicit) 58 | else: 59 | assert reversible_type.non_reversible in reac.type 60 | assert all(x not in reac.type for x in reversible_type 61 | if x != reversible_type.non_reversible) 62 | 63 | # finally test the third body types 64 | if reac.pdep or reac.thd_body: 65 | if reac.pdep_sp: 66 | assert thd_body_type.species in reac.type 67 | assert all(x not in reac.type for x in thd_body_type 68 | if x != thd_body_type.species) 69 | elif not reac.thd_body_eff: 70 | assert thd_body_type.unity in reac.type 71 | assert all(x not in reac.type for x in thd_body_type 72 | if x != thd_body_type.unity) 73 | else: 74 | assert thd_body_type.mix in reac.type 75 | assert all(x not in reac.type for x in thd_body_type 76 | if x != thd_body_type.mix) 77 | 78 | def test_rxn_strings(self): 79 | for i, rxn in enumerate(self.store.reacs): 80 | rstr = str(rxn) 81 | rstr = rstr[rstr.index(': ') + 2:] 82 | assert str(rstr) == str(self.store.gas.reaction(i).equation) 83 | -------------------------------------------------------------------------------- /pyjac/tests/test_chem_utils.py: -------------------------------------------------------------------------------- 1 | # local imports 2 | from pyjac.core.rate_subs import polyfit_kernel_gen, assign_rates 3 | from pyjac.loopy_utils.loopy_utils import kernel_call 4 | from pyjac.tests import TestClass 5 | from pyjac.tests.test_utils import _generic_tester 6 | 7 | # modules 8 | from nose.plugins.attrib import attr 9 | import numpy as np 10 | 11 | 12 | class SubTest(TestClass): 13 | def __subtest(self, ref_ans, nicename): 14 | def __wrapper(opt, namestore, test_size=None, **kwargs): 15 | return polyfit_kernel_gen(nicename, opt, namestore, 16 | test_size=test_size) 17 | 18 | # create args 19 | args = {'phi': lambda x: np.array(self.store.phi_cp, order=x, copy=True), 20 | nicename: lambda x: np.zeros_like(ref_ans, order=x)} 21 | # create the kernel call 22 | kc = kernel_call('eval_' + nicename, 23 | [ref_ans], 24 | **args) 25 | 26 | return _generic_tester(self, __wrapper, [kc], assign_rates) 27 | 28 | @attr('long') 29 | def test_cp(self): 30 | self.__subtest(self.store.spec_cp, 'cp') 31 | 32 | @attr('long') 33 | def test_cv(self): 34 | self.__subtest(self.store.spec_cv, 'cv') 35 | 36 | @attr('long') 37 | def test_h(self): 38 | self.__subtest(self.store.spec_h, 'h') 39 | 40 | @attr('long') 41 | def test_u(self): 42 | self.__subtest(self.store.spec_u, 'u') 43 | 44 | @attr('long') 45 | def test_b(self): 46 | self.__subtest(self.store.spec_b, 'b') 47 | -------------------------------------------------------------------------------- /pyjac/tests/test_conversions.py: -------------------------------------------------------------------------------- 1 | # local imports 2 | from pyjac.core.unit_conversions import (mass_to_mole_factions) 3 | from pyjac.core.rate_subs import assign_rates 4 | from pyjac.tests import TestClass 5 | from pyjac.loopy_utils.loopy_utils import kernel_call 6 | from pyjac.tests.test_utils import _generic_tester, get_comparable 7 | 8 | # modules 9 | import numpy as np 10 | from nose.plugins.attrib import attr 11 | 12 | 13 | class SubTest(TestClass): 14 | def __generic_conversion_tester( 15 | self, func, kernel_calls, do_conp=False, **kwargs): 16 | """ 17 | A generic testing method that can be used for various conversion tests 18 | This is primarily a thin wrapper for :func:`_generic_tester` 19 | 20 | Parameters 21 | ---------- 22 | func : function 23 | The function to test 24 | kernel_calls : :class:`kernel_call` or list thereof 25 | Contains the masks and reference answers for kernel testing 26 | do_conp: bool [False] 27 | If true, test for both constant pressure _and_ constant volume 28 | """ 29 | 30 | _generic_tester(self, func, kernel_calls, assign_rates, 31 | do_conp=do_conp, **kwargs) 32 | 33 | @attr('long') 34 | def test_mass_to_mole_fractions(self): 35 | # create a hybrid input array 36 | Yphi = np.concatenate((self.store.T.reshape(-1, 1), 37 | self.store.V.reshape(-1, 1), 38 | self.store.Y[:, :-1]), axis=1) 39 | 40 | args = {'phi': lambda x: np.array(Yphi, order=x, copy=True), 41 | 'mw_work': lambda x: np.zeros(self.store.test_size, order=x)} 42 | 43 | def __chainer(self, out_vals): 44 | self.kernel_args['mw_work'] = out_vals[-1][0] 45 | 46 | # first test w/o the splitting 47 | compare_mask = [get_comparable( 48 | (np.arange(self.store.test_size),), 1. / self.store.mw, 49 | compare_axis=(0,))] 50 | kc = kernel_call('molecular_weight_inverse', 51 | [1. / self.store.mw], 52 | strict_name_match=True, 53 | compare_axis=(0,), 54 | compare_mask=compare_mask, 55 | **args) 56 | mole_fractions = (self.store.mw * ( 57 | self.store.Y[:, :-1] / self.store.gas.molecular_weights[:-1]).T).T 58 | # create a reference answer of same shape just to simply comparison 59 | ref_answer = np.concatenate((self.store.T.reshape(-1, 1), 60 | self.store.V.reshape(-1, 1), 61 | mole_fractions), axis=1) 62 | compare_mask = [get_comparable( 63 | (np.arange(2, self.store.jac_dim),), ref_answer)] 64 | kc2 = kernel_call('mole_fraction', 65 | [ref_answer], 66 | strict_name_match=True, 67 | compare_mask=compare_mask, 68 | compare_axis=(1,), 69 | chain=__chainer, 70 | **args) 71 | self.__generic_conversion_tester(mass_to_mole_factions, [kc, kc2]) 72 | -------------------------------------------------------------------------------- /pyjac/tests/test_functional_tester.py: -------------------------------------------------------------------------------- 1 | # Python 2 compatibility 2 | from __future__ import print_function 3 | from __future__ import division 4 | 5 | import sys 6 | 7 | from pyjac.functional_tester import partially_stirred_reactor # noqa 8 | from pyjac.functional_tester import test # noqa 9 | 10 | 11 | class TestPartiallyStirredReactor(object): 12 | """ 13 | """ 14 | def test_imported(self): 15 | """Ensure partially_stirred_reactor module imported. 16 | """ 17 | assert 'pyjac.functional_tester.partially_stirred_reactor' in sys.modules 18 | 19 | 20 | class TestTest(object): 21 | """ 22 | """ 23 | def test_imported(self): 24 | """Ensure test module imported. 25 | """ 26 | assert 'pyjac.functional_tester.test' in sys.modules 27 | -------------------------------------------------------------------------------- /pyjac/tests/test_instruction_creator.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from textwrap import dedent 3 | 4 | from pyjac.core import array_creator as arc 5 | from pyjac.core.instruction_creator import get_update_instruction 6 | from pyjac.core.array_creator import MapStore, creator 7 | from pyjac.tests.test_utils import TestingLogger 8 | from pyjac.tests import set_seed 9 | 10 | set_seed() 11 | 12 | 13 | def test_get_update_instruction(): 14 | # test the update instruction creator 15 | 16 | # first, create some domains 17 | map_np = np.arange(12, dtype=arc.kint_type) 18 | map_domain = creator('map', map_np.dtype, map_np.shape, 'C', initializer=map_np) 19 | 20 | # and a dummy loopy options and mapstore 21 | loopy_opts = type('', (object,), { 22 | 'use_working_buffer': False, 'pre_split': False}) 23 | mapstore = MapStore(loopy_opts, map_domain, True) 24 | 25 | # add a new domain 26 | domain_np = np.arange(12, dtype=arc.kint_type) + 2 27 | domain = creator('domain', domain_np.dtype, domain_np.shape, 'C', 28 | initializer=domain_np) 29 | 30 | mapstore.check_and_add_transform(domain, map_domain) 31 | 32 | # test #1, non-finalized mapstore produces warming 33 | # capture logging 34 | tl = TestingLogger() 35 | tl.start_capture(logname='pyjac.core.instruction_creator') 36 | 37 | get_update_instruction(mapstore, map_domain, 'dummy') 38 | 39 | logs = tl.stop_capture() 40 | assert 'non-finalized mapstore' in logs 41 | 42 | # test #2, empty map produces no-op with correct ID 43 | test_instrution = '<> test = domain[i] {id=anchor}' 44 | insn = get_update_instruction(mapstore, None, test_instrution) 45 | assert insn == '... nop {id=anchor}' 46 | 47 | # test #3, non-transformed domain doesn't result in guarded update insn 48 | insn = get_update_instruction(mapstore, domain, test_instrution) 49 | assert insn == test_instrution 50 | 51 | # test #4, transformed domain results in guarded update insn 52 | mapstore = MapStore(loopy_opts, map_domain, True) 53 | domain_np = np.full_like(domain_np, -1) 54 | choice = np.sort(np.random.choice(domain_np.size, domain_np.size - 3, 55 | replace=False)) 56 | domain_np[choice] = np.arange(choice.size) 57 | domain = creator('domain', domain_np.dtype, domain_np.shape, 'C', 58 | initializer=domain_np) 59 | variable = creator('variable', domain_np.dtype, domain_np.shape, 'C') 60 | 61 | mapstore.check_and_add_transform(domain, map_domain) 62 | mapstore.check_and_add_transform(variable, domain) 63 | insn = get_update_instruction(mapstore, variable, test_instrution) 64 | test = dedent(""" 65 | if i_0 >= 0 66 | <> test = domain[i] {id=anchor} 67 | end 68 | """).strip() 69 | assert dedent(insn).strip() == test 70 | -------------------------------------------------------------------------------- /pyjac/tests/test_libgen.py: -------------------------------------------------------------------------------- 1 | # Python 2 compatibility 2 | from __future__ import print_function 3 | from __future__ import division 4 | 5 | import sys 6 | 7 | from pyjac.libgen import libgen # noaq 8 | 9 | 10 | class TestLibgen(object): 11 | """ 12 | """ 13 | def test_imported(self): 14 | """Ensure libgen module imported. 15 | """ 16 | assert 'pyjac.libgen.libgen' in sys.modules 17 | -------------------------------------------------------------------------------- /pyjac/tests/test_mech_interpret.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import tempfile 4 | import difflib 5 | import re 6 | 7 | import cantera as ct 8 | from cantera import __version__ as ct_version 9 | 10 | from pyjac.utils import reassign_species_lists 11 | from pyjac.core.create_jacobian import create_jacobian, find_last_species 12 | from pyjac.core.enum_types import reaction_sorting 13 | from pyjac.core.mech_interpret import read_mech, read_mech_ct 14 | from pyjac.tests.test_utils import xfail, OptionLoopWrapper 15 | from pyjac.tests import script_dir, TestClass, get_mechanism_file 16 | 17 | 18 | ck_file = os.path.join(script_dir, 'test.inp') 19 | cti_file = os.path.join(script_dir, 'test.cti') 20 | 21 | 22 | @xfail(ct_version <= '2.3.0', msg=( 23 | "fail until " 24 | "https://github.com/Cantera/cantera/pull/497 is published in 2.4.0")) 25 | def test_ck_is_cti(): 26 | """ tests that the test.inp mechanism corresponds to the test.cti mechanism""" 27 | with open(cti_file, 'r') as file: 28 | cti = file.readlines() 29 | 30 | # call ck2cti 31 | with tempfile.NamedTemporaryFile(mode='r', suffix='.cti') as file: 32 | # write 33 | subprocess.check_call(['ck2cti', '--input', ck_file, '--output', file.name]) 34 | # read 35 | file.seek(0) 36 | ck = file.readlines() 37 | 38 | # process unicodes 39 | for i in range(len(cti)): 40 | cti[i] = re.sub("u'", "'", cti[i]) 41 | 42 | # check diff 43 | assert not len([x for x in difflib.unified_diff(ck, cti)]) 44 | 45 | 46 | def test_mech_interpret_runs(): 47 | """ test mechanism intpreter for both cantera and chemkin, and that results 48 | match""" 49 | _, specs_ck, reacs_ck = read_mech(ck_file, None) 50 | _, specs_cti, reacs_cti = read_mech_ct(cti_file) 51 | 52 | # reassign 53 | reassign_species_lists(reacs_ck, specs_ck) 54 | reassign_species_lists(reacs_cti, specs_cti) 55 | 56 | assert len(reacs_ck) == len(reacs_cti) 57 | for i in range(len(reacs_ck)): 58 | assert reacs_ck[i] == reacs_cti[i] 59 | assert len(specs_ck) == len(specs_cti) 60 | for i in range(len(specs_ck)): 61 | specs_ck[i] == specs_cti[i] 62 | 63 | 64 | def test_equality_checking(): 65 | """ test species and reaction equality checking""" 66 | _, specs_ck, reacs_ck = read_mech(ck_file, None) 67 | _, specs_cti, reacs_cti = read_mech_ct(cti_file) 68 | 69 | # reassign 70 | reassign_species_lists(reacs_ck, specs_ck) 71 | reassign_species_lists(reacs_cti, specs_cti) 72 | 73 | assert reacs_ck[0] == reacs_cti[0] 74 | for i in range(1, len(reacs_ck)): 75 | assert reacs_ck[0] != reacs_cti[i] 76 | assert specs_ck[0] == specs_cti[0] 77 | for i in range(1, len(specs_ck)): 78 | assert specs_ck[0] != specs_cti[i] 79 | 80 | 81 | def test_mechanism_sorting(): 82 | # perform sort 83 | _, specs_ck, reacs_ck = read_mech(ck_file, None, reaction_sorting.simd) 84 | # ensure we have a good sort 85 | from pyjac.core.enum_types import ( 86 | reaction_type, falloff_form, reversible_type, thd_body_type) 87 | 88 | enum_order = (reaction_type, falloff_form, thd_body_type, reversible_type) 89 | 90 | def check(start=0, end=len(reacs_ck), depth=0): 91 | if depth == len(enum_order): 92 | return 93 | for enum in enum_order[depth]: 94 | this_start = None 95 | this_end = None 96 | # pass #1, find start and end of this enum 97 | for i in range(start, end): 98 | if reacs_ck[i].match(enum) and this_start is None: 99 | this_start = i 100 | continue 101 | if not reacs_ck[i].match(enum) and ( 102 | this_end is None and this_start is not None): 103 | # end of this section 104 | this_end = i - 1 105 | break 106 | elif this_start is not None: 107 | # should all by of this type 108 | assert reacs_ck[i].match(enum) 109 | 110 | if this_start is None: 111 | # no matches, nothing futher to check for this enum 112 | continue 113 | if this_end is None: 114 | # all matches 115 | this_end = end 116 | 117 | check(this_start, this_end, depth+1) 118 | 119 | check() 120 | 121 | 122 | class Tester(TestClass): 123 | def test_heikki_issue(self): 124 | # tests issue raised by heikki via email re: incorrect re-ordering of species 125 | # post call to reassign_species_lists 126 | mech = get_mechanism_file() 127 | gas = ct.Solution(mech) 128 | # read our species for MW's 129 | _, specs, _ = read_mech_ct(gas=gas) 130 | 131 | # find the last species 132 | gas_map = find_last_species(specs, return_map=True) 133 | del specs 134 | # update the gas 135 | specs = gas.species()[:] 136 | gas = ct.Solution(thermo='IdealGas', kinetics='GasKinetics', 137 | species=[specs[x] for x in gas_map], 138 | reactions=gas.reactions()) 139 | del specs 140 | 141 | _, base_specs, base_reacs = read_mech_ct(gas=gas) 142 | # and reassign 143 | reassign_species_lists(base_reacs, base_specs) 144 | 145 | for opts in OptionLoopWrapper.from_get_oploop(self): 146 | reacs, specs = create_jacobian( 147 | opts.lang, 148 | mech_name=mech, 149 | vector_size=opts.vector_width, 150 | width=opts.width, 151 | depth=opts.depth, 152 | last_spec=base_specs[-1].name, 153 | platform=opts.platform_name.lower(), 154 | data_order=opts.order, 155 | explicit_simd=opts.is_simd, 156 | test_mech_interpret_vs_backend=True) 157 | 158 | assert all(r1 == r2 for r1, r2 in zip(*(reacs, base_reacs))) 159 | assert all(s1 == s2 for s1, s2 in zip(*(specs, base_specs))) 160 | -------------------------------------------------------------------------------- /pyjac/tests/test_performance_tester.py: -------------------------------------------------------------------------------- 1 | # Python 2 compatibility 2 | from __future__ import print_function 3 | from __future__ import division 4 | 5 | import sys 6 | 7 | from pyjac.performance_tester import performance_tester # noqa 8 | 9 | 10 | class TestPerformanceTester(object): 11 | """ 12 | """ 13 | def test_imported(self): 14 | """Ensure performance_tester module imported. 15 | """ 16 | assert 'pyjac.performance_tester.performance_tester' in sys.modules 17 | -------------------------------------------------------------------------------- /pyjac/tests/test_pywrap.py: -------------------------------------------------------------------------------- 1 | # Python 2 compatibility 2 | from __future__ import print_function 3 | from __future__ import division 4 | 5 | import sys 6 | 7 | from pyjac.pywrap import pywrap_gen # noqa 8 | 9 | 10 | class TestPywrap_gen(object): 11 | """ 12 | """ 13 | def test_imported(self): 14 | """Ensure pywrap_gen module imported. 15 | """ 16 | assert 'pyjac.pywrap.pywrap_gen' in sys.modules 17 | -------------------------------------------------------------------------------- /pyjac/tests/test_utils/data_bin_writer.py: -------------------------------------------------------------------------------- 1 | import os 2 | from argparse import ArgumentParser 3 | 4 | import numpy as np 5 | 6 | 7 | def get_files(directory): 8 | return [os.path.join(directory, f) for f in os.listdir(directory) 9 | if f.endswith('.npy') and 10 | 'pasr_out' in f 11 | and os.path.isfile(os.path.join(directory, f))] 12 | 13 | 14 | def load(npy_files, directory=None): 15 | if not npy_files and directory is not None: 16 | npy_files = get_files(directory) 17 | data = None 18 | num_conditions = 0 19 | for npy in sorted(npy_files): 20 | state_data = np.load(npy) 21 | if data is None: 22 | data = state_data 23 | else: 24 | data = np.vstack((data, state_data)) 25 | num_conditions += state_data.shape[0] 26 | print(num_conditions, data.shape) 27 | return num_conditions, data 28 | 29 | 30 | def write(directory, cut=None, num_conditions=None, data=None): 31 | if not (num_conditions or data): 32 | npy_files = get_files(directory) 33 | num_conditions, data = load(npy_files) 34 | 35 | filename = 'data.bin' if cut is None else 'data_eqremoved.bin' 36 | with open(os.path.join(directory, filename), 'wb') as file: 37 | # load PaSR data for different pressures/conditions, 38 | # and save to binary C file 39 | if num_conditions == 0: 40 | print('No data found in folder {}, continuing...'.format(directory)) 41 | return 0 42 | if cut is not None: 43 | data = data[cut:, :] 44 | data.tofile(file) 45 | del data 46 | return num_conditions 47 | 48 | 49 | if __name__ == '__main__': 50 | parser = ArgumentParser( 51 | description='data bin writer: Convenience script to generate binary ' 52 | 'files from .npy') 53 | parser.add_argument('-d', '--directory', 54 | type=str, 55 | required=True, 56 | help='The directory containing the .npy files.') 57 | parser.add_argument('-c', '--cut_off_front', 58 | type=int, 59 | default=None, 60 | required=False, 61 | help='The number of conditions to remove from the front ' 62 | 'of the database') 63 | args = parser.parse_args() 64 | write(os.path.realpath(os.path.dirname(args.directory)), 65 | args.cut_off_front) 66 | -------------------------------------------------------------------------------- /pyjac/tests/test_utils/read_ic_setup.py.in: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | 3 | from Cython.Distutils import build_ext 4 | import numpy 5 | 6 | sources = ['${buildpath}/read_ic_wrapper.pyx'] 7 | includes = ['${buildpath}'] 8 | includes = [x for x in includes if x.strip()] 9 | 10 | ext_modules = [Extension("py_readics", 11 | sources=sources, 12 | include_dirs=includes + [numpy.get_include()], 13 | language='c++', 14 | extra_objects=['${obj_dir}/read_initial_conditions.o'] 15 | )] 16 | 17 | setup( 18 | name='py_readics', 19 | ext_modules=ext_modules, 20 | cmdclass={'build_ext': build_ext} 21 | ) 22 | -------------------------------------------------------------------------------- /pyjac/tests/test_utils/read_ic_wrapper.pyx: -------------------------------------------------------------------------------- 1 | import cython 2 | import numpy as np 3 | cimport numpy as np 4 | from cpython cimport bool 5 | 6 | cdef extern from "read_initial_conditions${header_ext}": 7 | void read_initial_conditions (const char *filename, unsigned int NUM, 8 | double *arg1, double *arg2, 9 | const char order); 10 | 11 | cdef char C_ord = 'C' 12 | cdef char F_ord = 'F' 13 | 14 | @cython.boundscheck(False) 15 | @cython.wraparound(False) 16 | def read_ics(const char* filename, 17 | np.uint_t NUM, 18 | np.ndarray[np.float64_t] arg1, 19 | np.ndarray[np.float64_t] arg2, 20 | bool C_order): 21 | read_initial_conditions(filename, NUM, &arg1[0], &arg2[0], 22 | C_ord if C_order else F_ord) 23 | return None 24 | -------------------------------------------------------------------------------- /pyjac/tests/test_utils/ric_tester.py.in: -------------------------------------------------------------------------------- 1 | import importlib 2 | import numpy as np 3 | import sys 4 | import os 5 | import six 6 | 7 | home_dir = os.path.dirname(__file__) 8 | read_ics = importlib.import_module('py_readics') 9 | data = six.u(os.path.join(home_dir, 'data.bin')).encode('UTF-8') 10 | 11 | 12 | phi_test = np.fromfile(os.path.join(home_dir, 'phi_test.npy')) 13 | """[[[cog 14 | from pyjac.core.array_creator import pressure_array, volume_array 15 | conp = True if conp == 'True' else False 16 | param_name = pressure_array if conp else volume_array 17 | cog.outl("{} = np.fromfile(os.path.join(home_dir, 'param_test.npy'))".format( 18 | param_name + '_test')) 19 | ]]] 20 | [[[end]]]""" 21 | 22 | order = str(sys.argv[1]) 23 | num = int(sys.argv[2]) 24 | assert order in ['C', 'F'] 25 | 26 | """[[[cog 27 | cog.outl("{0} = np.zeros_like({0}_test)".format(param_name)) 28 | ]]] 29 | [[[end]]]""" 30 | phi = np.zeros_like(phi_test) 31 | args = [data, num] 32 | """[[[cog 33 | from pyjac.utils import kernel_argument_ordering, stringify_args 34 | from pyjac.core.enum_types import KernelType 35 | 36 | args = kernel_argument_ordering(['phi', param_name], KernelType.species_rates) 37 | cog.outl('args += [{}]'.format(stringify_args(args))) 38 | ]]] 39 | [[[end]]]""" 40 | 41 | args += [order == 'C'] 42 | 43 | read_ics.read_ics(*args) 44 | 45 | # check extra variable 46 | """[[[cog 47 | cog.outl("allclear = np.allclose({0}, {0}_test)".format(param_name)) 48 | ]]] 49 | [[[end]]]""" 50 | 51 | # and check 52 | allclear = allclear and np.allclose(phi, phi_test) 53 | 54 | sys.exit(not allclear) 55 | -------------------------------------------------------------------------------- /pyjac/tests/test_utils/test_import.py.in: -------------------------------------------------------------------------------- 1 | """ 2 | Once we create a python module using the wrapper it becomes difficult to 3 | manage reloading the module if recreated frequently during testing. 4 | 5 | Hence we create this small testing stub that is designed to test importing the module 6 | """ 7 | 8 | import importlib 9 | import os 10 | 11 | if __name__ == '__main__': 12 | # find path 13 | path = os.path.abspath('${path}') 14 | # change to 15 | os.chdir(path) 16 | # load package 17 | package = '${package}' 18 | package = importlib.import_module(package) 19 | 20 | kernel = package.Py${kernel}Kernel(1, 1, testing_only_skip_compilation=True) 21 | assert len(kernel.species_names()) == ${nsp} 22 | assert len(kernel.reaction_strings()) == ${nrxn} 23 | # this is misleading, but since we skip compilation the work-size is never set 24 | # hence, we expect a 0 required working memory (but include this test here to 25 | # make sure we can access the method) 26 | kernel.required_working_memory() 27 | assert kernel.num_species() == ${nsp} 28 | assert kernel.num_reactions() == ${nrxn} 29 | -------------------------------------------------------------------------------- /pyjac/tests/test_utils/test_run.py.in: -------------------------------------------------------------------------------- 1 | """ 2 | Once we create a python module using the wrapper it becomes difficult to 3 | manage reloading the module if recreated frequently during testing. 4 | 5 | Hence we create this small testing stub that is designed to read in 6 | the inputs and outouts to test, and exit with the result 7 | 8 | This function is designed to be called as subprocess 9 | """ 10 | 11 | import numpy as np 12 | import importlib 13 | import sys 14 | import warnings 15 | 16 | if __name__ == '__main__': 17 | # load package 18 | package = '${package}' 19 | package = importlib.import_module(package) 20 | 21 | # load input data 22 | input_args = [${input_args}] 23 | # load from filenames 24 | for i in range(len(input_args)): 25 | input_args[i] = np.load(input_args[i]) 26 | 27 | # load test arrays 28 | test_arrays = [${test_arrays}] 29 | # load from filenames 30 | for i in range(len(test_arrays)): 31 | test_arrays[i] = np.load(test_arrays[i]) 32 | 33 | # create output args in same shape as test arrays 34 | output_args = [np.zeros_like(x) for x in test_arrays] 35 | 36 | # get non-arrays 37 | non_array_args = [${non_array_args}] 38 | if len(sys.argv) > 1: 39 | # get compile arg 40 | force_no_compile = int(sys.argv[1]) 41 | non_array_args += [force_no_compile] 42 | 43 | # put all args together 44 | args = input_args + output_args 45 | 46 | # create the kernel 47 | kernel = package.Py${kernel_name}Kernel(*non_array_args) 48 | 49 | # finally call 50 | args = input_args + output_args 51 | kernel(*args) 52 | 53 | output_files = [${output_files}] 54 | if output_files: 55 | assert len(output_files) == len(output_args) 56 | 57 | # for cases where the moles of the last species is set to zero in the test 58 | # condition initializer, this may not be the exact case here due to floating 59 | # point accuracy concerns, hence we provide a way to specify output indicies 60 | # that require looser tolerances for proper comparison 61 | looser_tols = [${looser_tols}] 62 | 63 | # if save err to file, 64 | if output_files: 65 | for i in range(len(output_args)): 66 | np.save(output_files[i], output_args[i]) 67 | else: 68 | # check allclose 69 | for i in range(len(output_args)): 70 | if not np.allclose(output_args[i], test_arrays[i], atol=${atol}, 71 | rtol=${rtol}): 72 | if looser_tols and looser_tols[i]: 73 | # first check that all the misses are in looser_tols 74 | lt = looser_tols[i] 75 | 76 | # find misses 77 | misses = np.where(np.logical_not(np.isclose( 78 | output_args[i], test_arrays[i], atol=${atol}, 79 | rtol=${rtol})))[0] 80 | 81 | if not np.all(np.in1d(misses, lt)): 82 | # log the missed values for debugging purposes 83 | warnings.warn('Missed indicies: {}'.format( 84 | ', '.join(str(x) for x in misses[np.where( 85 | np.logical_not(np.in1d(misses, lt)))]))) 86 | sys.exit(1) 87 | 88 | # check for nan's 89 | check = np.where(np.isfinite(test_arrays[i][misses])) 90 | 91 | # next check for match at looser tols 92 | if np.allclose(output_args[i][misses][check], 93 | test_arrays[i][misses][check], 94 | rtol=${loose_rtol}, atol=${loose_atol}): 95 | continue 96 | 97 | # log the missed values for debugging purposes 98 | missed_checks = np.where(np.logical_not(np.isclose( 99 | output_args[i][misses][check], 100 | test_arrays[i][misses][check], 101 | rtol=${loose_rtol}, atol=${loose_atol}))) 102 | misses = misses[check][missed_checks] 103 | warnings.warn( 104 | 'Out of tolerance for indicies:\n({})\n' 105 | 'error:\n({})'.format( 106 | ', '.join(str(x) for x in misses), 107 | ', '.join(str(x) for x in np.abs(( 108 | output_args[i][misses] - test_arrays[i][misses] 109 | ) / test_arrays[i][misses])))) 110 | # if not a match, exit 111 | sys.exit(2) 112 | 113 | # success 114 | sys.exit(0) 115 | -------------------------------------------------------------------------------- /pyjac/tests/test_version.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test for _version.py 3 | """ 4 | # Standard libraries 5 | import pkg_resources 6 | 7 | # Local imports 8 | from pyjac._version import __version__ 9 | 10 | 11 | def test_semantic_version(): 12 | pkg_resources.parse_version(__version__) 13 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | -e git+git://github.com/arghdos/loopy@working2#egg=loopy 3 | enum34 >= 1.1.6;python_version<'3.4' 4 | six 5 | pyyaml 6 | cgen 7 | cogapp 8 | Cython 9 | Cerberus > 1.1 10 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | # This flag says that the code is written to work on both Python 2 and Python 3 | # 3. If at all possible, it is good practice to do this. If you cannot, you 4 | # will need to generate wheels for each Python version that you support. 5 | universal=1 6 | 7 | [files] 8 | packages = 9 | pyjac 10 | pyjac.core 11 | pyjac.functional_tester 12 | pyjac.performance_tester 13 | pyjac.pywrap 14 | pyjac.libgen 15 | pyjac.kernel_utils 16 | pyjac.tests 17 | pyjac.examples 18 | pyjac.schemas 19 | 20 | extra_files = 21 | setup.py 22 | README.md 23 | LICENSE 24 | CITATION.md 25 | CHANGELOG.md 26 | CONTRIBUTING.md 27 | citation.jsonld 28 | nose.cfg 29 | requirements.txt 30 | optional-requirements.txt 31 | 32 | [flake8] 33 | max-line-length=85 34 | 35 | [pep8] 36 | max-line-length=85 37 | 38 | [nosetests] 39 | verbosity=3 40 | exclude-dir=pyjac/tests/test_utils/ 41 | pyjac/tests/lib/ 42 | pyjac/functional_tester/ 43 | pyjac/performance_tester/ 44 | logging-filter=pyjac 45 | tc-file=test_setup.py 46 | tc-format=python 47 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """A setuptools based setup module. 2 | See: 3 | https://packaging.python.org/en/latest/distributing.html 4 | https://github.com/pypa/sampleproject 5 | """ 6 | 7 | from setuptools import setup, find_packages 8 | from codecs import open 9 | from os import path 10 | from setup_helper import get_config, ConfigSchema, get_config_schema 11 | 12 | here = path.abspath(path.dirname(__file__)) 13 | 14 | with open(path.join(here, 'pyjac', '_version.py')) as version_file: 15 | exec(version_file.read()) 16 | 17 | # Get the long description from the relevant files 18 | with open(path.join(here, 'README.md')) as readme_file: 19 | readme = readme_file.read() 20 | 21 | with open(path.join(here, 'CHANGELOG.md')) as changelog_file: 22 | changelog = changelog_file.read() 23 | 24 | with open(path.join(here, 'CITATION.md')) as citation_file: 25 | citation = citation_file.read() 26 | 27 | desc = readme + '\n\n' + changelog + '\n\n' + citation 28 | try: 29 | import pypandoc 30 | long_description = pypandoc.convert_text(desc, 'rst', format='md') 31 | with open(path.join(here, 'README.rst'), 'w') as rst_readme: 32 | rst_readme.write(long_description) 33 | except (ImportError, OSError, IOError): 34 | long_description = desc 35 | 36 | # get user's siteconf.py from CMD/file, and write to pyjac's siteconf.py 37 | schema = get_config_schema() 38 | conf = get_config(schema, warn_about_no_config=False) 39 | schema.set_conf_dir(path.join(here, 'pyjac')) 40 | schema.write_config(conf) 41 | 42 | setup( 43 | name='pyJac', 44 | description=('Create analytical Jacobian matrix source code for chemical ' 45 | 'kinetics'), 46 | long_description=long_description, 47 | 48 | # The project's main homepage. 49 | url='https://github.com/SLACKHA/pyJac', 50 | 51 | # Author details 52 | author='Nick Curtis, Kyle E. Niemeyer', 53 | author_email='nicholas.curtis@uconn.edu, kyle.niemeyer@gmail.com', 54 | 55 | # Choose your license 56 | license='MIT License', 57 | 58 | # version 59 | version=__version__, 60 | 61 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 62 | classifiers=[ 63 | 'Development Status :: 5 - Production/Stable', 64 | 'Intended Audience :: Developers', 65 | 'Intended Audience :: Science/Research', 66 | 'License :: OSI Approved :: MIT License', 67 | 'Natural Language :: English', 68 | 'Operating System :: OS Independent', 69 | 'Programming Language :: Python :: 3', 70 | 'Programming Language :: Python :: 3.4', 71 | 'Programming Language :: Python :: 3.5', 72 | 'Programming Language :: Python :: 3.6', 73 | 'Topic :: Scientific/Engineering', 74 | 'Topic :: Scientific/Engineering :: Physics', 75 | 'Topic :: Software Development :: Libraries :: Python Modules', 76 | ], 77 | keywords='chemical_kinetics analytical_Jacobian', 78 | 79 | # You can just specify the packages manually here if your project is 80 | # simple. Or you can use find_packages(). 81 | packages=find_packages(exclude=['docs']), 82 | 83 | # List run-time dependencies here. These will be installed by pip when 84 | # your project is installed. For an analysis of "install_requires" vs pip's 85 | # requirements files see: 86 | # https://packaging.python.org/en/latest/requirements.html 87 | # install_requires=['peppercorn'], 88 | install_requires=[ 89 | 'numpy', 90 | 'loo.py>=2018.1', 91 | 'six', 92 | 'pyyaml', 93 | 'cgen', 94 | 'cogapp', 95 | 'cerberus>1.1', 96 | 'Cython', 97 | 'enum34;python_version<"3.4"'], 98 | 99 | tests_require=[ 100 | 'nose', 101 | 'nose-exclude', 102 | 'nose-testconfig', 103 | 'nose-timer', 104 | 'parameterized', 105 | 'optionloop >= 1.0.7', 106 | 'cantera >= 2.3.0', 107 | 'scipy', 108 | 'tables', 109 | 'psutil', 110 | 'pyopencl'], 111 | 112 | # use nose for tests 113 | test_suite='nose.collector', 114 | 115 | # List additional groups of dependencies here (e.g. development 116 | # dependencies). You can install these using the following syntax, 117 | # for example: 118 | # $ pip install -e .[dev,test] 119 | # extras_require={ 120 | # 'dev': ['check-manifest'], 121 | # 'test': ['coverage'], 122 | # }, 123 | 124 | # If there are data files included in your packages that need to be 125 | # installed, specify them here. If using Python 2.6 or less, then these 126 | # have to be included in MANIFEST.in as well. 127 | package_data={ 128 | 'pyjac': ['*.yaml'], 129 | 'pyjac.pywrap': ['*.in'], 130 | 'pyjac.functional_tester': ['*.yaml'], 131 | 'pyjac.kernel_utils.c': ['*.cpp', '*.hpp', '*.in'], 132 | 'pyjac.kernel_utils.common': ['*.cpp', '*.hpp', '*.in'], 133 | 'pyjac.kernel_utils.opencl': ['*.ocl', '*.oclh', '*.in'], 134 | 'pyjac.loopy_utils': ['*.in'], 135 | 'pyjac.tests': ['*.cti', '*.inp'], 136 | 'pyjac.tests.test_utils': ['*.in', '*.pyx'], 137 | 'pyjac.examples': ['*.yaml'], 138 | 'pyjac.schemas': ['*.yaml'] 139 | }, 140 | include_package_data=True, 141 | zip_safe=False, 142 | 143 | entry_points={ 144 | 'console_scripts': [ 145 | 'pyjac=pyjac.__main__:main', 146 | ], 147 | }, 148 | ) 149 | -------------------------------------------------------------------------------- /test-environment.yaml: -------------------------------------------------------------------------------- 1 | name: test-environment 2 | channels: 3 | - defaults 4 | - conda-forge 5 | - slackha 6 | - cantera 7 | dependencies: 8 | - numpy=1.12.0 9 | - bitarray>=0.8.1 10 | - cython>=0.23.1 11 | - pyyaml>=3.11 12 | - python=${PYTHON} 13 | - optionloop>1.0.3 14 | - cantera>=2.3.0 15 | - pytest>=3.0.1 16 | -------------------------------------------------------------------------------- /test_setup.py: -------------------------------------------------------------------------------- 1 | # Configuration file for nose-testconfig that sets: 2 | # a) the test platforms file 3 | # b) the chemical mechanism to test 4 | # c) the maximum number of threads to test 5 | # d) the relative / absolute tolerances 6 | # e) the languages to test 7 | # f) the reaction sorting method to use 8 | # All test configuration variables can be specified on the command line via 9 | # ENV variables (prefixed with PYJAC_) if desired 10 | # e.g. PYJAC_GAS=mymech.cti PYJAC_TEST_PLATFORM=my_platform.yaml nosetests ... 11 | # or simply feel free to modify the below... 12 | # NOTE: supplied enviroment variables with override variables set in this test config 13 | 14 | import os 15 | home = os.getcwd() 16 | global config 17 | config = {} 18 | PLATFORM = 'test_platform.yaml' 19 | gas = os.path.join(home, 'pyjac', 'tests', 'test.cti') 20 | config['test_platform'] = os.path.join(home, PLATFORM) 21 | config['gas'] = gas 22 | # set test languages to opencl & c 23 | config['test_langs'] = 'opencl,c' 24 | # unused by default, sets maximum # of hardware threads for testing 25 | # config['max_threads'] = None 26 | # unused by default, but allows the user to specify relative tolerance for unit tests 27 | # note that the default tolerances should work for the test mechanism, but you may 28 | # need to adjust for other (real) mechanisms 29 | # config['rtol'] = 1e-3 30 | # unused by default, but allows the user to specify absolute tolerance for unit tests 31 | # note that the default tolerances should work for the test mechanism, but you may 32 | # need to adjust for other (real) mechanisms 33 | # config['atol'] = 1 34 | # Set the number of initial conditions for pyJac testing 35 | # config['test_size'] = 8192 36 | # Set the type of reaction sorting to utilize 37 | # config['rxn_sort'] = 'simd' 38 | --------------------------------------------------------------------------------