diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 000000000..8aa325aeb --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 52a1a8931d90dc93a37c39dd55a434f0 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.github/problem-matchers/gcc.json b/.github/problem-matchers/gcc.json new file mode 100644 index 000000000..9ab06796a --- /dev/null +++ b/.github/problem-matchers/gcc.json @@ -0,0 +1,18 @@ +{ + "__comment": "Taken from vscode-cpptools's Extension/package.json gcc rule", + "problemMatcher": [ + { + "owner": "gcc-problem-matcher", + "pattern": [ + { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + ] + } + ] +} diff --git a/.github/problem-matchers/sphinx.json b/.github/problem-matchers/sphinx.json new file mode 100644 index 000000000..6fcd3884e --- /dev/null +++ b/.github/problem-matchers/sphinx.json @@ -0,0 +1,40 @@ +{ + "problemMatcher": [ + { + "owner": "sphinx-problem-matcher", + "pattern": [ + { + "regexp": "^(.*):(\\d+):\\s+(\\w*):\\s+(.*)$", + "file": 1, + "line": 2, + "severity": 3, + "message": 4 + } + ] + }, + { + "owner": "sphinx-problem-matcher-loose", + "pattern": [ + { + "_comment": "A bit of a looser pattern, doesn't look for line numbers, just looks for file names relying on them to start with / and end with .rst", + "regexp": "(\/.*\\.rst):\\s+(\\w*):\\s+(.*)$", + "file": 1, + "severity": 2, + "message": 3 + } + ] + }, + { + "owner": "sphinx-problem-matcher-loose-no-severity", + "pattern": [ + { + "_comment": "Looks for file names ending with .rst and line numbers but without severity", + "regexp": "^(.*\\.rst):(\\d+):(.*)$", + "file": 1, + "line": 2, + "message": 3 + } + ] + } + ] +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..9f63e5d97 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,189 @@ +name: PelePhysics +on: + push: + branches: [development] + pull_request: + branches: [development] + +jobs: + Formatting: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: DoozyX/clang-format-lint-action@v0.13 + with: + source: './Eos ./Transport ./Reactions ./Source ./Utility ./Testing ./Support/Fuego/Mechanism/Models' + exclude: '.' + extensions: 'H,h,cpp' + clangFormatVersion: 13 + + Pythia: + needs: Formatting + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: [3.8] + poetry-version: [1.1.7] + defaults: + run: + working-directory: ${{github.workspace}}/Support/Fuego/Pythia + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: ${{matrix.python-version}} + - name: Run image + uses: abatilo/actions-poetry@v2.0.0 + with: + poetry-version: ${{matrix.poetry-version}} + - name: Install Dependencies using Poetry + run: poetry install + - name: Formatting with black + run: poetry run black --check . + - name: Sort imports with isort + run: poetry run isort --check-only --diff . + - name: Run tests + run: poetry run bash -c "cd ../Mechanism/Models/air && ./make-mechanism.sh" + + Transport-EOS-Reactions: + needs: Formatting + runs-on: ubuntu-latest + strategy: + matrix: + comp: [gnu, llvm, cuda, hip, dpcpp] + include: + - comp: gnu + amrex_build_args: 'COMP=gnu' + dependency_cmds: + - comp: llvm + amrex_build_args: 'COMP=llvm' + dependency_cmds: + - comp: cuda + amrex_build_args: 'COMP=gnu USE_CUDA=TRUE' + dependency_cmds: '.github/workflows/dependencies/dependencies_cuda.sh' + - comp: hip + amrex_build_args: 'USE_HIP=TRUE AMD_ARCH=gfx908 LIBRARY_LOCATIONS=/opt/rocm/lib' + dependency_cmds: '.github/workflows/dependencies/dependencies_hip.sh' + - comp: dpcpp + amrex_build_args: 'USE_DPCPP=TRUE' + dependency_cmds: '.github/workflows/dependencies/dependencies_dpcpp.sh' + steps: + - name: Cancel previous runs + uses: styfle/cancel-workflow-action@0.6.0 + with: + access_token: ${{github.token}} + - name: Checkout PelePhysics + uses: actions/checkout@v2 + with: + path: PelePhysics-${{matrix.comp}} + - name: Checkout AMReX + uses: actions/checkout@v2 + with: + repository: AMReX-Codes/amrex + path: AMReX-${{matrix.comp}} + - name: Set Environment Variables + run: | + echo "AMREX_HOME=${{github.workspace}}/AMReX-${{matrix.comp}}" >> $GITHUB_ENV + echo "PELE_PHYSICS_HOME=${{github.workspace}}/PelePhysics-${{matrix.comp}}" >> $GITHUB_ENV + echo "TRANSPORT_WORKING_DIRECTORY=${{github.workspace}}/PelePhysics-${{matrix.comp}}/Testing/Exec/TranEval" >> $GITHUB_ENV + echo "EOS_WORKING_DIRECTORY=${{github.workspace}}/PelePhysics-${{matrix.comp}}/Testing/Exec/EosEval" >> $GITHUB_ENV + echo "REACT_WORKING_DIRECTORY=${{github.workspace}}/PelePhysics-${{matrix.comp}}/Testing/Exec/ReactEval" >> $GITHUB_ENV + echo "IGNDELAY_WORKING_DIRECTORY=${{github.workspace}}/PelePhysics-${{matrix.comp}}/Testing/Exec/IgnitionDelay" >> $GITHUB_ENV + echo "NPROCS=$(nproc)" >> $GITHUB_ENV + if [ "${{matrix.comp}}" == 'cuda' ]; then \ + echo "CUDA_HOME=/usr/local/cuda-11.2" >> $GITHUB_ENV; \ + echo "LD_LIBRARY_PATH=/usr/local/cuda-11.2/lib64:${LD_LIBRARY_PATH}" >> $GITHUB_ENV; \ + echo "/usr/local/cuda-11.2/bin" >> $GITHUB_PATH; \ + fi + - name: Dependencies + working-directory: ${{env.TRANSPORT_WORKING_DIRECTORY}} + run: | + if [ "${{matrix.comp}}" == 'cuda' ]; then \ + ${{github.workspace}}/PelePhysics-${{matrix.comp}}/${{matrix.dependency_cmds}}; \ + echo "CUDA_HOME=${CUDA_HOME}"; \ + ls ${CUDA_HOME} > /dev/null; \ + which nvcc || echo "nvcc not in PATH!"; \ + fi + if [ "${{matrix.comp}}" == 'hip' ]; then \ + ${{github.workspace}}/PelePhysics-${{matrix.comp}}/${{matrix.dependency_cmds}}; \ + source /etc/profile.d/rocm.sh + which hipcc || echo "hipcc not in PATH!"; \ + fi + if [ "${{matrix.comp}}" == 'dpcpp' ]; then \ + ${{github.workspace}}/PelePhysics-${{matrix.comp}}/${{matrix.dependency_cmds}}; \ + source /opt/intel/oneapi/setvars.sh || true + which dpcpp || echo "dpcpp not in PATH!"; \ + fi + cmake --version + make TPL ${{matrix.amrex_build_args}}; + - name: Test Transport + working-directory: ${{env.TRANSPORT_WORKING_DIRECTORY}} + run: | + echo "::add-matcher::${{github.workspace}}/PelePhysics-${{matrix.comp}}/.github/problem-matchers/gcc.json" + if [ "${{matrix.comp}}" == 'hip' ]; then source /etc/profile.d/rocm.sh; fi; + if [ "${{matrix.comp}}" == 'dpcpp' ]; then source /opt/intel/oneapi/setvars.sh || true; fi; + for TYPE in Constant Simple Sutherland; do \ + printf "\n-------- ${TYPE} --------\n"; \ + make -j ${{env.NPROCS}} Transport_Model=${TYPE} TINY_PROFILE=TRUE ${{matrix.amrex_build_args}}; \ + if [ "${{matrix.comp}}" == 'gnu' ] || [ "${{matrix.comp}}" == 'llvm' ]; then \ + ./Pele2d.${{matrix.comp}}.TPROF.ex inputs.2d_${TYPE}; \ + fi; \ + make realclean; \ + if [ $? -ne 0 ]; then exit 1; fi; \ + done + - name: Test EOS + working-directory: ${{env.EOS_WORKING_DIRECTORY}} + run: | + echo "::add-matcher::${{github.workspace}}/PelePhysics-${{matrix.comp}}/.github/problem-matchers/gcc.json" + if [ "${{matrix.comp}}" == 'hip' ]; then source /etc/profile.d/rocm.sh; fi; + if [ "${{matrix.comp}}" == 'dpcpp' ]; then source /opt/intel/oneapi/setvars.sh || true; fi; + for TYPE in Fuego GammaLaw; do \ + if [ "${TYPE}" == 'Fuego' ]; then CHEMISTRY=LiDryer; else CHEMISTRY=Null; fi; \ + printf "\n-------- ${TYPE} --------\n"; \ + make -j ${{env.NPROCS}} Eos_Model=${TYPE} Chemistry_Model=${CHEMISTRY} TINY_PROFILE=TRUE ${{matrix.amrex_build_args}}; \ + if [ "${{matrix.comp}}" == 'gnu' ] || [ "${{matrix.comp}}" == 'llvm' ]; then \ + ./Pele2d.${{matrix.comp}}.TPROF.ex inputs.2d; \ + fi; \ + make realclean; \ + if [ $? -ne 0 ]; then exit 1; fi; \ + done + - name: Test Reactions + working-directory: ${{env.REACT_WORKING_DIRECTORY}} + run: | + echo "::add-matcher::${{github.workspace}}/PelePhysics-${{matrix.comp}}/.github/problem-matchers/gcc.json" + if [ "${{matrix.comp}}" == 'hip' ]; then source /etc/profile.d/rocm.sh; fi; + if [ "${{matrix.comp}}" == 'dpcpp' ]; then source /opt/intel/oneapi/setvars.sh || true; fi; + make -j ${{env.NPROCS}} Eos_Model=Fuego Chemistry_Model=drm19 TINY_PROFILE=TRUE ${{matrix.amrex_build_args}} + if [ "${{matrix.comp}}" == 'gnu' ] || [ "${{matrix.comp}}" == 'llvm' ]; then \ + for TYPE in Cvode Arkode RK64; do \ + printf "\n-------- ${TYPE} --------\n"; \ + ./Pele3d.${{matrix.comp}}.TPROF.ex inputs.3d_Array4 ode.dt=1.e-05 ode.ndt=100 chem_integrator="Reactor${TYPE}"; \ + ./Pele3d.${{matrix.comp}}.TPROF.ex inputs.3d_1dArray ode.dt=1.e-05 ode.ndt=100 chem_integrator="Reactor${TYPE}"; \ + if [ $? -ne 0 ]; then exit 1; fi; \ + done \ + fi; + make realclean + make -j ${{env.NPROCS}} Eos_Model=Fuego Chemistry_Model=LiDryer TINY_PROFILE=TRUE ${{matrix.amrex_build_args}} + if [ "${{matrix.comp}}" == 'gnu' ] || [ "${{matrix.comp}}" == 'llvm' ]; then \ + for TYPE in Cvode Arkode RK64; do \ + printf "\n-------- ${TYPE} --------\n"; \ + ./Pele3d.${{matrix.comp}}.TPROF.ex inputs.3d_Array4 ode.dt=1.e-05 ode.ndt=100 chem_integrator="Reactor${TYPE}"; \ + ./Pele3d.${{matrix.comp}}.TPROF.ex inputs.3d_1dArray ode.dt=1.e-05 ode.ndt=100 chem_integrator="Reactor${TYPE}"; \ + if [ $? -ne 0 ]; then exit 1; fi; \ + done \ + fi + make realclean + - name: Test Ignition delay + working-directory: ${{env.IGNDELAY_WORKING_DIRECTORY}} + run: | + echo "::add-matcher::${{github.workspace}}/PelePhysics-${{matrix.comp}}/.github/problem-matchers/gcc.json" + if [ "${{matrix.comp}}" == 'gnu' ] || [ "${{matrix.comp}}" == 'llvm' ]; then \ + python -m pip install --upgrade pip + pip install numpy + make -j ${{env.NPROCS}} Eos_Model=Fuego Chemistry_Model=dodecane_lu TINY_PROFILE=TRUE ${{matrix.amrex_build_args}} + bash exec_ignDelay.sh + python check_ignDelay.py + if [ $? -ne 0 ]; then exit 1; fi; \ + fi; + make realclean diff --git a/.github/workflows/dependencies/dependencies_cuda.sh b/.github/workflows/dependencies/dependencies_cuda.sh new file mode 100755 index 000000000..02b598117 --- /dev/null +++ b/.github/workflows/dependencies/dependencies_cuda.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# +# Copyright 2020 Axel Huebl +# +# License: BSD-3-Clause-LBNL + +# search recursive inside a folder if a file contains tabs +# +# @result 0 if no files are found, else 1 +# + +set -eu -o pipefail + +CUDA_VERSION=11-2 + +sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/3bf863cc.pub +echo "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64 /" \ + | sudo tee /etc/apt/sources.list.d/cuda.list +sudo apt-get update +sudo apt-get install -y \ + cuda-command-line-tools-${CUDA_VERSION} \ + cuda-compiler-${CUDA_VERSION} \ + cuda-cupti-dev-${CUDA_VERSION} \ + cuda-minimal-build-${CUDA_VERSION} \ + cuda-nvml-dev-${CUDA_VERSION} \ + cuda-nvtx-${CUDA_VERSION} \ + libcurand-dev-${CUDA_VERSION} \ + libcusolver-dev-${CUDA_VERSION} \ + libcusparse-dev-${CUDA_VERSION} \ + libcublas-dev-${CUDA_VERSION} \ + libcurand-dev-${CUDA_VERSION} + +export PATH=/usr/local/cuda-11.2/bin:${PATH} +which nvcc +nvcc --version diff --git a/.github/workflows/dependencies/dependencies_dpcpp.sh b/.github/workflows/dependencies/dependencies_dpcpp.sh new file mode 100755 index 000000000..f3f2c3c35 --- /dev/null +++ b/.github/workflows/dependencies/dependencies_dpcpp.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# +# Copyright 2020 The AMReX Community +# +# License: BSD-3-Clause-LBNL +# Authors: Axel Huebl + +set -eu -o pipefail + +sudo wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB +sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2023.PUB +echo "deb https://apt.repos.intel.com/oneapi all main" \ + | sudo tee /etc/apt/sources.list.d/oneAPI.list + +sudo apt-get update +sudo apt-get install -y \ + intel-oneapi-dpcpp-cpp-compiler \ + intel-oneapi-mkl-devel diff --git a/.github/workflows/dependencies/dependencies_hip.sh b/.github/workflows/dependencies/dependencies_hip.sh new file mode 100755 index 000000000..62b3640c9 --- /dev/null +++ b/.github/workflows/dependencies/dependencies_hip.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# +# Copyright 2020 The AMReX Community +# +# License: BSD-3-Clause-LBNL +# Authors: Axel Huebl + +# search recursive inside a folder if a file contains tabs +# +# @result 0 if no files are found, else 1 +# + +set -eu -o pipefail + +sudo wget http://repo.radeon.com/rocm/rocm.gpg.key +sudo apt-key add rocm.gpg.key +echo 'deb [arch=amd64] http://repo.radeon.com/rocm/apt/debian/ ubuntu main' \ + | sudo tee /etc/apt/sources.list.d/rocm.list +echo 'export PATH=/opt/rocm/llvm/bin:/opt/rocm/bin:/opt/rocm/profiler/bin:/opt/rocm/opencl/bin:$PATH' \ + | sudo tee -a /etc/profile.d/rocm.sh + +sudo apt-get update +sudo apt-get install -y \ + rocm-dev \ + roctracer-dev \ + rocprofiler-dev \ + rocrand-dev \ + rocprim-dev \ + rocm-libs + +source /etc/profile.d/rocm.sh +which hipcc +which clang +which clang++ +which flang +hipcc --version diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..f63c7720a --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,48 @@ +name: PelePhysics-Docs + +on: + push: + branches: [development] + paths: + - 'Docs/**' + - 'README.md' + - '.github/workflows/docs.yml' + pull_request: + branches: [development] + paths: + - 'Docs/**' + - 'README.md' + - '.github/workflows/docs.yml' + +jobs: + Docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Python + uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Dependencies + run: | + python -m pip install --upgrade pip + pip install sphinx sphinx_rtd_theme + - name: Configure + run: cmake -B${{runner.workspace}}/build-docs ${{github.workspace}}/Docs + - name: Build + working-directory: ${{runner.workspace}}/build-docs + run: | + echo "::add-matcher::.github/problem-matchers/sphinx.json" + cmake --build ${{runner.workspace}}/build-docs + echo "::remove-matcher owner=sphinx-problem-matcher-loose-no-severity::" + echo "::remove-matcher owner=sphinx-problem-matcher-loose::" + echo "::remove-matcher owner=sphinx-problem-matcher::" + touch ${{runner.workspace}}/build-docs/sphinx/html/.nojekyll + - name: Deploy + if: github.event_name == 'push' && github.ref == 'refs/heads/development' + uses: JamesIves/github-pages-deploy-action@releases/v3 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH: gh-pages + FOLDER: ${{runner.workspace}}/build-docs/sphinx/html + SINGLE_COMMIT: true diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/Ceptr.html b/Ceptr.html new file mode 100644 index 000000000..005a62c00 --- /dev/null +++ b/Ceptr.html @@ -0,0 +1,241 @@ + + + + + + + CEPTR: Chemistry Evaluation for Pele Through Recasting — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CEPTR: Chemistry Evaluation for Pele Through Recasting

+

We use CEPTR to generate C++ mechanism files from Cantera yaml chemistry files. CEPTR is a python package part of the PelePhysics source code.

+
+

Software requirements

+

The CEPTR package uses poetry to manage the Python dependencies. Poetry is therefore required to use CEPTR and can typically be installed through system package managers (e.g. HomeBrew) or following the instructions in poetry’s documentation.

+

To install CEPTR dependencies:

+
$ cd ${PELE_PHYSICS_HOME}/Support/ceptr
+$ poetry update
+
+
+
+
+

Usage

+
+

Generating for a single chemistry

+

There are three ways to use CEPTR to generate C++ mechanism files for a given chemistry

+
    +
  1. Using CEPTR directly:

    +
    $ cd ${PELE_PHYSICS_HOME}/Support/ceptr
    +$ poetry run convert -f ${PELE_PHYSICS_HOME}/Mechanisms/LiDryer/mechanism.yaml
    +
    +
    +
  2. +
  3. Using a helper script in the directory containing the mechanism.yaml file:

    +
    $ ./convert.sh
    +
    +
    +
  4. +
  5. Using a helper script in the Models directory:

    +
    $ bash ${PELE_PHYSICS_HOME}/Mechanisms/converter.sh -f ./LiDryer/mechanism.yaml
    +
    +
    +
  6. +
+
+
+

Batched generation

+
+

Note

+

If you are using batched generation as outlined here, it will automatically use multiprocessing to generate the files in parallel using all CPUs detected on the machine. If you want to change that you can pass the optional argument -n NPCU, wheren NCPU is an integer indicating the number of processes you want to use.

+
+

For non-reduced chemistries, CEPTR can take a file with a list of mechanism.yaml files to convert:

+
$ cd ${PELE_PHYSICS_HOME}/Support/ceptr
+$ poetry run convert -l ${PELE_PHYSICS_HOME}/Mechanisms/list_mech
+
+
+

For reduced chemistries, CEPTR can take a file with a list of qssa.yaml and qssa_input.toml to convert:

+
$ cd ${PELE_PHYSICS_HOME}/Support/ceptr
+$ poetry run convert -lq ${PELE_PHYSICS_HOME}/Mechanisms/list_qss_mech
+
+
+

For generating qssa.yaml for reduced chemistries, CEPTR can take a file with a list of skeletal.yaml and non_qssa_list.yaml:

+
$ cd ${PELE_PHYSICS_HOME}/Support/ceptr
+$ poetry run qssa -lq ${PELE_PHYSICS_HOME}/Mechanisms/list_qss_mech
+
+
+

To generate all mechanisms:

+
$ poetry run convert -l ${PELE_PHYSICS_HOME}/Mechanisms/list_mech
+$ poetry run qssa -lq ${PELE_PHYSICS_HOME}/Mechanisms/list_qss_mech
+$ poetry run convert -lq ${PELE_PHYSICS_HOME}/Mechanisms/list_qss_mech
+
+
+
+
+
+

Converting CHEMKIN files

+

We rely on Cantera’s ck2yaml utility to convert CHEMKIN files to the Cantera yaml format (and proceed as above with CEPTR on the resulting yaml file):

+
$ cd ${PELE_PHYSICS_HOME}/Support/ceptr
+$ poetry run ck2yaml --input=${PATH_TO_CHEMKIN_DIR}/mechanism.inp --thermo=${PATH_TO_CHEMKIN_DIR}/therm.dat --transport=${PATH_TO_CHEMKIN_DIR}/tran.dat --permissive
+
+
+

The files tran.dat and therm.dat are optional if already included in the .inp file.

+
+
+

Generating a QSS chemistry file

+

To generate a QSS chemistry yaml file from another yaml file, one executes:

+
$ poetry run qssa -f ${PATH_TO_YAML}/skeletal.yaml -n ${PATH_TO_YAML}/non_qssa_list.yaml
+
+
+

The full list of options is:

+
$ poetry run qssa -h
+usage: qssa [-h] -f FNAME -n NQSSA [-m {0,1,2}] [-v]
+
+Mechanism converter
+
+optional arguments:
+  -h, --help            show this help message and exit
+  -f FNAME, --fname FNAME
+                        Mechanism file
+  -n NQSSA, --nqssa NQSSA
+                        Non-QSSA species list
+  -m {0,1,2}, --method {0,1,2}
+                        QSSA method (default: 2)
+  -v, --visualize       Visualize quadratic coupling and QSSA dependencies
+
+
+

For a detailed description of these options and a further information on the way QSS mechanism are treated in CEPTR the reader may consult the QSS section.

+

See Tutorials (Generating NC12H26 QSS mechanism with analytical jacobian and Generating NC12H26 QSS mechanism without analytical jacobian) for generating QSS mechanisms from the .yaml files.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Chemistry.html b/Chemistry.html new file mode 100644 index 000000000..bc857f7ab --- /dev/null +++ b/Chemistry.html @@ -0,0 +1,207 @@ + + + + + + + Chemistry — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+ + +
+
+
+
+ + + + \ No newline at end of file diff --git a/CvodeInPP.html b/CvodeInPP.html new file mode 100644 index 000000000..629339c95 --- /dev/null +++ b/CvodeInPP.html @@ -0,0 +1,875 @@ + + + + + + + CVODE implementation in PelePhysics — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

CVODE implementation in PelePhysics

+
+

The different reactors

+

Throughout this document, what we call a reactor is in fact a zero-dimensional model, +the simplest representation of a chemically reacting system. Depending upon the choice of state variables +driving the system, several different types of reactor can be considered; +and the “correct” choice is case dependent. In general, the state variables for a reactor model are

+
    +
  • The reactor mass

  • +
  • The reactor volume

  • +
  • The energy of the system

  • +
  • The mass fractions for each species

  • +
+

The most common type of reactor is the constant-volume (CV) reactor, which is the one used to advance the chemistry +within PeleC. This reactor type is equivalent to a rigid vessel with fixed volume but variable pressure. +In PelePhysics, the constant-volume constraint is ensured by keeping the density \(\rho\) fixed +-since there is no change of mass; and the indirect choice of energy in the CV reactor implementation is the total energy +\(E\). \(E\)’s evolution in our case is solely due to a constant external source term \(\dot{E}_{ext}\), which accounts +for the effects of advection and convection in the Spectral Deferred Correction (SDC) scheme that all Pele codes use (see the PeleLM documentation for example). +In that sense, the CV reactor is an abstraction and is not a true closed vessel.

+

Note that CVODE still integrates the mass fractions (\(\rho Y\)) together with energy for stability reasons, +but a change of variable is applied to effectively transport the temperature \(T\) via

+
+\[\rho C_v \frac{\partial T}{\partial t} = \rho\dot{E}_{ext} - \sum_k e_k {\dot{\omega}_k}^M\]
+

where the \(e_k\) are the species internal energy and \({\dot{\omega}_k}^M\) is the species \(k\) mass production rate.

+

In a second implementation, that we will label constant-volume-enthalpy (CVH), the mass-weighted total enthalpy \(\rho H\) is used and +conserved along with \(\rho\). This reactor type is also an abstraction. Here also, \(\rho H\) +evolves according to an external source term \(\dot{\rho H}_{ext}\), and in CVODE, the mass fractions (\(\rho Y\)) and +temperature \(T\) are integrated according to

+
+\[\rho C_p \frac{\partial T}{\partial t} = \rho\dot{H}_{ext} - \sum_k h_k {\dot{\omega}_k}^M\]
+

where the \(h_k\) are the species internal energy.

+
+

Validation of the CV reactor implementation in CVODE (with CANTERA)

+

CANTERA is an open-source suite of tools for problems involving chemical kinetics, thermodynamics, and transport processes. +It is a very robust and fast tool written in C++ that is also based on CVODE to perform the chemistry integration. +CANTERA is well recognized in the combustion community, and by comparing our results to CANTERA reactor simulations, +we will be able to validate our implementation.

+

Note that only the CV reactor model described above can be validated, since as we discussed before, +the CVH reactor model is an abstraction needed for our Low-Mach PeleLM chemistry integration. Also, to have a real CV reactor, +the external source terms for the energy and species equations in PelePhysics have been set to 0 (see The different reactors).

+

The parameters chosen to initialize the simulation in both CANTERA and PelePhysics are described in +Table 1. The kinetic mechanism used for hydrogen combustion is available in PelePhysics. +Note that small sub-steps are explicitly taken until the final time is reached, +but CVODE’s internal machinery can subdivides the \(dt\) even further. +For the purpose of validation, the direct dense solver of CVODE is selected +in PelePhysics (see section Activating the different CVODE solver options via the input files).

+ + + + + + + + + + + + + + + + + + + + +
1 Parameters for initializing simulation

Mechanism

Mixture

Initial T

Initial phi

Pressure

dt

Final time

Li Dryer

H2/O2

1500 K

0.8

101325 Pa

1.0e-8s

3.0e-6s

+

Results are plotted in Fig 2 and 3. for the \(H_2/O_2\) mixture. +All curves are indistinguishable, so the relative error of all major quantities is also plotted in Fig. 4. +Note that \(H_2\) and \(O_2\) relative errors have similar features, and that relative errors observed +for \(H\) and \(H_2O\) are representative of those exhibited by, respectively, intermediates and products.

+ + + + + + +
2 Evolution of temperature, pressure and enthalpy in a CV reactor, computed with the LiDryer mechanism. Black: CANTERA, red: PelePhysics.

a

+ + + + + + +
3 Evolution of major species in a CV reactor, computed with the LiDryer mechanism. Black: CANTERA, red: PelePhysics.

b

+ + + + + + +
4 Relative errors on the temperature, pressure, enthalpy and major species in a CV reactor, computed with the LiDryer mechanism.

c

+

Overall, considering the many CVODE controlling parameters, results are deemed acceptable and that +concludes the validation of the reactors implemented in PelePhysics.

+
+
+
+

Activating the different CVODE solver options via the input files

+

Note that at this point, it is believed that the user has properly installed CVODE as well as the SuiteSparse package. If not, refer to Dependencies.

+

Choosing between DVODE/CVODE (as well as other ODE integrators that will not be discussed in this section) is done at compile time, +via the GNUmakefile. On the other hand, the type of reactor and specifics of the numerical algorithm +are selected via keywords in the input file. There is a subtlety though: +when any sparsity feature is required, the choice should also be made at compile time since external libraries will be required; +and if the compilation is not performed properly, subsequent options via keywords in the input file can either lead to an error or fall back to a dense formulation +of the problem. This is discussed in more depth in what follows.

+
+

The GNUmakefile

+

The default setting is to use DVODE in PelePhysics; i.e, if no modifications are done to the original GNUmakefile (see the test case ReactEval_FORTRAN of PelePhysics), +then this option should automatically be selected. To activate CVODE, the user must first activates the use of Sundials via the following line:

+
USE_SUNDIALS_PP = TRUE
+
+
+

Note that this is a PelePhysics flag, so it will automatically be recognized in the Pele codes. However, if CVODE has not been installed as prescribed in Dependencies then a line specifying the location of the Sundials libraries should be added:

+
CVODE_LIB_DIR=PathToSundials/instdir/lib/
+
+
+

By default, if Sundials is used then the implicit ODE solver CVODE is selected. The user then has to choose between a number of +different methods to integrate the linear system arising during the implicit solve. Add the following line if sparsity features are required:

+
PELE_USE_KLU = TRUE
+
+
+

Likewise, if SuiteSparse has not been installed as prescribed in Dependencies, then a line specifying its location should be added:

+
SUITESPARSE_DIR=PathToSuiteSparse/
+
+
+

All of the flags discussed in this subection are used in $PELE_PHYSICS_HOME/ThirdPartyThirdParty/Make.ThirdParty.

+
+
+

The input file

+

The input file is made up of specific blocks containing keywords that apply to specific areas of the integrationof the problem at hand. +The suffix associated with each block of keywords should help the user in determining which keywords +are needed in his case, depending on the options selected via the GNUmakefile. +If CVODE is enabled via the GNUmakefile, for example, keywords starting with cvode.* are relevant. +The general ode.* keywords are shared by all ODE integrators and thus are also relevant for CVODE:

+
    +
  • ode.reactor_type enable to switch from a CV reactor (=1) to a CVH reactor (=2).

  • +
  • cvode.solve_type controls the CVODE linear integration method: choose 1 to enable the dense direct linear solver, +5 for the sparse direct linear solver (if the KLU library has been linked) and 99 for the Krylov iterative solver

  • +
  • ode.analytical_jacobian is a bit less obvious:

    +
      +
    • If cvode.solve_type = 1, then ode.analytical_jacobian = 1 will activate the use of an Analytical Jacobian.

    • +
    • If cvode.solve_type = 99, then ode.analytical_jacobian = 1 will activate the preconditioned GMRES solver while ode.analytical_jacobian = 0 will activate the non-preconditioned GMRES solver.

    • +
    • If cvode.solve_type = 99, ode.analytical_jacobian = 1 and the KLU library is linked, then the preconditioned solve is done in a sparse format.

    • +
    • With cvode.solve_type = 5, the only allowed option is ode.analytical_jacobian = 1.

    • +
    +
  • +
+
+
+
+

The ReactEval_C test case with CVODE in details

+

This tutorial has been adapted from the ReactEval_FORTRAN tutorial employed in the series of regression tests to monitor the DVODE chemistry integration. +The domain considered is a \(2x1024x2\) box, where the initial temperature is different in each \((i,j,k)-\) cell, according to a \(y-\) evolving sinusoidal profile, see Fig. 1:

+
+\[T(i,j,k) = T_l + (T_h-T_l)\frac{y(i,j,k)}{L} + dTsin\left(2\pi\frac{y(i,j,k)}{P}\right)\]
+

The different parameters involved are summarized in Table 5. The initial pressure is 1 atm. The initial composition is the same in every cell, and is a mixture of 0.1 \(C_nH_m\), 0.2 \(O_2\) and 0.7 \(N_2\) in mass fractions.

+

Various fuels and kinetic mechanisms can be employed. For the purpose of this tutorial, two common fuels will be considered: methane (n=1 and m=4) and n-dodecane (n=12 and m=26), modelled via the drm and dodecane_wang kinetic schemes, respectively. Both mechanisms are available in PelePhysics.

+

The following focuses on the \(CH_4\)/\(O_2\) example, but performances for both mechanisms and initial composition will be reported in the results section.

+ + + + + + + + + + + + + + + + +
5 Parameters used to initialize T in the ReactEval_C test case

Tl

Th

dT

L

P

2000 K

2500 K

100 K

1024

L/4

+
+The ReactEval_C test case +
+

1 The ReactEval_C test case

+
+
+
+

The GNUmakefile

+

For this example, the USE_SUNDIALS_PP flag should be set to true, as the ODE integration +is called from the C++ routine directly using CVODE. +Additionally, the FUEGO_GAS flag should be set to true and the chemistry model should be set to drm19. The full file reads as follows:

+
PRECISION  = DOUBLE
+PROFILE    = FALSE
+
+DEBUG      = FALSE
+
+DIM        = 3
+
+COMP       = gcc
+FCOMP      = gfortran
+
+USE_MPI    = TRUE
+USE_OMP    = FALSE
+
+FUEGO_GAS  = TRUE
+
+TINY_PROFILE = TRUE
+
+# define the location of the PELE_PHYSICS top directory
+PELE_PHYSICS_HOME    := ../../../..
+
+#######################
+DEFINES  += -DMOD_REACTOR
+
+#######################
+# ODE solver OPTIONS: DVODE (default) / SUNDIALS / RK explicit
+#######################
+# Activates use of SUNDIALS: CVODE (default) / ARKODE
+USE_SUNDIALS_PP = TRUE
+ifeq ($(USE_SUNDIALS_PP), TRUE)
+  # provide location of sundials lib if needed
+  SUNDIALS_LIB_DIR=$(PELE_PHYSICS_HOME)/ThirdParty/sundials/instdir/lib/
+  # use KLU sparse features -- only useful if CVODE is used
+  PELE_USE_KLU = FALSE
+  ifeq ($(PELE_USE_KLU), TRUE)
+    # provide location of KLU lib if needed
+    SUITESPARSE_DIR=$(PELE_PHYSICS_HOME)/ThirdParty/SuiteSparse/
+  endif
+endif
+
+#######################
+ifeq ($(FUEGO_GAS), TRUE)
+  Eos_Model       = Fuego
+  Chemistry_Model = drm19
+  Reactions_dir   = Fuego
+  Transport_Model = Simple
+else
+  Eos_Model       = GammaLaw
+  Reactions_dir   = Null
+  Transport_Model = Constant
+endif
+
+Bpack   := ./Make.package
+Blocs   := .
+
+include $(PELE_PHYSICS_HOME)/Testing/Exec/Make.PelePhysics
+
+
+

Note that the TINY_PROFILE flag has been activated to obtain statistics on the run. This is an AMREX option.

+
+
+

The input file

+

The run parameters that can be controlled via inputs.3d input file for this example are as follows:

+
#ODE solver options
+# REACTOR mode
+ode.dt = 1.e-05
+ode.ndt = 10
+# Reactor formalism: 1=full e, 2=full h
+ode.reactor_type = 1
+# Tolerances for ODE solve
+ode.rtol = 1e-9
+ode.atol = 1e-9
+# Select ARK/CV-ODE Jacobian eval: 0=FD 1=AJ
+ode.analytical_jacobian = 0
+#CVODE SPECIFICS
+# Choose between sparse (5) dense (1/101) iterative (99) solver
+cvode.solve_type = 1
+
+#OTHER
+# Max size of problem
+max_grid_size = 2
+# Choose name of output pltfile
+amr.plot_file       = plt
+# Fuel species
+fuel_name = CH4
+
+
+

so in this example, a CV reactor model is chosen to integrate each cell, and the dense direct solve without analytical Jacobian is activated. +Each cell is then integrated for a total of \(1.e-05\) seconds, with 10 external time steps. +This means that the actual \(dt\) is \(1.e-06s\), which is more than what is typically used in the PeleC code, +but consistent with what is used in PeleLM. Note that the fuel is explicitly specified to be methane. +By default, the number of cells integrated simultaneously by one CVODE instance is 1 [1], but the AMREX block-integration proceeds by blocks of \(2x2x2\).

+
+
+

Results

+

It took 52.61s to integrate the 4096 cells of this box, with 4 MPI processes and no OMP process. +The resulting temperature evolution for all cells in the y-direction is displayed in Fig. 2.

+
+Evolution of temperature in the 2x1024x2 example box, using a CV reactor and a dense direct solve, and computed with the DRM mechanism. Black: $t=0$, red: $t=1e-05s$ +
+

2 Evolution of temperature in the 2x1024x2 example box, using a CV reactor and a dense direct solve, and computed with the DRM mechanism. Black: t=0s, red: t=1e-05s

+
+
+
+
+
+

To go further: ReactEval_C with CVODE and the KLU library

+
+

The GNUmakefile

+

Only the middle part of the GNUmakefile needs to be modified compared to the previous example.

+
...
+#######################
+# ODE solver OPTIONS: DVODE (default) / SUNDIALS / RK explicit
+#######################
+# Activates use of SUNDIALS: CVODE (default) / ARKODE
+USE_SUNDIALS_PP = TRUE
+ifeq ($(USE_SUNDIALS_PP), TRUE)
+  ...
+  # use KLU sparse features -- only useful if CVODE is used
+  PELE_USE_KLU = TRUE
+  ...
+else
+  ...
+endif
+
+#######################
+...
+
+
+
+
+

The input file

+

For the KLU library to be of use, a solver utilizing sparsity features should +be selected. We modify the input file as follows:

+
...
+#######################
+#ODE solver options
+...
+# Select ARK/CV-ODE Jacobian eval: 0=FD 1=AJ
+ode.analytical_jacobian = 1
+#CVODE SPECIFICS
+# Choose between sparse (5) dense (1/101) iterative (99) solver
+cvode.solve_type = 99
+...
+#OTHER
+...
+
+
+

So that now, a preconditioned iterative Krylov solver is selected, where the preconditioner is specified in a sparse format.

+
+
+

Results

+

This run now takes 1m34s to run. As expected from the dense Jacobian of the system obtained when using the small DRM mechanism +(the fill in pattern is \(>90 \%\)), using an iterative solver does not enable to reach speed-ups over the simple dense direct +solve. NOTE, and this is important, that this tendency will revert when sufficiently small time steps are used. +For example, if instead of \(1e-6s\) we took time steps of \(1e-8s\) (consistent with PeleC time steps), then using +the iterative GMRES solver would have provided significant time savings. This is because the smaller the time step the +closer the system matrix is from the identity matrix and the GMRES iterations become really easy to complete.

+

This example illustrates that choosing the “best” and “most efficient” algorithm is far from being a trivial task, +and will depend upon many factors. Table 6 provides a summary of the CPU run time in solving the +ReactEval_C example with a subset of the various available CVODE linear solvers. As can be seen from the numbers, using an AJ is much more efficient than relying upon CVODE’s built-in difference quotients. Using a sparse solver does not appear to provide additional time savings.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
6 Summary of ReactEval_C runs with various algorithms (methane/air)

Solver

Direct +Dense

Direct +Dense AJ

Direct +Sparse AJ

Iter. +not Precond.

Iter. +Precond. (S)

KLU

OFF

OFF

ON

OFF

ON

ode.reactor_type

1

1

1

1

1

cvode.solve_type

1

1

5

99

99

ode.analytical_jacobian

0

1

1

1

1

Run time

52.61s

44.87s

48.64s

1m42s

1m34s

+

The same series of tests are performed for a mixture of n-dodecane and air (see The ReactEval_C test case with CVODE in details), the configuration being otherwise the same as in the methane/air case. Results are summarized in Table 7. The overall tendencies remain similar. Note that the non-preconditioned GMRES solver becomes very inefficient for this larger system. Here also, the direct sparse solve –which relies upon the KLU library, does not seem to provide additional time savings. The fill-in pattern is \(70 \%\).

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
7 Summary of ReactEvalCvode runs with various algorithms (n-dodecane/air)

Solver

Direct +Dense

Direct +Dense AJ

Direct +Sparse AJ

Iter. +not Precond.

Iter. +Precond. (S)

KLU

OFF

OFF

ON

OFF

ON

ode.reactor_type

1

1

1

1

1

cvode.solve_type

1

1

5

99

99

ode.analytical_jacobian

0

1

1

1

1

Run time

6m25s

5m33s

6m32s

21m44s

10m14s

+
+
+
+

Current Limitations

+

Note that currently, all sparse operations rely on an Analytical Jacobian. This AJ is provided via the chemistry routines dumped by the CEPTR code. Those routines are generated in a pre-processing step, when the sparsity pattern of the AJ is still unknown. As such, all entries of the AJ are computed at all times, and when a sparsity solver is chosen, the AJ is in fact “sparsified” to take advantage of the sparse linear algebra. The “sparsification” process involves a series of loop in the cpp that takes a significant amount of the CPU time most of the time. However, it is always good to verify that this is the case. AMREX’s TINY_PROFILER features is a handy tool to do so.

+
+
+

Tricks and hacks, stuff to know

+

When using DVODE, there is a hack enabling the user to reuse the Jacobian instead of reevaluating it from scratch. +This option is triggered when setting the extern_probin_module flag new_Jacobian_each_cell to 0. +This can be done in PelePhysics by adding the following line in the probin file:

+
&extern
+ new_Jacobian_each_cell = 0
+/
+
+
+

A similar feature is currently not available in CVODE, although it would be possible to modify the CVodeReInit function +to reinitialize only a subset of counters. This is currently under investigation. +The user still has some control via the CVODE flag CVodeSetMaxStepsBetweenJac.

+
+
+

How does CVODE compare with DVODE ?

+

Depending on whether the famous Jacobian hack is activated or not in DVODE, +the completion time of the run can be decreased significantly. The same test case as that described in the previous section can also be integrated with DVODE. +For that purpose, the FORTRAN routines implementing the DVODE integration have been interfaced with C++ via a FORTRAN header. The run is thus identical to ReactEval_C with CVODE. +Only the GNUmakefile needs to be modified:

+
...
+#######################
+# ODE solver OPTIONS: DVODE (default) / SUNDIALS / RK explicit
+#######################
+# Activates use of SUNDIALS: CVODE (default) / ARKODE
+USE_SUNDIALS_PP = FALSE
+...
+
+#######################
+...
+
+
+

and, as explained in section Tricks and hacks, stuff to know, the famous AJ hack can be activated via the probin file.

+

Two runs are performed, activating the hack or not. Times are reported in Table 8.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
8 Summary of a CVODE vs a DVODE chemistry integration on the same test case

Solver

Direct +Dense

Direct +Dense

Direct +Dense + hack

KLU

OFF

OFF

OFF

USE_SUNDIALS_PP

ON (CVODE)

OFF (DVODE)

OFF (DVODE)

ode.reactor_type

1

1

1

cvode.solve_type

1

N/A

N/A

ode.analytical_jacobian

0

N/A

N/A

Run time

52.61s

53.21s

52.83s

+

In this case, the hack does not seem to provide significant time savings. Note also that CVODE is usually slightly more efficient than DVODE, consistently with findings of other studies available in the literature – although in this case all options give comparable results.

+
+
+
+

CVODE implementation in PelePhysics on GPU

+
+

Requirements and input files

+

To use CVODE on a GPU, Sundials should be build with the flag CUDA_ENABLE . A CUDA compiler also needs to be specified. Relevant information is provided in the Sundials install guide, and an automatic script is distributed with PelePhysics to ease the process. Refer to Dependencies.

+

Note that the SuiteSparse package does not support GPU architecture and is thus no longer required. Sparse linear algebra operations, when needed, are performed with the help of CUDA’s cuSolver.

+
+

The GNUmakefile

+

To run on GPUs, AMREX should be build with CUDA enabled. To do so, add this line to the GNUmakefile:

+
USE_CUDA   = TRUE
+
+
+

This should activate the CUDA features of CVODE in PelePhysics too.

+
+
+

The input file

+

In the inputs.3d, the same three main keywords control the algorithm (ode.reactor_type, cvode.solve_type, ode.analytical_jacobian). However, note that there are less linear solver options available.

+
    +
  • Both preconditioned or non-preconditioned GMRES options are available (cvode.solve_type = 99). The preconditioned version is triggered via the same flag as on the CPU (ode.analytical_jacobian = 1).

  • +
  • The user has the choice between two different sparse solvers.

    +
      +
    • Sundials offers one option (the SUNLinSol_cuSolverSp_batchQR) relying upon the cuSolver to perform batched sparse QR factorizations. This version is enabled via cvode.solve_type = 5 and ode.analytical_jacobian = 1.

    • +
    • Another version is available via cvode.solve_type = 1 and ode.analytical_jacobian = 1. This version relies upon a pre-computed Gauss-Jordan Solver, and is fairly efficient for problems of moderate size.

    • +
    +
  • +
+
+
+
+

Grouping cells together

+

To take full advantage of the GPU power, many intensive operations of similar nature should be performed in parallel. In PelePhysics, this is achieved by grouping many cells together, and integrating each one in separate threads within one CVODE instance. Indeed, the flow of operations to solve one set of ODEs is very similar from one cell to the next, and one could expect limited thread divergence from this approach. Fig. 3 summarizes the idea. Note that the Jacobian of the group of cells is block-sparse, and any chosen integration method should take advantage of this.

+
+Grouping of cells +
+

3 n cells are solved together in one CVODE instance. The big-matrix is block-sparse.

+
+
+

In the current implementation, the number of cells that are grouped together is equal to the number of cells contained in the box under investigation within a MultiFab iteration.

+
+
+

The ReactEval_C_GPU test case in details

+

A series of tests are performed on the GPU for a mixture of methane and air, with the intent of evaluationg the performance of the chemistry solvers. +The test case, configuration and initial conditions are similar to that described in The ReactEval_C test case with CVODE in details. The mechanism employed is the drm.

+
+

The GNUmakefile

+

The full file reads as follows:

+
PRECISION  = DOUBLE
+PROFILE    = FALSE
+
+DEBUG      = FALSE
+
+DIM        = 3
+
+COMP       = gcc
+FCOMP      = gfortran
+
+USE_MPI    = FALSE
+USE_OMP    = FALSE
+
+FUEGO_GAS  = TRUE
+
+USE_CUDA   = TRUE
+
+TINY_PROFILE = TRUE
+
+# define the location of the PELE_PHYSICS top directory
+PELE_PHYSICS_HOME    := ../../..
+
+#######################
+# this flag activates the subcycling mode in the D/Cvode routines
+DEFINES  += -DMOD_REACTOR
+
+#######################
+# ODE solver OPTIONS on GPU: SUNDIALS
+#######################
+# Activates use of SUNDIALS: CVODE (default)
+USE_SUNDIALS_PP = TRUE
+
+##############################################
+ifeq ($(FUEGO_GAS), TRUE)
+  Eos_Model       = Fuego
+  Chemistry_Model = drm19
+  Reactions_dir   = Fuego
+  Transport_Model   = Simple
+else
+  Eos_Model       = GammaLaw
+  Reactions_dir = Null
+  Transport_Model = Constant
+endif
+
+Bpack   := ./Make.package
+Blocs   := .
+
+include $(PELE_PHYSICS_HOME)/Testing/Exec/Make.PelePhysics
+
+
+
+
+

The input file

+
+
+

The Results

+

Results are summarized in Table 9.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
9 Summary of ReactEvalCvode_GPU runs with various algorithms (methane/air)

Solver

Direct +Sparse I

Direct +Sparse II

Iter. +not Precond.

Iter. +Precond. (S)

reactor_type

1

1

1

1

cvode.solve_type

1

5

99

99

ode.analytical_jacobian

1

1

0

1

Run time

13s

20s

19s

36s

+
+
+
+

Current Limitations

+

The current GPU implementation of CVODE relies on the launch of many kernels from the host. As such, a CVODE instance does not live directly on the GPU; rather, the user is in charge of identifying and delegating computation-intensive part of the RHS, Jacobian evaluation, etc. +The current implementation thus suffers from the cost of data movement, and parallelization is limited due to required device synchronizations within CVODE.

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/DeveloperGuide.html b/DeveloperGuide.html new file mode 100644 index 000000000..eb0fab976 --- /dev/null +++ b/DeveloperGuide.html @@ -0,0 +1,168 @@ + + + + + + + Developer Guidelines — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Developer Guidelines

+

The following developer guidelines apply to all code that is to be committed to the Pele suite.

+

Before adding files for a commit to be pushed to a branch of PelePhysics, first run the following formatting tools depending on the type of code:

+
+

C++ Code

+

All C++ code should be processed by the Clang formatter prior to being added for commit.

+

Run clang-format:

+
clang-format -i FILE.cpp
+clang-format -i FILE.H
+
+
+

Will apply all of the correct formatting and make the changes directly to the cpp source files.

+
+
+

Python

+

The tools necessary to format Python code (currently only used within CEPTR) are maintained through Poetry.

+
    +
  1. Run isort:

    +
    poetry run isort .
    +
    +
    +
  2. +
+

This will perform proper sorting of the installed Python libraries.

+
    +
  1. Run black:

    +
    poetry run black .
    +
    +
    +
  2. +
+

This will perform proper formatting of all Python files to be consistent with all current files.

+
    +
  1. Run flake8:

    +
    poetry run flake8 .
    +
    +
    +
  2. +
+

This will run diagnostics on all the Python files and will list a series of issues that need to be addressed to adhere to current Python best practices.

+

Once all flake8 messages have been addressed, the code will match the Pele suite standard.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/EOS.html b/EOS.html new file mode 100644 index 000000000..36838320a --- /dev/null +++ b/EOS.html @@ -0,0 +1,368 @@ + + + + + + + Equation of State — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Equation of State

+

PelePhysics allows the user to use different equation of state (EOS) as the constitutive equation and close the compressible Navier-Stokes system of equations. All the routines needed to fully define an EOS are implemented through PelePhysics module. Available models include:

+
    +
  • A simple GammaLaw model for a single component perfect gas

  • +
  • An ideal gas mixture model (similar to the CHEMKIN-II approach) labeled Fuego

  • +
  • The Soave-Redlich-Kwong cubic equation of state; Peng-Robinson support was started in the original Fortran version of the code but stalled and is not supported.

  • +
+

Examples of EOS implementation can be seen in PelePhysics/Eos. The choice between these Eos models is made at compile time. When using GNUmake, this is done by setting the Eos_Model parameter in the GNUmakefile.

+

The following sections will fully describe the implementation of Soave-Redlich-Kwong, a non-ideal cubic EOS, for a general mixture of species. Some examples of the old Fortran implementation of the code are given; these have since been ported to C++. Integration with CEPTR, for a chemical mechanism described in a chemkin format, will also be highlighted. For an advanced user interested in implementing a new EOS this chapter should provide a good starting point.

+
+

Note

+

For the flow solvers in the Pele suite, the SRK EOS is presently only supported in PeleC, and not PeleLM(eX).

+
+
+

GammaLaw

+

This EOS corresponds to a single component perfect gas, i.e. a gas that follows \(p = \rho \hat{R} T\) and \(e = c_v T\), with constant \(c_v\), which together imply that \(p = (\gamma - 1)\rho e\), where \(\gamma = c_p / c_v\). The values of the relevant physical properties (\(\gamma = 1.4\), \(MW=28.97\) g/mol) are chosen to correspond to air at standard conditions and are set in PelePhysics/Source/PhysicsConstants.H.

+

When the GammaLaw EOS is used, the Chemistry_Model should be set to Null.

+
+
+

Fuego

+

This is a multi-component ideal gas EOS to be used for mutli-component (reacting) calculations with any Chemistry_Model besides Null. The gas mixture follows \(p = \rho \hat{R} T\), but with \(h(T) \equiv \sum Y_i h_i(T)\) and \(h_i(T)\) computed based on NASA polynomials that are included in the Chemistry_Model.

+
+
+

Soave-Redlich-Kwong (SRK)

+

The cubic model is built on top of the ideal gas models. It should be used for multi-component (reacting) calculations where the pressure is sufficiently high that real gas effects are important; there is a significant computational cost penalty relative ideal gas calculations. Note that the function to compute the analytical Jacobian of the chemical system using the SRK EOS has not been implemented, so this EOS is not compatible with reaction integrators that rely on computing the analytical Jacobian. Any additional parameters (e.g., attractions, repulsions, critical states) are either included in the underlying Fuego database used to generate the source file model implementation, or else are inferred from the input model data.

+

SRK EOS as a function of Pressure (p), Temperature(T), and \(\tau\) (specific volume) is given by

+
+\[p = R T \sum \frac{Y_k}{W_k} \frac{1}{\tau - b_m} - \frac{a_m}{\tau(\tau + b_m)}\]
+

where \(Y_k\) are species mass fractions, \(R\) is the universal gas constant, and +\(b_m\) and \(a_m\) are mixture repulsion and attraction terms, respectively.

+
+

Mixing rules

+

For a mixture of species, the following mixing rules are used to compute \(b_m\) and \(a_m\).

+
+\[a_m = \sum_{ij} Y_i Y_j \alpha_i \alpha_j \;\;\; b_m = \sum_k Y_k b_k\]
+

where \(b_i\) and \(a_i\) for each species is defined using critical pressure and temperature.

+
+\[a_i(T) = 0.42748 \frac{\left(R T_{c,i} \right)^2}{W_i^2 p_{c,i}} \bar{a}_i \left(T/T_{c,i}\right) \;\;\; +b_i = 0.08664 \frac{R T_{c,i}}{W_i p_{c,i}}\]
+

where

+
+\[\bar{a}_i (T/T_{c,i}) = \left(1 + \mathcal{A} \left[ f\left( \omega_i \right) \left(1-\sqrt{T/T_{c,i}} \right ) \right] \right)^2\]
+

where \(\omega_i\) are the accentric factors and

+
+\[f\left( \omega_i \right) = 0.48508 + 1.5517 \omega_i - 0.151613 \omega_{i}^2\]
+

For chemically unstable species such as radicals, critical temperatures and pressures are not available. +For species where critical properties are not available, we use the Lennard-Jones potential for that species to construct attractive and repulsive coefficients.

+
+\[T_{c,i} = 1.316 \frac{\epsilon_i}{k_b} \;\;\; a_i(T_{c,i}) = 5.55 \frac{\epsilon_i \sigma_i^3}{m_i^2} \;\;\; +\mathrm{and} \;\;\; b_i = 0.855 \frac{\sigma_i^3}{m_i}\]
+

where \(\sigma_i\), \(\epsilon_i\) are the Lennard-Jones potential molecular diameter and well-depth, respectively, +\(m_i\) the molecular mass, and \(k_b\) is Boltzmann’s constant.

+

In terms of implementation, a routine called MixingRuleAmBm can be found in the SRK eos implementation. The following code block shows the subroutine which receives species mass fractions and temperature as input. The outputs of this routine are \(b_m\) and \(a_m\) .

+
do i = 1, nspecies
+  Tr = T*oneOverTc(i)
+  amloc(i) =  (1.0d0 + Fomega(i)*(1.0d0-sqrt(Tr))) *sqrtAsti(i)
+
+  bm = bm + massFrac(i)*Bi(i)
+
+enddo
+do j = 1, nspecies
+   do i = 1, nspecies
+
+      am = am + massFrac(i)*massFrac(j)*amloc(i)*amloc(j)
+
+   end do
+end do
+
+
+
+
+

Thermodynamic Properties

+

Most of the thermodynamic properties can be calculated from the equation of state and involve derivatives of various thermodynamic quantities and of EOS parameters. In the following, some of these thermodynamic properties for SRK and the corresponding routines are presented.

+
+

Specific heat

+

For computing mixture specific heat at constant volume and pressure, the ideal gas contribution and the departure from the ideal gas are computed. Specific heat at constant volume can be computed using the following

+
+\[c_v = \left( \frac{\partial e_m}{\partial T}\right)_{\tau,Y}\]
+

For SRK EOS, the formula for \(c_v\) reduces to

+
+\[c_v = c_v^{id} - T \frac{\partial^2 a_m}{\partial T^2} \frac{1}{b_m} ln ( 1 + \frac{b_m}{\tau})\]
+

where \(c_v^{id}\) is the specific heat at constant volume. Mixture specific heat at constant volume is implemented through the routine SRK_EOS_GetMixtureCv

+
subroutine SRK_EOS_GetMixtureCv(state)
+implicit none
+type (eos_t), intent(inout) :: state
+real(amrex_real) :: tau, K1
+
+state % wbar = 1.d0 / sum(state % massfrac(:) * inv_mwt(:))
+
+call MixingRuleAmBm(state%T,state%massFrac,state%am,state%bm)
+
+tau = 1.0d0/state%rho
+
+! Derivative of the EOS AM w.r.t Temperature - needed for calculating enthalpy, Cp, Cv and internal energy
+call Calc_dAmdT(state%T,state%massFrac,state%am,state%dAmdT)
+
+! Second Derivative of the EOS AM w.r.t Temperature - needed for calculating enthalpy, Cp, Cv and internal energy
+call Calc_d2AmdT2(state%T,state%massFrac,state%d2AmdT2)
+
+! Ideal gas specific heat at constant volume
+call ckcvbs(state%T, state % massfrac, iwrk, rwrk, state % cv)
+
+! Real gas specific heat at constant volume
+state%cv = state%cv + state%T*state%d2AmdT2* (1.0d0/state%bm)*log(1.0d0+state%bm/tau)
+
+end subroutine SRK_EOS_GetMixtureCv
+
+
+

Specific heat at constant pressure is given by

+
+\[\begin{split}c_p = \left( \frac{\partial h_m}{\partial T}\right)_{p,Y} \;\; \\ +c_p = \frac{\partial h_m}{\partial T} - \frac {\frac{\partial h}{\partial \tau}} {\frac{\partial p}{\partial \tau}} \frac{\partial p}{\partial T}\end{split}\]
+

where all the derivatives in the above expression for SRK EOS are given by

+
+\[\begin{split}\frac{\partial p}{\partial T} = \sum Y_k / W_k \frac{R}{\tau-b_m} - \frac{\partial a_m}{\partial T} \frac{1}{\tau(\tau +b_m)} \\ +\frac{\partial p}{\partial \tau} = -\sum Y_k / W_k \frac{R T}{(\tau-b_m)^2} + \frac{a_m (2 \tau + b_m)}{[\tau(\tau +b_m)]^2} \\ +\frac{\partial h_m}{\partial \tau} = -\left(T \frac{\partial a_m}{\partial T} - a_m \right) \frac{1}{\tau(\tau+b_m)} + \frac{a_m}{(\tau+b_m)^2} -\sum Y_k / W_k \frac{R T b_m}{(\tau-b_m)^2} \\ +\frac{\partial h_m}{\partial T} = c_p^{id} +T \frac{\partial^2 a_m}{\partial T^2} \frac{1}{b_m} ln ( 1 + \frac{b_m}{\tau}) - \frac{\partial a_m}{\partial T} \frac{1}{\tau+b_m} +\sum Y_k / W_k \frac{R b_m}{\tau-b_m}\end{split}\]
+
subroutine SRK_EOS_GetMixtureCp(state)
+implicit none
+type (eos_t), intent(inout) :: state
+real(amrex_real) :: tau, K1
+real(amrex_real) :var: : Cpig
+real(amrex_real) :: eosT1Denom, eosT2Denom, eosT3Denom
+real(amrex_real) :: InvEosT1Denom,InvEosT2Denom,InvEosT3Denom
+real(amrex_real) :: dhmdT,dhmdtau
+real(amrex_real) :: Rm
+
+state % wbar = 1.d0 / sum(state % massfrac(:) * inv_mwt(:))
+
+call MixingRuleAmBm(state%T,state%massFrac,state%am,state%bm)
+
+tau = 1.0d0/state%rho
+
+! Derivative of the EOS AM w.r.t Temperature - needed for calculating enthalpy, Cp, Cv and internal energy
+call Calc_dAmdT(state%T,state%massFrac,state%dAmdT)
+
+! Second Derivative of the EOS AM w.r.t Temperature - needed for calculating enthalpy, Cp, Cv and internal energy
+call Calc_d2AmdT2(state%T,state%massFrac,state%d2AmdT2)
+
+K1 = (1.0d0/state%bm)*log(1.0d0+state%bm/tau)
+
+eosT1Denom = tau-state%bm
+eosT2Denom = tau*(tau+state%bm)
+eosT3Denom = tau+state%bm
+
+InvEosT1Denom = 1.0d0/eosT1Denom
+InvEosT2Denom = 1.0d0/eosT2Denom
+InvEosT3Denom = 1.0d0/eosT3Denom
+
+Rm = (Ru/state%wbar)
+
+! Derivative of Pressure w.r.t to Temperature
+state%dPdT = Rm*InvEosT1Denom - state%dAmdT*InvEosT2Denom
+
+! Derivative of Pressure w.r.t to tau (specific volume)
+state%dpdtau = -Rm*state%T*InvEosT1Denom*InvEosT1Denom + state%am*(2.0*tau+state%bm)*InvEosT2Denom*InvEosT2Denom
+
+! Ideal gas specific heat at constant pressure
+call ckcpbs(state % T, state % massfrac, iwrk, rwrk,Cpig)
+
+! Derivative of enthalpy w.r.t to Temperature
+dhmdT = Cpig + state%T*state%d2AmdT2*K1 - state%dAmdT*InvEosT3Denom + Rm*state%bm*InvEosT1Denom
+
+! Derivative of enthalpy w.r.t to tau (specific volume)
+dhmdtau = -(state%T*state%dAmdT - state%am)*InvEosT2Denom + state%am*InvEosT3Denom*InvEosT3Denom - &
+   Rm*state%T*state%bm*InvEosT1Denom*InvEosT1Denom
+
+! Real gas specific heat at constant pressure
+state%cp = dhmdT - (dhmdtau/state%dpdtau)*state%dPdT
+
+end subroutine SRK_EOS_GetMixtureCp
+
+
+
+
+

Internal energy and Enthalpy

+

Similarly mixture internal energy for SRK EOS is given by

+
+\[e_m = \sum_k Y_k e_k^{id} + \left( T \frac{\partial a_m}{\partial T} - a_m \right)\frac{1}{b_m} ln \left( 1 + \frac{b_m}{\tau}\right)\]
+

and mixture enthalpy \(h_m = e + p \tau\)

+
+\[h_m = \sum_k Y_k h_k^{id} + \left ( T \frac{\partial a_m}{\partial T} - a_m \right) \frac{1}{b_m} \ln \left( 1 + \frac{b_m}{\tau}\right) + R T \sum \frac{Y_k}{W_k} \frac{b_m}{\tau -b_m} - \frac{a_m}{\tau + b_m}\]
+

and the implementation can be found in the routine SRK_EOS_GetMixture_H.

+
+
+

Speed of Sound

+

The sound speed for SRK EOS is given by

+
+\[a^2 = -\frac{c_p}{c_v} \tau^2 \frac{\partial p}{\partial \tau}\]
+
+
+

Species enthalpy

+

For computation of kinetics and transport fluxes we will also need the species partial enthalpies and the chemical potential. The species enthalpies for SRK EOS are given by

+
+\[h_k = \frac{\partial h_m}{\partial Y_k } - \frac {\frac{\partial h}{\partial \tau}} {\frac{\partial p}{\partial \tau}} \frac{\partial p}{\partial Y_k}\]
+

where

+
+\[\begin{split}\frac{\partial h_m}{\partial Y_k } &= h_k^{id} + (T \frac{\partial^2 a_m}{\partial T \partial Y_k} - \frac{\partial a_m }{\partial Y_k}) \frac{1}{b_m} \ln\left(1+ \frac{b_m}{\tau}\right) \\&-\left(T \frac{\partial a_m}{\partial T} - a_m \right) \left[ \frac{1}{b_m^2} \ln\left(1+ \frac{b_m}{\tau}\right) - \frac{1}{b_m(\tau+b_m)} \right ] \frac{\partial b_m}{\partial Y_k} \nonumber \\&+ \frac{a_m}{(\tau+b_m)^2} \frac{\partial b_m}{\partial Y_k} - \frac{1}{\tau+b_m} \frac{\partial a_m}{\partial Y_k} + 1 / W_k \frac{R T b_m}{\tau-b_m}\\&+\sum_i \frac{Y_i}{W_i} R T \left( \frac{1}{\tau -b_m} + \frac{b_m}{(\tau-b_m)^2} \right) \frac{ \partial b_m}{\partial Y_k}\end{split}\]
+
+\[\begin{split}\frac{\partial p}{\partial Y_k} &= R T \frac{1}{W_k} \frac{1}{\tau - b_m} - \frac{\partial a_m}{\partial Y_k} \frac{1}{\tau(\tau + b_m)} \\&+\left(R T \sum \frac{Y_i}{W_i} \frac{1}{(\tau - b_m)^2} + \frac{a_m}{\tau(\tau + b_m)^2} \right ) \frac{\partial b_m}{\partial Y_k}\end{split}\]
+
+
+

Chemical potential

+

The chemical potentials are the derivative of the free energy with respect to composition. Here the free energy f` is given by

+
+\[\begin{split}f &= \sum_i Y_i (e_i^{id} - T s_i^{id,*}) + \sum_i \frac{Y_i R T}{W_i} ln (\frac{Y_i R T}{W_i \tau p^{st}}) \nonumber \\ &+ \sum_i \frac{Y_i R T}{W_i} ln (\frac{\tau}{\tau-b_m}) - a_m \frac{1}{b_m}ln (1+ \frac{b_m}{\tau}) \nonumber \\ &= \sum_i Y_i (e_i^{id} - T s_i^{id,*}) + \sum_i \frac{Y_i R T}{W_i} ln (\frac{Y_i R T}{W_i (\tau-b_m) p^{st}} )- a_m \frac{1}{b_m} ln (1+ \frac{b_m}{\tau}) \nonumber\end{split}\]
+

Then

+
+\[\begin{split}\mu_k &= \frac{\partial f}{\partial Y_k} = e_k^{id} - T s_k^{id,*} + \frac{RT}{W_k} ln (\frac{Y_k R T}{W_k (\tau-b_m) p^{st}}) + \frac{RT}{W_k} + \frac{RT}{\bar{W}} \frac{1}{\tau-b_m} \frac {\partial b_m}{\partial Y_k} \nonumber \\ +&- \frac{1}{b_m} ln(1 + \frac{b_m}{\tau}) \frac{\partial a_m}{\partial Y_k}+ \frac{a_m}{b_m^2} ln(1 + \frac{b_m}{\tau}) \frac{\partial b_m}{\partial Y_k}- \frac{a_m}{b_m} \frac{1}{\tau+b_m} \frac{\partial b_m}{\partial Y_k}\end{split}\]
+
+
+

Other primitive variable derivatives

+

The Godunov (FV) algorithm also needs some derivatives to express source terms in terms of primitive variables. In particular one needs

+
+\[\left . \frac{\partial p}{\partial \rho} \right|_{e,Y} =-\tau^2 \left( \frac{\partial p}{\partial \tau}- \frac {\frac{\partial e}{\partial \tau}} {\frac{\partial e}{\partial T}} \frac{\partial p}{\partial T} \right )\]
+

and

+
+\[\left . \frac{\partial p}{\partial e} \right|_{\rho,Y} = \frac{1}{c_v} \frac{\partial p}{\partial T}\]
+

All of the terms needed to evaluate this quantity are known except for

+
+\[\frac{\partial e}{\partial \tau} = \frac{1}{\tau ( \tau + b_m)} \left( a_m - T \frac{\partial a_m}{\partial T} \right) \;\; .\]
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/GettingStarted.html b/GettingStarted.html new file mode 100644 index 000000000..7ff38cf09 --- /dev/null +++ b/GettingStarted.html @@ -0,0 +1,215 @@ + + + + + + + PelePhysics Quickstart — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

PelePhysics Quickstart

+

Greetings impatient user. As a word of caution, this documentation is in progress. Some parts of the code remain undocumented, +and some parts of the documentation are out of data. If you are confused by something you read here, or otherwise +need help with PelePhysics, the best course of action is to open a Discussion on the GitHub page, +so the development team and other users can help.

+
    +
  • If you are a complete beginner, I urge you to carefully read the two following chapters Obtaining PelePhysics and Dependencies, to properly set-up your working environment.

  • +
  • If you are familiar with PelePhysics, have it installed already and would simply like to know which chemistry-related keywords and/or environment variables to set in your various input files to perform a simulation with one of the codes available in the PeleSuite, then I invite you to directly skip to section Activating the different CVODE solver options via the input files.

  • +
  • If you are in a hurry but still would like more context, visit section Introduction to be referred to portions of this document that are of interest to you.

  • +
+
+

Obtaining PelePhysics

+

PelePhysics is primarily intended as a library for use in the other Pele codes, and is automatically downloaded as +a submodule of both PeleC and PeleLMeX. However, it can also be used as a stand-alone solver for chemical reactions and thermodynamic properties, +or as a library for other codes. Instructions for how to obtain PelePhysics for these purposes are provided here.

+

First, make sure that “Git” is installed on your machine—we recommend version 1.7.x or higher. Then…

+
    +
  1. Clone the PelePhysics repository and its submodules:

    +
    git clone --recursive https://github.com/AMReX-Combustion/PelePhysics.git
    +
    +
    +
  2. +
+
+

This will create a PelePhysics directory on your machine. The --recursive option ensures that the required Dependencies are also downloaded to the +PelePhysics/Submodules directory. Set the environment variable PELE_PHYSICS_HOME to point to the location of this folder (export PELE_PHYSICS_HOME=$(pwd)/PelePhysics)

+
+
    +
  1. Periodically update the repository and its dependencies by typing git pull && git submodule update within the repository.

  2. +
+
+
+

Dependencies

+

PelePhysics has two required dependencies: AMReX and SUNDIALS. +These dependencies are shipped with PelePhysics as git submodules and the proper versions are cloned to the PelePhysics/Submodules/ directory automatically when +doing the recursive git clone described in Obtaining PelePhysics. Users also have the option to download their own versions of these dependencies elsewhere on their machine, in which case +the paths to these libraries must be specified by exporting AMREX_HOME and SUNDIALS_HOME environment variables or defining these variables in +the GNUmakefile when building.

+
    +
  1. AMReX is a library that provides data structures and methods for operating on data in the context of +block-structured adaptive mesh refinement that are used throughout the Pele suite of codes.

  2. +
  3. SUNDIALS is a library of differential and algebraic equation solvers that is used by PelePhysics +primarily for its CVODE package for implicit solution of stiff ODE systems. CVODE is used for integration of stiff chemical reaction systems in PelePhysics.

  4. +
+

PelePhysics has two optional dependencies: SuiteSparse and MAGMA. +These dependencies are not shipped with PelePhysics by default, but the proper versions are automatically downloaded if needed during the building +process (Building and Running Test Cases). Both of these dependencies are libraries that aid in solving the linear systems that arise during implicit integration of a chemical system using CVODE. +There are several other options available for solvers within CVODE, so these libraries are not strictly required, but they may enable options that +lead to better performance on certain computing architectures.

+
    +
  1. SuiteSparse is a suite of Sparse Matrix software that is very handy when dealing with big kinetic mechanisms (the Jacobian of which are usually very sparse). +In such a case, CVODE can make use of the KLU library, which is part of SuiteSparse, to perform sparse linear algebra. +Documentation and further information can be found on SuiteSparse website.

  2. +
  3. MAGMA is a collection of linear algebra libraries for heterogeneous computing.

  4. +
+
+
+

Building and Running Test Cases

+

PelePhysics has several short programs that are used to test its various capabilities, located in the Testing/Exec directory. For example, +we will consider the ReactEval case, which tests the chemical reaction integration capability.

+
cd ${PELE_PHYSICS_HOME}/Testing/Exec/ReactEval
+
+
+

The GNUmakefile in this directory specifies several key build options, like the compiler (COMP) and whether it will be a debug (DEBUG) build.

+

First, build the necessary dependencies. SUNDIALS is always built. +SuiteSparse is downloaded and built if PELE_USE_KLU = TRUE is specified in the GNUmakefile. +MAGMA is downloaded and built if PELE_USE_MAGMA = TRUE is specified in the GNUmakefile. +All dependencies are installed in the ${PELE_PHYSICS_HOME}/ThirdParty directory. For a given set of +compile-time options, this step only needs to be done once, but it needs to be redone whenever compile-time +options are changed

+
make TPL
+
+
+

Now, build the ReactEval executable (the -j 4 option specified to compile in parallel on 4 processors):

+
make -j 4
+
+
+

To run the program, execute:

+
./Pele3d.gnu.ex inputs.3d-regt_GPU
+
+
+

If you need to clean your build, you can run

+
make TPLrealclean && make realclean
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Introduction.html b/Introduction.html new file mode 100644 index 000000000..8127904f2 --- /dev/null +++ b/Introduction.html @@ -0,0 +1,197 @@ + + + + + + + Introduction — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Introduction

+
+

Objectives and State-Of-The-Art

+

What we will call the PeleSuite is currently composed of 3 separate codes:

+
    +
  • PelePhysics is a repository of physics databases and implementation code for use within the other Pele codes. In particular, the choice of chemistry and transport models as well as associated functions and capabilities are managed in PelePhysics.

  • +
  • PeleLM is an adaptive-mesh Low-Mach number hydrodynamics code for reacting flows. It has a sibling, PeleLMeX, that solves for the same type of flow using a subtly different numerical approach.

  • +
  • PeleC is an adaptive-mesh compressible hydrodynamics code for reacting flows.

  • +
+

All three codes rely on AMReX, which is a software frameworks that provides the data structure and enable massive parallelization.

+ + + + + +

a

+

PelePhysics (as well as the ChemDriver object of PeleLM ) used to rely upon DVODE [VODE1989] +to perform the chemistry integration, no matter the problem at hand. +DVODE is a very robust, but slightly outdated, variable-coefficient Ordinary Differential Equation (ODE) solver written in Fortran 77. +At its core, it uses a direct dense linear solver. DVODE is very efficient in the resolution of small stiff systems +of equations but can become prohibitively expensive when dealing with bigger systems of equations, such as those frequently encountered in combustion systems.

+

In recent years, the Sundials team at LLNL [LLNL2005] has been involved in the active development of a modern, +C++ version, of DVODE called CVODE. +CVODE implements the same functionalities as those available in DVODE, but offers much more flexibility through +its user-friendly set of interface routines. Additionally, other linear solvers are available, +such as iterative or sparse solvers which can prove to be very efficient in handling “larger” systems of equations.

+

The objective of this user-guide is to document the CVODE-based chemistry integration implemented in PelePhysics. Although it is possible to use CVODE in PeleC, the following is mainly intended for PeleLM users. This user-guide will cover:

+
    +
  • ODE equations (reactor type)

  • +
  • Default settings (tolerances/order/…)

  • +
  • Linear solvers available –along with examples of performance

  • +
  • Setting-up a PelePhysics test case

  • +
  • +
+
+
+

How to naviguate this documentation

+

This section provides a short overview of the chemistry-related features of PelePhysics. For an in-depth discussion, relevant references to specific sections of this manuscript are given.

+
    +
  • In PelePhysics, the user can select between two different reactor types. +The first type is a constant volume reactor, were the choice of fixed variables are the internal energy and the density, +to comply with PeleC transported variables. This reproduces what was originally +implemented with DVODE in PelePhysics. +A second reactor type formulated in terms of enthalpy and density has been put in place, to comply with PeleLM. +Both reactors are available in DVODE (in fortran 90) and CVODE (in cpp). +See sections The different reactors for additional details, +and Activating the different CVODE solver options via the input files to see how to activate one or the other via the input files.

  • +
  • With both reactors, it is possible to use an Analytical Jacobian (depending upon the choice of linear solver, see section Linear Algebra.)

  • +
  • Three different types of linear solvers are implemented, see section Linear Algebra for additional details, and Activating the different CVODE solver options via the input files to see how to make a selection:

    +
    +
      +
    • a dense direct solver – with or without Analytical Jacobian

    • +
    • a sparse direct solver (requires the KLU library) – always requires an Analytical Jacobian

    • +
    • a couple of sparse iterative solvers from the GMRES family – preconditioned or not

    • +
    +
    +
  • +
  • Regression testings have been put in place in PelePhysics to test the CVODE integration. See section Validation of the CV reactor implementation in CVODE (with CANTERA) for validations, and section The ReactEval_C test case with CVODE in details for a step-by-step example.

  • +
  • A CVODE version running on GPU is also technically available but the documentation is a WIP. The interested user can +contact code developers for additional information

  • +
  • PelePhysics uses an automatic chemistry-related routine generator: +CEPTR. CEPTR is part of the sources of PelePhysics. With +CEPTR, a unique chemistry file is generated for a specific kinetic +scheme. Instructions to generate your own chemistry files (all you +need are chemistry files in the famous Cantera yaml format) are discussed in section +CEPTR: Chemistry Evaluation for Pele Through Recasting. Note that PelePhysics already offers a large +choice of more than 20 different kinetic schemes.

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/IntroductionToCvode.html b/IntroductionToCvode.html new file mode 100644 index 000000000..b70a06807 --- /dev/null +++ b/IntroductionToCvode.html @@ -0,0 +1,260 @@ + + + + + + + A brief introduction to CVODE — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

A brief introduction to CVODE

+

CVODE is part of a software family called sundials for SUite of Nonlinear and DIfferential / ALgebraic equation Solver [LLNL2005].

+

The version used with PelePhysics for the tests presented in this document is v4.0.2. This does not mean this is the recommended version to link with PelePhysics. Always refer to Dependencies to know which versions of CVODE/SuiteSparse to use !!

+

In the following, details pertaining to the methods implemented in PelePhysics are provided. +The interested user is referred to the very exhaustive CVODE User-guide for more information.

+

Most of this section is adapted from the v4.1.0 Cvode Documentation.

+
+

Numerical methods overview

+

The methods implemented in CVODE are variable-order, variable-step multistep methods, based on formulas of the form

+
+\[\sum_{i=0}^{K_1} \alpha_{n,i} y^{n-i} + h_n \sum_{i=0}^{K_2} \beta_{n,i} \dot{y}^{n-i} = 0\]
+

Here the \(y^n\) are computed approximations to \(y(t_n)\), and \(h_n = t_n-t_{n-1}\) is the step size. +For stiff problems, CVODE includes the Backward Differentiation Formulas (BDF) in so-called fixed-leading coefficient (FLC) form, +given by \(K_1=q\) and \(K_2= 0\), with order \(q\) varying between 1 and 5. The coefficients are uniquely determined by the method type, +its order, the recent history of the step sizes, and the normalization \(\alpha_{n,0}=-1\) [BYRNE1975], [JAC1980].

+

A nonlinear system must be solved (approximately) at each integration step. This nonlinear system can be formulated as a root-finding problem

+
+\[F(y^{n}) = y^n - h_n \beta_{n,0} f(t_n,y^{n}) - a_n = 0\]
+

where \(a_n = \sum_{i>0} (\alpha_{n,i} y^{n-i} + h_n\beta_{n,i} \dot{y}^{n-i})\). CVODE provides several non-linear solver choices. +By default, CVODE solves this problem with a Newton iteration, which requires the solution of linear systems

+
+(1)\[M[y^{n(m+1)} - y^{n(m)}] = -F(y^{n(m)})\]
+

in which

+
+\[M \approx I-\gamma J, \; \; \; J = \frac{\partial f}{ \partial y}, \;\;\; and \;\;\; \gamma = h_n \beta_{n,0}\]
+
+
+

Linear Algebra

+

To find the solution of the linear system (1); CVODE provides several linear solver choices. +The linear solver modules distributed with Sundials are organized in two families, a direct family comprising direct linear solvers +for dense, banded, or sparse matrices, and a spils family comprising scaled preconditioned iterative (Krylov) linear solvers. +The solvers offered through these modules that are of interest to us are:

+
    +
  • a dense direct solver

  • +
  • a sparse direct solver interface using the KLU sparse solver library

  • +
  • SPGMR, a scaled -possibly preconditioned- GMRES (Generalized Minimal Residual method) solver [BROWN1990]

  • +
+

When using a dense direct solver, the user has the option to specify an Analytical Jacobian. +If none is provided, a difference quotients is performed. When a sparse direct solver is employed however, +the user must specify an analytical Jacobian. All of these options have been enabled in PelePhysics.

+

For large stiff systems, where direct methods are often not feasible, the combination of a BDF integrator and a preconditioned Krylov method +yields a powerful tool. In this case, the linear solve is matrix-free, and the default Newton iteration is an +Inexact Newton iteration, in which \(M\) is applied with matrix-vector products \(Jv\) obtained by either difference quotients +or a user-supplied routine. In PelePhysics, it is possible to use either a non-preconditioned or a preconditioned GMRES solver. +In the latter case, the preconditioner can be either specified in a dense or sparse format (if the KLU library is linked to CVODE), +and it is provided in the form of a Jacobian approximation, based on the work of [McNenly2015].

+
+
+

Error control, step-sizing, order determination

+

In the process of controlling errors at various levels, CVODE uses a weighted root-mean-square norm, +denoted \(|| \bullet ||_{WRMS}\), for all error-like quantities. The multiplicative weights used are based +on the current solution and on the relative and absolute tolerances input by the user, namely

+
+\[W_i= \frac{1}{[rtol |y_i|+atol_i]}\]
+

Because \(1/W_i\) represents a tolerance in the component \(y_i\), a vector whose norm is 1 is regarded as small. +In PelePhysics, both these tolerances are fixed to a value of \(1.0e-10\).

+

A critical part of CVODE - making it an ODE solver rather than just an ODE method, is its control +of the local error. At every step, the local error is estimated and required to satisfy tolerance conditions, +and the step is redone with reduced step size whenever that error test fails. +Note that in PelePhysics, the first time step is always forced to \(1.0e-9\).

+

In addition to adjusting the step size to meet the local error test, CVODE periodically adjusts the order, +with the goal of maximizing the step size. The integration starts out at order 1 and varies the order dynamically after that. +The basic idea is to pick the order \(q\) for which a polynomial of order \(q\) best fits the discrete data involved +in the multistep method. In PelePhysics, the maximum order is limited to 2 for stability reasons.

+

The various algorithmic features of CVODE are inherited from VODE and VODPK, and are documented in [VODE1989] and [BROWN1990]. +They are also summarized in the CVODE User-guide as well as in [LLNL2005].

+
+
+[LLNL2005] +(1,2) +
    +
    1. +
    2. Hindmarsh, P. N. Brown, K. E. Grant, S. L. Lee, R. Serban, D. E. Shumaker, and C. S. Woodward. SUNDIALS: Suite of nonlinear and differential/algebraic-equation solvers. ACM Transactions on Mathematical Software (TOMS), 31(3):363-396, 2005.

    3. +
    +
  1. +
+
+
+[BYRNE1975] +
    +
    1. +
    2. Byrne, A. C. Hindmarsh. A polyalgorithm for the numerical solution of ordinary differential equations. ACM Transactions on Mathematical Software (TOMS), 1(1):71-96, 1975.

    3. +
    +
  1. +
+
+
+[JAC1980] +
    +
  1. R Jackson and R. Sacks-Davis. An alternative implementation of variable step-size multistep formulas for stiff odes. ACM Transactions on Mathematical Software (TOMS), 6(3):295–318, 1980.

  2. +
+
+
+[BROWN1990] +(1,2) +
    +
    1. +
    2. Brown and Y. Saad. Hybrid krylov methods for nonlinear systems of equations. SIAM Journal on Scientific and Statistical Computing, 11(3):450–481, 1990.

    3. +
    +
  1. +
+
+
+[McNenly2015] +
    +
    1. +
    2. McNenly, R. A. Whitesides, and D. L. Flowers. Faster solvers for large kinetic mechanisms using adaptive preconditioners. Proceedings of the Combustion Institute, 35(1):581–587, 2015.

    3. +
    +
  1. +
+
+
+[VODE1989] +
    +
    1. +
    2. Brown, G. D. Byrne, and A. C. Hindmarsh. VODE, a variable-coefficient ODE solver. SIAM journal on scientific and statistical computing, 10(5):1038-1051, 1989.

    3. +
    +
  1. +
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/QSS.html b/QSS.html new file mode 100644 index 000000000..57fc7f40d --- /dev/null +++ b/QSS.html @@ -0,0 +1,274 @@ + + + + + + + Analytically reduced chemistry via quasi-steady state (QSS) assumption in PelePhysics — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Analytically reduced chemistry via quasi-steady state (QSS) assumption in PelePhysics

+
+

The QSS assumption

+

Given a detailed chemical mechanism, some species can sometimes be assumed to be in a quasi-steady state (QSS). +Formally, if species \(A\) is assumed to be in a QSS then

+
+\[\frac{\partial [A]}{\partial t} = 0,\]
+

where \([A]\) is the molar concentration of species \(A\). +If the set of QSS species is judiciously chosen, macroscopic quantities of interest such as ignition delay or laminar flame speed are only mildly affected by the QSS assumption [DRG2005].

+
+
+

The advantage of the QSS assumption

+

Using the elementary reactions of the chemical mechanism, it is possible to write a set of algebraic equations that relate QSS species to non-QSS species. In turn, it is not necessary to transport the QSS species in the flow solver, as their concentration can be directly obtained from the non-QSS species.

+

In addition, QSS species are typically species that induce stiffness in the chemical mechanism since they evolve on scales different that the non-QSS species.

+
+
+

From non-QSS species to QSS species concentration

+

The set of algebraic equations that result from the QSS assumption does not always easily result in a simple algebraic relation between a given QSS species and all the non-QSS species. To do this, it is necessary to apply some form of linearization to the reactions involved [SYS2006]. In addition, even in the presence of linear relations, QSS species may depend on one another. The following figure shows the relation graph between the QSS species of a reduced \(N-C_{12}H_{26}\) mechanism [ND2018]. The arrows indicate that a QSS species concentration depends on another QSS species concentration. It can also be seen that dependency groups exist among the QSS species. In PelePhysics it is possible to deduce invert analytically the linear system of equations given an arbitrary relation graph.

+
+Directed graph of dependencies between QSS species +
+

4 Relation graph between QSS species for N-dodecane mechanism [ND2018]

+
+
+
+
+

Linearizing the set of equations

+

In general, the QSS assumption results in a set of equations that are non-linearly coupled making it difficult to invert the system. The non-linear relations can arise if two or more QSS-species are on the same side of an elementary reaction, or if the stoichiometric coefficient of a QSS-species is not equal to one. Below, the relation graph between the QSS species plotted above is expanded with dots that denote reactions that relate QSS-species. Dots or species are colored in red if they are involved in a quadratic coupling.

+
+Graph of dependencies between QSS species augmented with reactions. +
+

5 Graph of dependencies between QSS species for N-dodecane mechanism [ND2018], augmented with reactions. Red species or dots denote species and reactions involved in quadratic coupling.

+
+
+

From here, it is necessary to eliminate the quadratic coupling to linearize the set of algebraic equations that result from the QSS assumption. Three methods can be envisioned: either one relaxes the QSS assumption by reducing the set of QSS species (Method 1) or one can eliminate the reactions that induce quadratic coupling. In case reactions are reversible, it can happen that either the forward or the backward reaction induces the quadratic coupling. Either one can remove both the forward and the backward reaction (Method 2) or remove either the backward or the forward reaction (Method 3).

+

All three methods are available in PelePhysics. By default, Method 3 is activated as it is computationally efficient and accurate (as will be shown below). Method 1 is the most accurate and Method 2 is the most computationally efficient in our experience. Given that each method has its advantage, we decided to allow the user to choose either one according to his/her needs.

+
+
+

Validation

+

The three linearization methods are validated against the skeletal \(N-C_{12}H_{26}\) [SKEL2017]. Using 343 0D calculation that span the range of applicability of the QSS assumption (\(\phi = [0.5, 2.0], p=[1atm, 50atm], T=[800K, 1600K]\)), the ignition delay is computed using the skeletal mechanism (SK53) and each one of the three linearization methods for the QSS mechanism (RedXX). The left plot shows the correlation between the ignition delay from the skeletal mechanism and the reduced version. The statistics of the relative error between the reduced and the skeletal mechanism are shown in the title of that plot. The right plot shows the ignition delay values at high-pressure conditions only.

+
+Validation of linearization method +
+

6 Left: Scatter plot of the ignition delay measured with the QSS mechanism linearized and the skeletal mechanism. +Right: Ignition delays measured for the skeletal mechanism and QSS mechanism linearized at high-pressure conditions. +Top: Method 1. Middle: Method 2. Bottom: Method 3.

+
+
+
+
+

Analytical Jacobian

+

In several computational experiments, using analytical Jacobians was found to provide better stability or efficiency compared with finite difference approximation or numerical inversion (see also fig:qss_integrator). +Compared with non-QSS mechanisms, analytical Jacobians need to reflect the dependence of each QSS species on non-QSS species. However, QSS species may depend on an ensemble of other non-QSS species and therefore ensemble of reactions. Therefore, analytical Jacobian cannot be constructed by sequentially adding the contribution of each reaction. This significantly complicates the analytical jacobian generation. Failure to include the dependence of QSS species with respect to non-QSS species typically results in wrong ignition profiles, unless very small timesteps are used, as seen in figure fig:qss_aj.

+
+ +
+

7 Temperature of a 0D reactor at constant pressure for NC12H26. Initial temperature is 600K, initial molar fraction of O2 is 0.7 and initial molar fraction of fuel is 0.3. +Left: Results without inclusion of dependence of QSS species with respect to non-QSS species. +Right: Result with inclusion of dependence of QSS species with respect to non-QSS species.

+
+
+

To ease the implementation of analytical Jacobian in presence of QSS species, a symbolic approach is used to construct the analytical Jacobian. This strategy has the advantage of not requiring complex logic, and being flexible and readable for future development. For the last row of the Jacobian (partial difference of reaction rate with respect to temperature), finite difference is used since perturbations in temperature are less susceptible to numerical errors than perturbations in species concentrations. During the construction of the reaction rates, the operations printed to file are recorded symbolically using the sympy and symengine library [SYMPY]. For computational efficiency during the symbolic differentiation, the chain-rules terms are computed and the final expressions are computed and assembled by chain-ruling using logic internal to CEPTR rather than sympy. We have found that this speeds up the Jacobian construction cost by a factor 10.

+

To activate the use of symbolic jacobian, one needs to pass the flag --qss_symbolic_jacobian to CEPTR.

+

Printing the Jacobian terms one by one is not possible since the expressions that include QSS species are typically very large. Instead, the expressions are reduced via common sub-expression precomputing that are later used in each term of the Jacobian. The number of subexpressions may be orders of magnitude larger than the number of Jacobian entries which can be problematic if the computational architecture has limited memory.

+

Several formatting strategies have been implemented to mitigate the memory footprint of the symbolic Jacobian. They can be adjusted by providing a .toml file to CEPTR via the qss_format_input flag. A model input file is provided in the Tutorials section of this documentation. A model execution script for generating a mechanism for dodecane_lu_qss is available under the Tutorials section of this documentation.

+

The formatting options are the following

+
    +
  • +
    hformat (string)
      +
    • cpu will print intermediate variables used for chainruling. This gives a “readable” version of the Jacobian entries, albeit memory consuming.

    • +
    • gpu will not print intermediate variables used for chainruling, and instead will replace them directly in the Jacobian entries. This gives a less readable version of the Jacobian, but more memory efficient.

    • +
    +
    +
    +
  • +
  • remove_1 (boolean) will replace expressions of the type 1.0 * xxx into xxx.

  • +
  • remove_pow (boolean) will convert expressions of the type pow(xxx,n) into multiplications or division. The conversion occurs for n<=3 and n>=-3 consistent with optimCuda

  • +
  • remove_pow10 (boolean) will convert expressions of the type pow(10,xxx) into exp(ln(10)*xxx), consistent with optimCuda

  • +
  • min_op_count (integer) counts number operations used to construct each common subexpression and replace the common subexpression if the number of operations is less or equal to n

  • +
  • min_op_count_all (integer) is similar to min_op_count but also counts how many times that common subexpression is used later. The meaning of n is different than for min_op_count as it refers to how many more operations will be done if the common subexpression is eliminated. This option should be preferred to min_op_count as it tends to only marginally increase the file size (therefore compile time), while still being memory efficient.

  • +
  • gradual_op_count (boolean) is useful if min_op_count or min_op_count_all are active. It loops from 1 to n and gradually eliminate the common subexpressions. This has the advantage of ensuring that the memory footprint is strictly monotonically decreasing as n is increased.

  • +
  • store_in_jacobian (boolean) will use the Jacobian array as a temporary space to store intermediate variables. In particular, the last row of the Jacobian (dependence with respect to temperature) is done by finite difference which requires storing intermediate variables (production rate, forward and backward reactions). When the option is active, the productionRate function used to compute the finite difference is replaced with a productionRate_light functions where references to different parts of the Jacobian are used in place of allocating new arrays.

  • +
  • round_decimals (boolean) will round floats printed by sympy when possible to minimize character count in the mechanism.H file.

  • +
  • recycle_cse (boolean) will reuse subexpressions that are not used later to avoid declaring new temporary reals.

  • +
  • remove_single_symbols_cse (boolean) will remove common subexpressions that are made of 1 operation and 1 symbol. Those common subexpressions are typically -xxx and may not appear as worth replacing because they save 1 operations and are reused multiple times. However, when replaced in the later expressions, the - operations typically disappear or is merged into another operations which actually does not increase the total number of operations.

  • +
+

The analytical Jacobian for QSS mechanisms is typically more accurate and stable than GMRES, and is on par with the finite difference Jacobian of CVODE as seen in fig:qss_integrator

+
+ +
+

8 Temperature of a 0D reactor at constant pressure for NC12H26. Initial temperature is 600K, initial molar fraction of O2 is 0.7 and initial molar fraction of fuel is 0.3. Results are shown for finite difference jacobian (red thick line), analytical jacobian (black line) and GMRES (crosses) using the same tolerances.

+
+
+

In terms of speed, the analytical Jacobian 0D reactor is faster on CPU than finite difference Jacobian and GMRES. For the piston bowl challenge problem, the analytical Jacobian relative speed depends on the prevalence of chemical reactions. At some points, the AJ is slower than GMRES with PeleC, at others, AJ is faster. In PeleLM cases, AJ was found to be faster than GMRES. Further optimization and tests are still ongoing.

+
+
+

Using the Analytical Jacobian

+

To use the analytic Jacobian QSS mechanisms in a Pele run, one must specify the correct solve_type. The choice of the solve_type will determine whether or not the analytic Jacobian is used. With CUDA, both magma_direct and sparse_direct will use the analytic Jacobian, while on HIP only magma_direct will trigger the use of the analytic Jacobian parts.

+
+
+[DRG2005] +
    +
  1. Lu, C. K. Law, A directed relation graph method for mechanism reduction, Proceedings of the combustion institute, 30(1):1333-1341, 2005.

  2. +
+
+
+[SYS2006] +
    +
  1. Lu, C. K. Law, Systematic approach to obtain analytic solutions of quasi steady state species in reduced mechanisms, The Journal of Physical Chemistry A, 110(49):13202-13208, 2006.

  2. +
+
+
+[ND2018] +(1,2,3) +
    +
  1. Borghesi, A. Krisman, T. Lu, J. H. Chen, Direct numerical simulation of a temporally evolving air/n-dodecane jet at low-temperature diesel-relevant conditions, 195:183-202, 2018.

  2. +
+
+
+[SKEL2017] +
    +
  1. Yao, Y. Pei, B. J. Zhong, S. Som, T. Lu, K. H. Luo, A compact skeletal mechanism for n-dodecane with optimized semi-global ! low-temperature chemistry for diesel engine simulations, 191:339-349, 2017.

  2. +
+
+
+[SYMPY] +
    +
  1. Meurer, C. P. Smith, M. Paprocki, O. v{C}ert'{i}k, S. B. Kirpichev, M. Rocklin, A. Kumar, S. Ivanov, J. K. Moore, S. Singh, T. Rathnayake, S. Vig, B. E. Granger, R. P. Muller, F. Bonazzi, H. Gupta, S. Vats, F. Johansson, F. Pedregosa, M. J. Curry, A. R. Terrel, S. Rouv{c}ka, A. Saboo, I. Fernando, S. Kulal, R. Cimrman, A. Scopatz, SymPy: symbolic computing in Python, 3:e103, 2017.

  2. +
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Soot.html b/Soot.html new file mode 100644 index 000000000..d48670825 --- /dev/null +++ b/Soot.html @@ -0,0 +1,170 @@ + + + + + + + Soot — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Soot

+
+

Soot Equations

+

Soot formation, growth, and oxidation is modeled using the hybrid-method of moments (HMOM) model developed by Mueller et al. [1]. This approach combines the numerical ease of the method of moments with interpolative closure (MOMIC) with the ability to capture the bimodal nature of the soot number density function (NDF) provided by the direct quadrature method of moments (DQMOM). \(M_{x,y}\) is the moment of the soot NDF, where \(x\) is the order for volume and \(y\) for surface area; these terms are modeled according to

+
+\[M_{x,y} = N_0 V_0^x S_0^y + \exp{\left(\sum_{r=0}^R \sum_{k = 0}^r a_{r,k} x^k y^{r-k}\right)},\]
+

where \(R\) is the order of the polynomial interpolation, \(a_{r,k}\) are the interpolation coefficients, \(N_0\) is the weight of the delta function, and \(V_0\) and \(S_0\) are the volume and surface area of the nucleated spherical soot particles, respectively. The location of the delta function is fixed at coordinates \(V_0\) and \(S_0\) and assumed to be equal to the nucleated particle size. +The nucleated particle volume and surface area are fixed according to \(V_0 = 2 W_C C_{\rm{dimer}} / \rho_{\rm{soot}}\) and \(S_0 = (36 \pi)^{1/3} V_0^{2/3}\), where \(W_C\) is the molar mass of carbon, \(C_{\rm{dimer}}\) is the average number of carbon atoms per dimer, and \(\rho_{\rm{soot}}\) is the density of soot (\(\rho_{\rm{soot}} = 1800 {\text{ kg/m}}^3\)). If the first-order polynomial interpolation of the moments (\(R=1\)) is used, the above equation reduces to

+
+\[M_{x,y} = N_0 V_0^x S_0^y + N_L V_L^x S_L^y,\]
+

where \(V_L\) and \(S_L\) are the mean volume and surface area of the second mode (large particles). For first-order polynomial interpolation, four transport equations are solved: \(M_{0,0}\) (number density), \(M_{1,0}\) (volume fraction, also denoted as \(f_v\)), \(M_{0,1}\), and \(N_0\). +The governing equations for the soot moments are [2]

+
+\[\frac{\partial M_{x,y}}{\partial t} + \frac{\partial M_{x,y} \mathbf{u}_g}{\partial \mathbf{X}} = -\frac{\partial \boldsymbol{J}_{M}}{\partial \mathbf{X}} + \dot{M}_{x,y},\]
+

where \(\boldsymbol{J}_{M}\) is the soot mass flux and \(\dot{M}_{x,y}\) is the soot source term. +The current formulation ignores the molecular diffusion and thermophoretic effects of the soot, making the first term of the right-hand side zero.

+

For more details regarding the HMOM model, users are encouraged to consult the references cited.

+
+
+

Soot Flags and Inputs

+
    +
  • In the GNUmakefile, specify USE_SOOT = TRUE and NUM_SOOT_MOMENTS = N where N is the number of moments to be used in the solution, either 3 or 6.

  • +
  • Depending on the gas phase solver, soot solving functionality can be turned on in the input file using pelec.add_soot_src = 1 or peleLM.do_soot_solve = 1.

  • +
  • The chemistry model specified with Chemistry_model = in GNUmakefile must contain the PAH inception species, as well as H2, H, OH, H2O, CO, C2H2, and O2.

  • +
  • A PAH inception species must be provided in the input file using soot.incept_pah =. Currently, only one of three inputs are accepted: A2, A3, or A4; which correspond to naphthalene (C10H8), phenathrene (C14H10), or pyrene (C16H10).

    +
      +
    • If the inception species is named something other than A# in the chemistry model, a different name can be specified using soot.pah_name =. However, soot.incept_pah must be set to A2, A3, or A4.

    • +
    +
  • +
+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Spray.html b/Spray.html new file mode 100644 index 000000000..44b84f0ca --- /dev/null +++ b/Spray.html @@ -0,0 +1,654 @@ + + + + + + + Spray — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Spray

+
+

Spray Equations

+

This section outlines the modeling and mathematics for the spray routines. +Firstly, spray modeling relies on the following assumptions:

+
    +
  • Dilute spray: droplet volume inside an Eulerian cell is much smaller than the volume of the gas phase; the droplets can be modeled as Lagrangian point source terms relative to the Eulerian gas phase

  • +
  • Infinite conductivity model: temperature within a droplet is temporally varying but spatially uniform

  • +
  • One-third rule: the thermophysical properties in the film of an evaporating droplet can be approximated as a weighted average of the state at the droplet surface (weighted as 2/3) and the state of the surrounding gas (weighted as 1/3)

  • +
  • Ideal equilibrium: the liquid and vapor state at the surface of the droplet are in equilibrium

  • +
  • The radiation, Soret, and Dufour effects are neglected

  • +
+

The evaporation models follow the work by Abramzon and Sirignano [2] and the multicomponent evaporation is based on work by Tonini. [1] Details regarding the energy balance are provided in Ge et al. [5]

+

The subscript notation for this section is: \(d\) relates to the liquid droplet, \(v\) relates to the vapor state that is in equilibrium with the liquid and gas phase, \(L\) relates to the liquid phase, and \(g\) relates to the gas phase. The subscript \(r\) relates to the reference state with which to approximate the thermophysical and transport properties. This reference state is assumed to be in the evaporating film that surrounds the droplet state and is approximated as

+
+\[ \begin{align}\begin{aligned}T_r &= T_d + A (T_g - T_d)\\Y_{r,n} &= Y_{v,n} + A (Y_{g,n} - Y_{v,n})\end{aligned}\end{align} \]
+

where \(A = 1/3\) according the the one-third rule. +Additional nomenclature: \(M_n\) is the molar mass of species \(n\), \(\overline{M}\) is the average molar mass of a mixture, \(\mathcal{R}\) is the universal gas constant, \(N_L\) is the number of liquid species, and \(N_s\) is the number of gas phase species. \(Y_n\) and \(\chi_n\) are the mass and molar fractions of species \(n\), respectively. +The user is required to provide a reference temperature for the liquid properties, \(T^*\), the critical temperature for each liquid species, \(T_{c,n}\), the boiling temperature for each liquid species at atmospheric pressure, \(T^*_{b,n}\), the latent heat and liquid specific heat at the reference temperature, \(h_{L,n}(T^*)\) and \(c_{p,L,n}(T^*)\), respectively. +Note: this reference temperature is a constant value for all species and is not related to the reference state denoted by the subscript \(r\).

+

The equations of motion, mass, momentum, and energy for the Lagrangian spray droplet are:

+
+\[ \begin{align}\begin{aligned}\frac{d \mathbf{X}_d}{d t} &= \mathbf{u}_d,\\\frac{d m_d}{d t} &= \sum^{N_L}_{n=0} \dot{m}_n,\\m_d \frac{d Y_{d,n}}{d t} &= \dot{m}_n - Y_{d,n} \frac{d m_d}{d t},\\m_d \frac{d \mathbf{u}_d}{d t} &= \mathbf{F}_d + m_d \mathbf{g},\\m_d c_{p,L} \frac{d T_d}{d t} &= \sum^{N_L}_{n=0} \dot{m}_n h_{L,n}(T_d) + \mathcal{Q}_d.\end{aligned}\end{align} \]
+

where \(\mathbf{X}_d\) is the spatial vector, \(\mathbf{u}_d\) is the velocity vector, \(T_d\) is the droplet temperature, \(m_d\) is the mass of the droplet, \(\mathbf{g}\) is an external body force (like gravity), \(\dot{m}\) is evaporated mass, \(\mathcal{Q}_d\) is the heat transfer between the droplet and the surrounding gas, and \(\mathbf{F}_d\) is the momentum source term. +The density of the liquid mixture, \(\rho_d\), depends on the liquid mass fractions of the dropet, \(Y_{d,n}\),

+
+\[\rho_d = \left( \sum^{N_L}_{n=0} \frac{Y_{d,n}}{\rho_{L,n}} \right)^{-1}\]
+

The droplets are assumed to be spherical with diameter \(d_d\). Therefore, the mass is computed as

+
+\[m_d = \frac{\pi}{6} \rho_d d_d^3\]
+

The procedure is as follows for updating the spray droplet:

+
    +
  1. Interpolate the gas phase state to the droplet location using a trilinear interpolation scheme.

  2. +
  3. Compute the boiling temperature for species \(n\) at the current gas phase pressure using the Clasius-Clapeyron relation

    +
    +\[T_{b,n} = \left(\log\left(\frac{p_{\rm{atm}}}{p_g}\right) \frac{\mathcal{R}}{M_n h_{L,n}(T^*_{b,n})} + \frac{1}{T^*_{b,n}}\right)\]
    +

    The boiling temperature of the droplet is computed as

    +
    +\[T_{d,b} = \sum^{N_L}_{n=0} Y_{d,n} T_{b,n}\]
    +

    Since we only have the latent heat at the reference condition temperature, we estimate the enthalpy at the boiling condition using Watson’s law

    +
    +\[h_{L,n}(T^*_{b,n}) = h_{L,n}(T^*) \left(\frac{T_{c,n} - T^*}{T_{c,n} - T^*_{b,n}} \right)^{-0.38}\]
    +
  4. +
  5. Compute the latent heat of the droplet using

    +
    +\[h_{L,n}(T_d) = h_{g,n}(T_d) - h_{g,n}(T^*) + h_{L,n}(T^*) - c_{p,L,n}(T^*) (T_d - T^*) \,.\]
    +

    and the saturation pressure using either the Clasius-Clapeyron relation

    +
    +\[p_{{\rm{sat}}, n} = p_{\rm{atm}} \exp\left(\frac{h_{L,n}(T_d) M_n}{\mathcal{R}} \left(\frac{1}{T^*_{b,n}} - \frac{1}{T_d}\right)\right)\]
    +

    or the Antoine curve fit

    +
    +\[p_{{\rm{sat}},n} = d 10^{a - b / (T_d + c)}\]
    +
  6. +
  7. Estimate the mass fractions in the vapor state using Raoult’s law

    +
    +\[ \begin{align}\begin{aligned}Y_{v,n} &= \frac{\chi_{v,n} M_n}{\overline{M}_v + \overline{M}_g (1 - \chi_{v,{\rm{sum}}})} \; \forall n \in N_L\\\chi_{v,{\rm{sum}}} &= \sum^{N_L}_{n=0} \chi_{v,n}\\\chi_{v,n} &= \frac{\chi_{d,n} p_{{\rm{sat}},n}}{p_g}\\\chi_{d,n} &= \frac{Y_{d,n}}{M_n}\left(\sum^{N_L}_{k=0} \frac{Y_{d,k}}{M_k}\right)^{-1}\\\overline{M}_v &= \sum^{N_L}_{n=0} \chi_{v,n} M_n\end{aligned}\end{align} \]
    +

    If \(\chi_{g,n} p_g > p_{{\rm{sat}},n}\), then \(\chi_{v,n} = Y_{v,n} = 0\) for that particular species in the equations above, since that means the gas phase is saturated. The mass fractions in the reference state for the fuel are computed using the one-third rule and the remaining reference mass fractions are normalized gas phase mass fractions to ensure they sum to 1

    +
    +\[\begin{split}Y_{r,n} = \left\{\begin{array}{c l} +\displaystyle Y_{v,n} + A (Y_{g,n} - Y_{v,n}) & {\text{If $Y_{v,n} > 0$}}, \\ +\displaystyle\frac{1 - \sum^{N_L}_{k=0} Y_{v,k}}{1 - \sum^{N_L}_{k=0} Y_{g,k}} Y_{g,n} & {\text{Otherwise}}. +\end{array}\right. \; \forall n \in N_s.\end{split}\]
    +
  8. +
  9. The average molar mass, specific heat, and density of the reference state in the gas film are computed as

    +
    +\[ \begin{align}\begin{aligned}\overline{M}_r &= \left(\sum^{N_s}_{n=0} \frac{Y_{r,n}}{M_n}\right)^{-1},\\c_{p,r} &= \sum^{N_s}_{n=0} Y_{s,n} c_{p,g,n}(T_r),\\\rho_r &= \frac{\overline{M}_r p_g}{\mathcal{R} T_r}.\end{aligned}\end{align} \]
    +
  10. +
  11. Transport properties are computed using the reference state: dynamic viscosity, \(\mu_r\), thermal conductivity, \(\lambda_r\), and mass diffusion coefficient for species \(n\), \(D_{r,n}\).

  12. +
  13. It is important to note that PelePhysics provides mixture averaged mass diffusion coefficient \(\overline{(\rho D)}_{r,n}\), which is converted into the binary mass diffusion coefficient using

    +
    +\[(\rho D)_{r,n} = \overline{(\rho D)}_{r,n} \overline{M}_r / M_n.\]
    +

    Mass diffusion coefficient is then normalized by the total fuel vapor molar fraction

    +
    +\[(\rho D)^*_{r,n} = \frac{\chi_{v,n} (\rho D)_{r,n}}{\chi_{v,{\rm{sum}}}} \; \forall n \in N_L\]
    +

    and the total is

    +
    +\[(\rho D)_r = \sum_{n=0}^{N_L} (\rho D)_{r,n}^*\]
    +
  14. +
  15. The momentum source is a function of the drag force

    +
    +\[\mathbf{F}_d = \frac{1}{2} \rho_r C_D A_d \left\|\Delta \mathbf{u}\right\| \Delta \mathbf{u}\]
    +

    where \(\Delta \mathbf{u} = \mathbf{u}_g - \mathbf{u}_d\), \(A_d = \pi d_d^2/4\) is the frontal area of the droplet, and \(C_D\) is the drag coefficient for a sphere, which is estimated using the standard drag curve for an immersed sphere

    +
    +\[\begin{split}C_D = \frac{24}{{\rm{Re}}_d}\left\{\begin{array}{c l} +1 & {\text{If Re$_d$ < 1}}, \\ +\displaystyle 1 + \frac{{\rm{Re}}^{2/3}_d}{6} & {\text{Otherwise}}. +\end{array}\right.\end{split}\]
    +

    The droplet Reynolds number is defined as

    +
    +\[{\rm{Re}}_d = \frac{\rho_r d_d \left\|\Delta \mathbf{u}\right\|}{\mu_r}\]
    +
  16. +
  17. The mass source term is modeled according to Abramzon and Sirignano (1989). The following non-dimensional numbers and factors are used:

    +
    +\[ \begin{align}\begin{aligned}F(B) &= (1 + B)^{0.7}\frac{\log(1 + B)}{B}\\F_2 &= \max(1, \min(400, {\rm{Re}}_d)^{0.077})\\{\rm{Pr}}_r &= \frac{\mu_r c_{p,r}}{\lambda_r}\\{\rm{Sc}}_r &= \frac{\mu_r}{(\rho D)_r}\\{\rm{Sh}}_0 &= 1 + (1 + {\rm{Re}}_d {\rm{Sc}}_r)^{1/3} F_2\\{\rm{Nu}}_0 &= 1 + (1 + {\rm{Re}}_d {\rm{Pr}}_r)^{1/3} F_2\\{\rm{Sh}}^* &= 2 + \frac{{\rm{Sh}}_0 - 2}{F(B_M)}\\{\rm{Nu}}^* &= 2 + \frac{{\rm{Nu}}_0 - 2}{F(B_T)}\end{aligned}\end{align} \]
    +
      +
    • The Spalding numbers for mass transfer, \(B_M\), and heat transfer, \(B_T\), are computed using

      +
      +\[ \begin{align}\begin{aligned}B_M &= \displaystyle\frac{\sum^{N_L}_{n=0} Y_{v,n} - \sum^{N_L}_{n=0} Y_{g,n}}{1 - \sum^{N_L}_{n=0} Y_{v,n}}\\B_T &= \left(1 + B_M\right)^{\phi} - 1\end{aligned}\end{align} \]
      +

      where

      +
      +\[\phi = \frac{c_{p,r} (\rho D)_r {\rm{Sh}}^*}{\lambda_r {\rm{Nu}}^*}\]
      +

      Note the dependence of \({\rm{Nu}}^*\) on \(B_T\) means an iterative scheme is required to solve for both. The droplet vaporization rate and heat transfer become

      +
      +\[ \begin{align}\begin{aligned}\dot{m}_n &= -\pi (\rho D)_{r,n}^* d_d {\rm{Sh}}^* \log(1 + B_M). \; \forall n \in N_L\\\mathcal{Q}_d &= \pi \lambda_r d_d (T_g - T_d) {\rm{Nu}}^* \frac{\log(1 + B_T)}{B_T}\end{aligned}\end{align} \]
      +
    • +
    • If the gas phase is saturated for all liquid species, the equations for heat and mass transfer become

      +
      +\[ \begin{align}\begin{aligned}\dot{m}_n &= 0\\\mathcal{Q}_d &= \pi \lambda_r d_d (T_g - T_d) {\rm{Nu}}_0\end{aligned}\end{align} \]
      +
    • +
    +
  18. +
  19. To alleviate conservation issues at AMR interfaces, each parcel only contributes to the gas phase source term of the cell containing it. The gas phase source terms for a single parcel to the cell are

    +
    +
    +\[ \begin{align}\begin{aligned}S_{\rho} &= \mathcal{C} \sum^{N_L}_{n=0} \dot{m}_n,\\S_{\rho Y_n} &= \mathcal{C} \dot{m}_n,\\\mathbf{S}_{\rho \mathbf{u}} &= \mathcal{C} \mathbf{F}_d,\\S_{\rho h} &= \mathcal{C}\left(\mathcal{Q}_d + \sum_{n=0}^{N_L} \dot{m}_n h_{g,n}(T_d)\right),\\S_{\rho E} &= S_{\rho h} + \frac{1}{2}\left\|\mathbf{u}_d\right\| S_{\rho} + \mathcal{C} \mathbf{F}_d \cdot \mathbf{u}_d\end{aligned}\end{align} \]
    +

    where

    +
    +\[\mathcal{C} = -\frac{N_{d}}{V_{\rm{cell}}},\]
    +

    \(N_{d}\) is the number of droplets per computational parcel, and \(V_{\rm{cell}}\) is the volume for the cell of interest. Note that the cell volume can vary depending on AMR level and if an EB is present.

    +
    +
  20. +
+
+
+

Spray Flags and Inputs

+
    +
  • In the GNUmakefile, specify USE_PARTICLES = TRUE and SPRAY_FUEL_NUM = N where N is the number of liquid species being used in the simulation.

  • +
  • Depending on the gas phase solver, spray solving functionality can be turned on in the input file using pelec.do_spray_particles = 1 or peleLM.do_spray_particles = 1.

  • +
  • The units for PeleLM and PeleLMeX are MKS while the units for PeleC are CGS. This is the same for the spray inputs. E.g. when running a spray simulation coupled with PeleC, the units for particles.fuel_cp must be in erg/g.

  • +
  • There are many required particles. flags in the input file. For demonstration purposes, 2 liquid species of NC7H16 and NC10H22 will be used.

    +
      +
    • The liquid fuel species names are specified using particles.fuel_species = NC7H16 NC10H22. The number of fuel species listed must match SPRAY_FUEL_NUM.

    • +
    • Many values must be specified on a per-species basis. Following the current example, one would have to specify particles.NC7H16_crit_temp = 540. and particles.NC10H22_crit_temp = 617. to set a critical temperature of 540 K for NC7H16 and 617 K for NC10H22.

    • +
    • Although this is not required or typical, if the evaporated mass should contribute to a different gas phase species than what is modeled in the liquid phase, use particles.dep_fuel_species. For example, if we wanted the evaporated mass from both liquid species to contribute to a different species called SP3, we would put particles.dep_fuel_species = SP3 SP3. All species specified must be present in the chemistry transport and thermodynamic data.

    • +
    +
  • +
  • The following table lists other inputs related to particles., where SP will refer to a fuel species name

  • +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Input

Description

Required

Default Value

fuel_species

Names of liquid species

Yes

None

dep_fuel_species

Name of gas phase species to +contribute

Yes

Inputs to +fuel_species

fuel_ref_temp

Liquid reference temperature

Yes

None

SP_crit_temp

Critical temperature

Yes

None

SP_boil_temp

Boiling temperature at +atmospheric pressure

Yes

None

SP_cp

Liquid \(c_p\) at reference +temperature

Yes

None

SP_latent

Latent heat at reference +temperature

Yes

None

SP_rho

Liquid density

Yes

None

SP_lambda

Liquid thermal conductivity +(currently unused)

No

    +
  1. +
+

SP_mu

Liquid dynamic viscosity +(currently unused)

No

    +
  1. +
+

mom_transfer

Couple momentum with gas phase

No

1

mass_transfer

Evaporate mass and exchange +heat with gas phase

No

1

fixed_parts

Fix particles in space

No

0

parcel_size

\(N_{d}\); Number of +droplets per parcel

No

1.

write_ascii_files

Output ascii files of spray +data

No

0

cfl

Particle CFL number for +limiting time step

No

0.5

init_file

Ascii file name to initialize +droplets

No

Empty

+
    +
  • If an Antoine fit for saturation pressure is used, it must be specified for individual species,

    +
    particles.SP_psat = 4.07857 1501.268 -78.67 1.E5
    +
    +
    +

    where the numbers represent \(a\), \(b\), \(c\), and \(d\), respectively in:

    +
    +\[p_{\rm{sat}}(T) = d 10^{a - b / (T + c)}\]
    +
      +
    • If no fit is provided, the saturation pressure is estimated using the Clasius-Clapeyron relation; see

    • +
    +
  • +
  • Temperature based fits for liquid density, thermal conductivity, and dynamic viscosity can be used; these can be specified as

    +
    particles.SP_rho = 10.42 -5.222 1.152E-2 4.123E-7
    +particles.SP_lambda = 7.243 1.223 4.223E-8 8.224E-9
    +particles.SP_mu = 7.243 1.223 4.223E-8 8.224E-9
    +
    +
    +

    where the numbers represent \(a\), \(b\), \(c\), and \(d\), respectively in:

    +
    +\[ \begin{align}\begin{aligned}\rho_L \,, \lambda_L = a + b T + c T^2 + d T^3\\\mu_L = a + b / T + c / T^2 + d / T^3\end{aligned}\end{align} \]
    +

    If only a single value is provided, \(a\) is assigned to that value and the other coefficients are set to zero, effectively using a constant value for the parameters.

    +
  • +
+
+

Spray Injection

+

Templates to facilitate and simplify spray injection are available. To use them, changes must be made to the input and SprayParticlesInitInsert.cpp files. Inputs related to injection use the spray. parser name. To create a jet in the domain, modify the InitSprayParticles() function in SprayParticleInitInsert.cpp. Here is an example:

+
void
+SprayParticleContainer::InitSprayParticles(
+const bool init_parts, ProbParm const& prob_parm)
+{
+  amrex::ignore_unused(prob_parm);
+  int num_jets = 1;
+  m_sprayJets.resize(num_jets);
+  std::string jet_name = "jet1";
+  m_sprayJets[0] = std::make_unique<SprayJet>(jet_name, Geom(0));
+  return;
+}
+
+
+

This creates a single jet that is named jet1. This name will be used in the input file to reference this particular jet. For example, to set the location of the jet center for jet1, the following should be included in the input file,

+
spray.jet1.jet_cent = 0. 0. 0.
+
+
+

No two jets may have the same name. If an injector is constructed using only a name and geometry, the injection parameters are read from the input file. Here is a list of injection related inputs:

+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Input

Description

Required

jet_cent

Jet center location

Yes

jet_norm

Jet normal direction

Yes

jet_vel

Jet velocity magnitude

Yes

jet_dia

Jet diameter

Yes

spread_angle

\(\theta_J\); Full spread +angle in degrees from the jet +normal direction; droplets vary +from +\([-\theta_J/2,\theta_J/2]\)

Yes

T

Temperature of the injected +liquid

Yes

Y

Mass fractions of the injected +liquid based on +particles.fuel_species

Yes, if +SPRAY_FUEL_NUM > +1

mass_flow_rate

\(\dot{m}_{\rm{inj}}\); Mass +flow rate of the jet

Yes

hollow_spray

Sets hollow cone injection with +angle \(\theta_J/2\)

No (Default: 0)

hollow_spread

\(\theta_h\); Adds spread to +hollow cone \(\theta_J/2\pm +\theta_h\)

No (Default: 0)

swirl_angle

\(\phi_S\); Adds a swirling +component along azimuthal +direction

No (Default: 0)

start_time and +end_time

Beginning and end time for jet

No

dist_type

Droplet diameter distribution +type: Uniform, Normal, +LogNormal, Weibull, +ChiSquared

Yes

+
+_images/inject_transform.png +
+

9 Demonstration of injection angles. \(\phi_J\) varies uniformly from \([0, 2 \pi]\)

+
+
+

Care must be taken to ensure the amount of mass injected during a time step matches the desired mass flow rate. For smaller time steps, the risk of over-injecting mass increases. To mitigate this issue, each jet accounts for three values: \(N_{P,\min}\), \(m_{\rm{acc}}\), and \(t_{\rm{acc}}\) (labeled in the code as m_minParcel, m_sumInjMass, and m_sumInjTime, respectively). \(N_{P,\min}\) is the minimum number of parcels that must be injected over the course of an injection event; this must be greater than or equal to one. \(m_{\rm{acc}}\) is the amount of uninjected mass accumulated over the time period \(t_{\rm{acc}}\). The injection routine steps are as follows:

+
    +
  1. The injected mass for the current time step is computed using the desired mass flow rate, \(\dot{m}_{\rm{inj}}\) and the current time step

    +
    +\[m_{\rm{inj}} = \dot{m}_{\rm{inj}} \Delta t + m_{\rm{acc}}\]
    +
  2. +
  3. The time period for the current injection event is computed using

    +
    +\[t_{\rm{inj}} = \Delta t + t_{\rm{acc}}\]
    +
  4. +
  5. Using the average mass of an injected parcel, \(N_{d} m_{d,\rm{avg}}\), the estimated number of injected parcels is computed

    +
    +\[N_{P, \rm{inj}} = m_{\rm{inj}} / (N_{d} m_{d, \rm{avg}})\]
    +
  6. +
+
+
    +
  • If \(N_{P, \rm{inj}} < N_{P, \min}\), the mass and time is accumulated as \(m_{\rm{acc}} = m_{\rm{inj}}\) and \(t_{\rm{acc}} = t_{\rm{inj}}\) and no injection occurs this time step.

  • +
  • Otherwise, \(m_{\rm{inj}}\) mass is injected and convected over time \(t_{\rm{inj}}\) and \(m_{\rm{acc}}\) and \(t_{\rm{acc}}\) are reset.

  • +
+
+
    +
  1. If injection occurs, the amount of mass injected, \(m_{\rm{actual}}\), is summed and compared with the desired mass flow rate. If \(m_{\rm{actual}} / t_{\rm{inj}} - \dot{m}_{\rm{inj}} > 0.05 \dot{m}_{\rm{inj}}\), then \(N_{P,\min}\) is increased by one to reduce the likelihood of over-injecting in the future. A balance is necessary: the higher the minimum number of parcels, the less likely to over-inject mass but the number of time steps between injections can potentially grow as well.

  2. +
+
+
+
+

Spray Validation

+
+

Single Droplet Tests

+

Single droplet tests are performed and compared with computational or experimental results published in literature. These tests are setup in PeleProduction/PeleMPruns/single_drop_test. To run a test case, simply open Validate.py and set the case name from the table below

+
case = TestCaseName()
+
+
+

then do python Validate.py. +The following table details the parameters of each test:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Test Case Name

\(T_g\) [K]

\(p_g\) [bar]

\(T_d\) [K]

\(d_d\) [um]

\(\Delta u\) [m/s]

Ref

Tonini_4_33

1000

1

300

200

6.786

[1]

Abramzon

1500

10

300

100

15

[2]

Daif

348

1

294

1334

3.10

[3]

RungeHep +RungeDec +RungeMix

273

1

272

500-570

2.5

[4]

+
+_images/ton_res.png +
+

10 Droplet diameter, temperature, and n-octane mass fraction comparisons with Figure 4.33 in [1]

+
+
+
+_images/abram_res.png +
+

11 Droplet diameter and temperature comparisons with [2]

+
+
+
+_images/daif_res.png +
+

12 Droplet diameter and temperature comparisons with [3]

+
+
+ +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Thermodynamics.html b/Thermodynamics.html new file mode 100644 index 000000000..1d63349ff --- /dev/null +++ b/Thermodynamics.html @@ -0,0 +1,126 @@ + + + + + + + Thermodynamics — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Thermodynamics

+

PelePhysics supports the computation of thermodynamic properties for different species. The thermodynamic property models currently supported are the NASA7 and NASA9 polynomial parameterizations. The reader is referred to the many discussions about these models to learn more specifics, including Cantera’s discussion about thermodynamics properties.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Transport.html b/Transport.html new file mode 100644 index 000000000..7d66e31f4 --- /dev/null +++ b/Transport.html @@ -0,0 +1,182 @@ + + + + + + + Transport — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Transport

+

PelePhysics supports computation of several transport coefficients: dynamic viscosity (\(\mu\)), bulk viscosity (\(\xi\)), thermal conductivity (\(\lambda\)), mixture-averaged species diffusion coefficients (\(D_i\)), and Soret coefficients/thermal diffusion ratio (\(\chi_i\)). There are three choices of model for computing these transport coefficients:

+
    +
  • Constant with user-specified values

  • +
  • Sutherland, adding a simple temperature dependence to user-specified values

  • +
  • Simple where transport coefficients are computed based on thermochemistry data for the multi-component mixture

  • +
+

The choice between these transport models is made at compile time. When using GNUmake, this is done by setting the Transport_Model parameter in the GNUmakefile.

+

The appropriate choice of transport model depends on the EOS being used. For perfect gasses (GammaLaw), constant transport must be used. For reacting flow calculations using either the ideal gas (Fuego) or Soave-Redlich-Kwong equations of state, Simple transport is appropriate in most cases. Note that based on code implementation and physics considerations, the EOS/transport combinations of GammaLaw/Sutherland, GammaLaw/Simple, Soave-Redlich-Kwong/Constant and Soave-Redlich-Kwong/Sutherland are not supported and attempting to compile with any of those combinations will lead to an error message similar to this:

+
error: static_assert failed due to requirement 'is_valid_physics_combination<pele::physics::eos::SRK,
+      pele::physics::transport::ConstTransport>::value' "Invalid physics combination attempted"
+
+
+
+

Note

+

For the flow solvers in the Pele suite, Soret effects are only supported in PeleLMeX at present. The bulk viscosity is utilized in PeleC but not in the low-Mach algorithm used in PeleLM and PeleLMeX.

+
+
+

Constant

+

In this model, all transport coefficients are user-specified constants. They can be set in a simulation input file using:

+
transport.const_viscosity = 1.81e-4
+transport.const_bulk_viscosity = 0.0
+transport.const_conducitivity = 2.623e2
+transport.const_diffusivity = 0.242
+transport.const_thermal_diffusion_ratio =  0.0
+transport.units = CGS
+
+
+

Any unspecified quantity is assumed to be 0.0. The transport.units parameter indicates the units of the parameters set in the input file and can be CGS or MKS. If not specified, CGS units are assumed, and regardless of the value of this parameter the output of all transport functions is in CGS units.

+
+
+

Sutherland

+

This is another minimal model, based on the temperature dependence of viscosity proposed by Sutherland (1893):

+
+\[\mu = \mu_{ref} \left(\frac{T}{T_{ref}} \right)^{3/2} \frac{T_{ref} + S} {T + S},\]
+

where \(\mu_{ref}\) is the dynamic viscosity at a reference temperature \(T_{ref}\) and \(S\) is a constant. In the PelePhysics implementation, the thermal conductivity is then computed based on a user-specified Prandtl number, \(\lambda = \mu c_p / Pr\), where the heat capacity \(c_p\) is evaluated using the EOS model. The user may specify constant values for the bulk viscosity and diffusvity (a single value for all species). Soret effects are not supported for this Transport model (\(\chi_i = 0\)).

+

For Sutherland transport, there are several runtime parameters that may be specified in the input file:

+
transport.Prandtl_number = 0.7
+transport.viscosity_mu_ref = 17.16
+transport.viscosity_T_ref = 273.15
+transport.viscosity_S = 110.4
+transport.const_bulk_viscosity = 0.0
+transport.const_diffusivity = 1.0
+
+
+

The values listed above are the defaults for each parameter. Note that the temperature is specified in K and all other dimensional quantities must be specified in CGS units.

+
+
+

Simple

+

In this model, transport coefficients are evaluated from data available in the chemical mechanisms (set at compilation using Chemistry_Model). The implementation isbased on that in EGlib (see Ern and Giovangigli (1995)) and simplified to compute only mixture-averaged diffusivities for each species. The only option that may be specified at run time is whether or not to compute Soret coefficients, which is done by setting the input file parameter transport.use_soret to 1 or 0, respectively (default: 0).

+

When Simple transport is used with the Soave-Redlich-Kwong equation of state, additional corrections are used to modify the transport coefficients to account for real gas effects based on Chung et al. (1988). Soret effects are not supported for SRK.

+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Tutorials.html b/Tutorials.html new file mode 100644 index 000000000..cfb04da01 --- /dev/null +++ b/Tutorials.html @@ -0,0 +1,212 @@ + + + + + + + Tutorials — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Tutorials

+
+
+
+

Tutorial 1 - Generating NC12H26 QSS mechanism with analytical Jacobian

+

Update poetry:

+
$ cd ${PELE_PHYSICS_HOME}/Support/ceptr
+$ poetry update
+
+
+

Make sure the list of non-QSS species is correct in ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/non_qssa_list.yaml

+

In the next step, skeletal.yaml is the mechanism.yaml of the skeletal version of the mechanism (here available under ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu). +If only CHEMKIN files are available for the skeletal mechanism, see Converting CHEMKIN files for generating skeletal.yaml.

+

Generate qssa.yaml from skeletal.yaml and non_qssa_list.yaml:

+
$ cd ${PELE_PHYSICS_HOME}/Support/ceptr
+$ poetry run qssa -f ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/skeletal.yaml -n ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/non_qssa_list.yaml
+
+
+

Generate mechanism.H and mechanism.cpp from qssa.yaml:

+
$ cd ${PELE_PHYSICS_HOME}/Support/ceptr
+$ poetry run convert -f ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/qssa.yaml --qss_format_input ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/qssa_input.toml --qss_symbolic_jacobian
+
+
+

We recommend using the following qssa_input.toml:

+
$ [Readability]
+  hformat =                       "gpu"
+
+  [Arithmetic]
+  remove_1 =                      true
+  remove_pow =                    true
+  remove_pow10 =                  true
+
+  [Replacement]
+  min_op_count =                  0
+  min_op_count_all =              10
+  gradual_op_count =              true
+  remove_single_symbols_cse =     true
+
+  [Recycle]
+  store_in_jacobian =             true
+  recycle_cse =                   true
+
+  [Characters]
+  round_decimals =                true
+
+
+
+
+

Tutorial 2 - Generating NC12H26 QSS mechanism without analytical Jacobian

+

Update poetry:

+
$ cd ${PELE_PHYSICS_HOME}/Support/ceptr
+$ poetry update
+
+
+

Make sure the list of non-QSS species is correct in Mechanisms/dodecane_lu_qss/non_qssa_list.yaml

+

In the next step, skeletal.yaml is the mechanism.yaml of the skeletal version of the mechanism (here available under ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu). +If only CHEMKIN files are available for the skeletal mechanism, see Converting CHEMKIN files for generating skeletal.yaml.

+

Generate qssa.yaml from skeletal.yaml and non_qssa_list.yaml:

+
$ cd ${PELE_PHYSICS_HOME}/Support/ceptr
+$ poetry run qssa -f ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/skeletal.yaml -n ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/non_qssa_list.yaml
+
+
+

Generate mechanism.H and mechanism.cpp from qssa.yaml:

+
$ cd ${PELE_PHYSICS_HOME}/Support/ceptr
+$ poetry run convert -f ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/qssa.yaml
+
+
+
+
+

Tutorial 3 - Generating NC12H26 Skeletal mechanism

+

Update poetry:

+
$ cd ${PELE_PHYSICS_HOME}/Support/ceptr
+$ poetry update
+
+
+

For all the available mechanisms, a Cantera yaml format is provided. +If only CHEMKIN files are available, see Converting CHEMKIN files for generating mechanism.yaml.

+

Generate mechanism.H and mechanism.cpp from mechanism.yaml:

+
$ cd ${PELE_PHYSICS_HOME}/Support/ceptr
+$ poetry run convert -f ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu/mechanism.yaml
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/Utility.html b/Utility.html new file mode 100644 index 000000000..0bbd0e3dc --- /dev/null +++ b/Utility.html @@ -0,0 +1,235 @@ + + + + + + + Utility — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Utility

+

In addition to routines for evaluating chemical reactions, transport properties, and equation of state functions, PelePhysics includes other shared utilities that are utilized by both PeleC and PeleLM(eX). These utilities include support for:

+
    +
  • Premixed Flame (PMF) initialization from precomputed 1D flame profiles

  • +
  • Turbulent inflows (TurbInflow) on domain boundaries from saved turbulence data

  • +
  • Plt file management (PltFileManager)

  • +
  • Output of runtime Diagnostics

  • +
+

This section provides relevant notes on using these utilities across the Pele family of codes. There may be additional subtleties based on the code-specific implementation of these capabilities, in which case it will be necessary to refer to the documentation of the code of interest.

+
+

Premixed Flame Initialization

+

Pre-computed profiles from 1D freely propagating premixed flames are used to initialize a wrinkled flamesheet in PeleLMeX, among other problems. Right now, this capability is not used in PeleC, but similar code that accomplishes the same task using data files of the same format is applied in PeleC. The code has two parts, a data container defined in PMFData.{H,cpp} that loads and stores data from the pre-computed profile, and a function defined in PMF.H that, when provided this data structure and the bounds of a cell of interest, returns temperature, velocity, and mole fractions from that location.

+

This code has two runtime parameters that may be set in the input file:

+
pmf.datafile = pmf.dat
+pmf.do_cellAverage = 1
+
+
+

The first parameter specifies the path to the PMF data file. This file contains a two-line header followed by whitespace-delimited data columns in the order: position (cm), temperature (K), velocity (cm/s), density(g/cm3), species mole fractions. Sample files are provided in the relevant PeleLMeX (and PeleC) examples, and the procedure to generate these files with a provided script is described below. The second parameter specifies whether the PMF code does a finite volume-style integral over the queried cell (pmf.do_cellAverage = 1) or whether the code finds an interpolated value at the midpoint of the queried cell (pmf.do_cellAverage = 0)

+
+

Generating a PMF file

+

The script cantera_pmf_generator.py solves a 1D unstrained premixed flame using Cantera and saves it in the appropriate file format for use by the Pele codes. To use this script, first follow the CEPTR instructions for setting up poetry. Then return to the Utility/PMF/ directory and run the script:

+
poetry -C ../../Support/ceptr/ run python cantera_pmf_generator.py -m dodecane_lu -f NC12H26 -d 0.01 -o ./
+
+
+

This example computes a dodecane/air flame using the dodecane_lu mechanism on a 0.01 m domain, and saves the resulting file to the present directory. You may choose any mechanism included with PelePhysics, as the Cantera .yaml format is included for all mechanisms. If you choose a reduced mechanism with QSS species, the 1D solution will be obtained using the skeletal version of the mechanism without QSS species being remove, as Cantera does not support QSS by default. In this case, the script will also save a data file with QSS species removed (ending in -qssa-removed.dat) that is suitable for use with the QSS mechanisms in Pele. A range of additional conditions may be specified at the command line. To see the full set of options, use the help feature:

+
poetry -C ../../Support/ceptr/ run python cantera_pmf_generator.py --help
+
+
+

Note that when running Cantera, you may need to adjust the domain size to be appropriate for your conditions in order for the solver to converge. At times, you may also need to adjust the solver tolerances and other parameters that are specified within the script.

+

An additional script is provided to allow plotting of the PMF solutions. This script is used as follows (if no variable index is specified, temperature is plotted by default):

+
poetry -C ../../Support/ceptr/ run python plotPMF.py <pmf-file> <variable-index>
+
+
+
+
+
+

Turbulent Inflows

+

Placeholder. PelePhysics supports the capability of the flow solvers to have spatially and temporally varying inflow conditions based on precomputed turbulence data.

+
+

Generating a turbulence file

+

A python script is used to generate a synthetic turbulence spectrum.

+
+
+
+

Plt File Management

+

This code contains data structures used to handle data read from plt files that is utilized by the routines that allow the code to be restarted based on data from plt files.

+
+
+

Diagnostics

+

Placeholder. Once the porting of diagnostics from PeleLMeX to PelePhysics/PeleC is complete, documentation can be added here.

+
+
+

Filter

+

A utility for filtering data stored in AMReX data structures. When initializing the Filter class, the filter type +and filter width to grid ratio are specified. A variety of filter types are supported:

+
    +
  • type = 0: no filtering

  • +
  • type = 1: standard box filter

  • +
  • type = 2: standard Gaussian filter

  • +
+

We have also implemented a set of filters defined in Sagaut & Grohens (1999) Int. J. Num. Meth. Fluids:

+
    +
  • type = 3: 3 point box filter approximation (Eq. 26)

  • +
  • type = 4: 5 point box filter approximation (Eq. 27)

  • +
  • type = 5: 3 point box filter optimized approximation (Table 1)

  • +
  • type = 6: 5 point box filter optimized approximation (Table 1)

  • +
  • type = 7: 3 point Gaussian filter approximation

  • +
  • type = 8: 5 point Gaussian filter approximation (Eq. 29)

  • +
  • type = 9: 3 point Gaussian filter optimized approximation (Table 1)

  • +
  • type = 10: 5 point Gaussian filter optimized approximation (Table 1)

  • +
+
+

Warning

+

This utility is not aware of EB or domain boundaries. If the filter stencil extends across these boundaries, +the boundary cells are treated as if they are fluid cells. +It is up to the user to ensure an adequate number of ghost cells in the arrays are appropriately populated, +using the get_filter_ngrow() member function of the class to determine the required number of ghost cells.

+
+
+

Developing

+

The weights for these filters are set in Filter.cpp. To add a +filter type, one needs to add an enum to the filter_types and +define a corresponding set_NAME_weights function to be called at +initialization.

+

The application of a filter can be done on a Fab or MultiFab. The loop nesting +ordering was chosen to be performant on existing HPC architectures and +discussed in PeleC milestone reports. An example call to the filtering operation is

+
les_filter = Filter(les_filter_type, les_filter_fgr);
+...
+les_filter.apply_filter(bxtmp, flux[i], filtered_flux[i], Density, NUM_STATE);
+
+
+

The user must ensure that the correct number of grow cells is present in the Fab or MultiFab.

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_images/Case_ReactEvalCvode.001.png b/_images/Case_ReactEvalCvode.001.png new file mode 100644 index 000000000..9ff0e07b4 Binary files /dev/null and b/_images/Case_ReactEvalCvode.001.png differ diff --git a/_images/ERRs.png b/_images/ERRs.png new file mode 100644 index 000000000..8a4451ee7 Binary files /dev/null and b/_images/ERRs.png differ diff --git a/_images/GroupingOfCells.png b/_images/GroupingOfCells.png new file mode 100644 index 000000000..e326087c5 Binary files /dev/null and b/_images/GroupingOfCells.png differ diff --git a/_images/Main.001.png b/_images/Main.001.png new file mode 100644 index 000000000..3b9c666f0 Binary files /dev/null and b/_images/Main.001.png differ diff --git a/_images/PeleSuite.png b/_images/PeleSuite.png new file mode 100644 index 000000000..68d988956 Binary files /dev/null and b/_images/PeleSuite.png differ diff --git a/_images/ReactEvalCv.001.png b/_images/ReactEvalCv.001.png new file mode 100644 index 000000000..ca255c950 Binary files /dev/null and b/_images/ReactEvalCv.001.png differ diff --git a/_images/Specs.png b/_images/Specs.png new file mode 100644 index 000000000..3f36cc331 Binary files /dev/null and b/_images/Specs.png differ diff --git a/_images/abram_res.png b/_images/abram_res.png new file mode 100644 index 000000000..f98c7fcb2 Binary files /dev/null and b/_images/abram_res.png differ diff --git a/_images/aj_0D_QSS.png b/_images/aj_0D_QSS.png new file mode 100644 index 000000000..1b8fe0fcf Binary files /dev/null and b/_images/aj_0D_QSS.png differ diff --git a/_images/daif_res.png b/_images/daif_res.png new file mode 100644 index 000000000..b09c7da4e Binary files /dev/null and b/_images/daif_res.png differ diff --git a/_images/directedGraphQSS.png b/_images/directedGraphQSS.png new file mode 100644 index 000000000..877cf2fc0 Binary files /dev/null and b/_images/directedGraphQSS.png differ diff --git a/_images/inject_transform.png b/_images/inject_transform.png new file mode 100644 index 000000000..285674a1f Binary files /dev/null and b/_images/inject_transform.png differ diff --git a/_images/qss_integrator.png b/_images/qss_integrator.png new file mode 100644 index 000000000..5b1ac618f Binary files /dev/null and b/_images/qss_integrator.png differ diff --git a/_images/quadGraphQSS.png b/_images/quadGraphQSS.png new file mode 100644 index 000000000..47385d479 Binary files /dev/null and b/_images/quadGraphQSS.png differ diff --git a/_images/ton_res.png b/_images/ton_res.png new file mode 100644 index 000000000..aa4719d54 Binary files /dev/null and b/_images/ton_res.png differ diff --git a/_images/validationQSS.png b/_images/validationQSS.png new file mode 100644 index 000000000..92cf7d8b8 Binary files /dev/null and b/_images/validationQSS.png differ diff --git a/_sources/Ceptr.rst.txt b/_sources/Ceptr.rst.txt new file mode 100644 index 000000000..49c99d061 --- /dev/null +++ b/_sources/Ceptr.rst.txt @@ -0,0 +1,111 @@ +.. highlight:: rst + +.. _sec:ceptr: + +CEPTR: Chemistry Evaluation for Pele Through Recasting +====================================================== + +We use CEPTR to generate C++ mechanism files from `Cantera `_ yaml chemistry files. CEPTR is a python package part of the PelePhysics source code. + +.. _sec_ceptr_software: + +Software requirements +--------------------- + +The CEPTR package uses `poetry `_ to manage the Python dependencies. Poetry is therefore required to use CEPTR and can typically be installed through system package managers (e.g. HomeBrew) or following the instructions in poetry's documentation. + +To install CEPTR dependencies:: + + $ cd ${PELE_PHYSICS_HOME}/Support/ceptr + $ poetry update + +Usage +----- + +Generating for a single chemistry +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +There are three ways to use CEPTR to generate C++ mechanism files for a given chemistry + +1. Using CEPTR directly:: + + $ cd ${PELE_PHYSICS_HOME}/Support/ceptr + $ poetry run convert -f ${PELE_PHYSICS_HOME}/Mechanisms/LiDryer/mechanism.yaml + +2. Using a helper script in the directory containing the ``mechanism.yaml`` file:: + + $ ./convert.sh + +3. Using a helper script in the ``Models`` directory:: + + $ bash ${PELE_PHYSICS_HOME}/Mechanisms/converter.sh -f ./LiDryer/mechanism.yaml + + +Batched generation +^^^^^^^^^^^^^^^^^^ + +.. note:: + + If you are using batched generation as outlined here, it will automatically use multiprocessing to generate the files in parallel using all CPUs detected on the machine. If you want to change that you can pass the optional argument ``-n NPCU``, wheren ``NCPU`` is an integer indicating the number of processes you want to use. + + +For non-reduced chemistries, CEPTR can take a file with a list of ``mechanism.yaml`` files to convert:: + + $ cd ${PELE_PHYSICS_HOME}/Support/ceptr + $ poetry run convert -l ${PELE_PHYSICS_HOME}/Mechanisms/list_mech + +For reduced chemistries, CEPTR can take a file with a list of ``qssa.yaml`` and ``qssa_input.toml`` to convert:: + + $ cd ${PELE_PHYSICS_HOME}/Support/ceptr + $ poetry run convert -lq ${PELE_PHYSICS_HOME}/Mechanisms/list_qss_mech + +For generating ``qssa.yaml`` for reduced chemistries, CEPTR can take a file with a list of ``skeletal.yaml`` and ``non_qssa_list.yaml``:: + + $ cd ${PELE_PHYSICS_HOME}/Support/ceptr + $ poetry run qssa -lq ${PELE_PHYSICS_HOME}/Mechanisms/list_qss_mech + +To generate all mechanisms:: + + $ poetry run convert -l ${PELE_PHYSICS_HOME}/Mechanisms/list_mech + $ poetry run qssa -lq ${PELE_PHYSICS_HOME}/Mechanisms/list_qss_mech + $ poetry run convert -lq ${PELE_PHYSICS_HOME}/Mechanisms/list_qss_mech + + +Converting CHEMKIN files +------------------------ +.. _sec_convertCK: + +We rely on Cantera's ``ck2yaml`` utility to convert CHEMKIN files to the Cantera yaml format (and proceed as above with CEPTR on the resulting yaml file):: + + $ cd ${PELE_PHYSICS_HOME}/Support/ceptr + $ poetry run ck2yaml --input=${PATH_TO_CHEMKIN_DIR}/mechanism.inp --thermo=${PATH_TO_CHEMKIN_DIR}/therm.dat --transport=${PATH_TO_CHEMKIN_DIR}/tran.dat --permissive + +The files ``tran.dat`` and ``therm.dat`` are optional if already included in the ``.inp`` file. + +Generating a QSS chemistry file +------------------------------- + +To generate a QSS chemistry yaml file from another yaml file, one executes:: + + $ poetry run qssa -f ${PATH_TO_YAML}/skeletal.yaml -n ${PATH_TO_YAML}/non_qssa_list.yaml + +The full list of options is:: + + $ poetry run qssa -h + usage: qssa [-h] -f FNAME -n NQSSA [-m {0,1,2}] [-v] + + Mechanism converter + + optional arguments: + -h, --help show this help message and exit + -f FNAME, --fname FNAME + Mechanism file + -n NQSSA, --nqssa NQSSA + Non-QSSA species list + -m {0,1,2}, --method {0,1,2} + QSSA method (default: 2) + -v, --visualize Visualize quadratic coupling and QSSA dependencies + +For a detailed description of these options and a further information on the way QSS mechanism are treated in `CEPTR` the reader may consult :ref:`the QSS section `. + +See Tutorials (:ref:`Generating NC12H26 QSS mechanism with analytical jacobian ` and :ref:`Generating NC12H26 QSS mechanism without analytical jacobian `) for generating QSS mechanisms from the ``.yaml`` files. diff --git a/_sources/Chemistry.rst.txt b/_sources/Chemistry.rst.txt new file mode 100644 index 000000000..8f7617596 --- /dev/null +++ b/_sources/Chemistry.rst.txt @@ -0,0 +1,17 @@ +.. highlight:: rst + +.. _sec:chemistry: + +********* +Chemistry +********* + +.. toctree:: + :maxdepth: 3 + :caption: Chemistry contents: + + IntroductionToCvode.rst + CvodeInPP.rst + QSS.rst + Ceptr.rst + diff --git a/_sources/CvodeInPP.rst.txt b/_sources/CvodeInPP.rst.txt new file mode 100644 index 000000000..885a69ee4 --- /dev/null +++ b/_sources/CvodeInPP.rst.txt @@ -0,0 +1,695 @@ +.. highlight:: rst + +.. role:: cpp(code) + :language: c++ + +CVODE implementation in `PelePhysics` +===================================== + +.. _sec:subsDiffReacts: + +The different reactors +---------------------- + +Throughout this document, what we call a `reactor` is in fact a zero-dimensional model, +the simplest representation of a chemically reacting system. Depending upon the choice of state variables +driving the system, several different types of reactor can be considered; +and the "correct" choice is case dependent. In general, the state variables for a reactor model are + +- The reactor mass +- The reactor volume +- The energy of the system +- The mass fractions for each species + +The most common type of reactor is the `constant-volume` (CV) reactor, which is the one used to advance the chemistry +within `PeleC`. This reactor type is equivalent to a rigid vessel with fixed volume but variable pressure. +In `PelePhysics`, the constant-volume constraint is ensured by keeping the density :math:`\rho` fixed +-since there is no change of mass; and the indirect choice of energy in the CV reactor implementation is the total energy +:math:`E`. :math:`E`'s evolution in our case is solely due to a constant external source term :math:`\dot{E}_{ext}`, which accounts +for the effects of advection and convection in the Spectral Deferred Correction (SDC) scheme that all `Pele` codes use (see the `PeleLM `_ documentation for example). +In that sense, the CV reactor is an abstraction and is not a true closed vessel. + +Note that CVODE still integrates the mass fractions (:math:`\rho Y`) together with energy for stability reasons, +but a change of variable is applied to effectively transport the temperature :math:`T` via + +.. math:: + + \rho C_v \frac{\partial T}{\partial t} = \rho\dot{E}_{ext} - \sum_k e_k {\dot{\omega}_k}^M + +where the :math:`e_k` are the species internal energy and :math:`{\dot{\omega}_k}^M` is the species :math:`k` mass production rate. + +In a second implementation, that we will label `constant-volume-enthalpy` (CVH), the mass-weighted total enthalpy :math:`\rho H` is used and +conserved along with :math:`\rho`. This reactor type is also an abstraction. Here also, :math:`\rho H` +evolves according to an external source term :math:`\dot{\rho H}_{ext}`, and in CVODE, the mass fractions (:math:`\rho Y`) and +temperature :math:`T` are integrated according to + +.. math:: + + \rho C_p \frac{\partial T}{\partial t} = \rho\dot{H}_{ext} - \sum_k h_k {\dot{\omega}_k}^M + +where the :math:`h_k` are the species internal energy. + +.. _sec:subsubValidCVreact: + +Validation of the CV reactor implementation in CVODE (with CANTERA) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +`CANTERA `_ is an open-source suite of tools for problems involving chemical kinetics, thermodynamics, and transport processes. +It is a very robust and fast tool written in C++ that is also based on CVODE to perform the chemistry integration. +CANTERA is well recognized in the combustion community, and by comparing our results to CANTERA reactor simulations, +we will be able to validate our implementation. + +Note that only the CV reactor model described above can be validated, since as we discussed before, +the CVH reactor model is an abstraction needed for our Low-Mach PeleLM chemistry integration. Also, to have a real CV reactor, +the external source terms for the energy and species equations in `PelePhysics` have been set to 0 (see :ref:`sec:subsDiffReacts`). + +The parameters chosen to initialize the simulation in both CANTERA and `PelePhysics` are described in +Table :numref:`fig:ReactEvalCVODETable`. The kinetic mechanism used for hydrogen combustion is available in `PelePhysics`. +Note that small sub-steps are explicitly taken until the final time is reached, +but CVODE's internal machinery can subdivides the :math:`dt` even further. +For the purpose of validation, the direct dense solver of CVODE is selected +in `PelePhysics` (see section :ref:`sec:subsPPOptions`). + +.. _fig:ReactEvalCVODETable: + +.. table:: Parameters for initializing simulation + :align: center + + +------------+-----------------+-------------+----------------+-------------+----------------+-----------------+ + | Mechanism | Mixture | Initial T | Initial phi | Pressure | dt | Final time | + +------------+-----------------+-------------+----------------+-------------+----------------+-----------------+ + | Li Dryer | H2/O2 | 1500 K | 0.8 | 101325 Pa | 1.0e-8s | 3.0e-6s | + +------------+-----------------+-------------+----------------+-------------+----------------+-----------------+ + +Results are plotted in Fig :numref:`fig:ReactEvalCVODE` and :numref:`fig:ReactEvalCVODESpecs`. for the :math:`H_2/O_2` mixture. +All curves are indistinguishable, so the relative error of all major quantities is also plotted in Fig. :numref:`fig:ReactEvalCVODEErrss`. +Note that :math:`H_2` and :math:`O_2` relative errors have similar features, and that relative errors observed +for :math:`H` and :math:`H_2O` are representative of those exhibited by, respectively, intermediates and products. + +.. |a| image:: ./Visualization/Main.001.png + :width: 100% + +.. |b| image:: ./Visualization/Specs.png + :width: 100% + +.. |c| image:: ./Visualization/ERRs.png + :width: 100% + +.. _fig:ReactEvalCVODE: + +.. table:: Evolution of temperature, pressure and enthalpy in a CV reactor, computed with the LiDryer mechanism. Black: CANTERA, red: PelePhysics. + :align: center + + +-----+ + | |a| | + +-----+ +.. + .. figure:: ./Visualization/Main.001.png + :width: 100% + :name: fig-ReactEvalCVODE + :alt: Evolution of temperature, pressure and enthalpy in a CV reactor, computed with the LiDryer mechanism. Black: CANTERA, red: PelePhysics. + + +.. _fig:ReactEvalCVODESpecs: + +.. table:: Evolution of major species in a CV reactor, computed with the LiDryer mechanism. Black: CANTERA, red: PelePhysics. + :align: center + + +-----+ + | |b| | + +-----+ + +.. _fig:ReactEvalCVODEErrss: + +.. table:: Relative errors on the temperature, pressure, enthalpy and major species in a CV reactor, computed with the LiDryer mechanism. + :align: center + + +-----+ + | |c| | + +-----+ + + +Overall, considering the many CVODE controlling parameters, results are deemed acceptable and that +concludes the validation of the reactors implemented in `PelePhysics`. + + + +.. _sec:subsPPOptions: + +Activating the different CVODE solver options via the input files +----------------------------------------------------------------- +**Note that at this point, it is believed that the user has properly installed CVODE as well as the SuiteSparse package. If not, refer to** :ref:`sec:GetCVODE`. + +Choosing between DVODE/CVODE (as well as other ODE integrators that will not be discussed in this section) is done at compile time, +via the ``GNUmakefile``. On the other hand, the type of reactor and specifics of the numerical algorithm +are selected via keywords in the input file. There is a subtlety though: +when any sparsity feature is required, the choice should also be made at compile time since external libraries will be required; +and if the compilation is not performed properly, subsequent options via keywords in the input file can either lead to an error or fall back to a dense formulation +of the problem. This is discussed in more depth in what follows. + +.. _subsubs:GNUtype: + +The GNUmakefile +^^^^^^^^^^^^^^^ + +The default setting is to use DVODE in `PelePhysics`; i.e, if no modifications are done to the original ``GNUmakefile`` (see the test case ReactEval_FORTRAN of `PelePhysics`), +then this option should automatically be selected. To activate CVODE, the user must first activates the use of Sundials via the following line: :: + + USE_SUNDIALS_PP = TRUE + +Note that this is a `PelePhysics` flag, so it will automatically be recognized in the `Pele` codes. However, if CVODE has not been installed as prescribed in :ref:`sec:GetCVODE` then a line specifying the location of the Sundials libraries should be added: :: + + CVODE_LIB_DIR=PathToSundials/instdir/lib/ + +By default, if Sundials is used then the implicit ODE solver CVODE is selected. The user then has to choose between a number of +different methods to integrate the linear system arising during the implicit solve. Add the following line if sparsity features are required: :: + + PELE_USE_KLU = TRUE + +Likewise, if `SuiteSparse` has not been installed as prescribed in :ref:`sec:GetCVODE`, then a line specifying its location should be added: :: + + SUITESPARSE_DIR=PathToSuiteSparse/ + +All of the flags discussed in this subection are used in ``$PELE_PHYSICS_HOME/ThirdPartyThirdParty/Make.ThirdParty``. + + +The input file +^^^^^^^^^^^^^^ + +The input file is made up of specific blocks containing keywords that apply to specific areas of the integrationof the problem at hand. +The suffix associated with each block of keywords should help the user in determining which keywords +are needed in his case, depending on the options selected via the ``GNUmakefile``. +If CVODE is enabled via the ``GNUmakefile``, for example, keywords starting with ``cvode.*`` are relevant. +The general ``ode.*`` keywords are shared by all ODE integrators and thus are also relevant for CVODE: + +- ``ode.reactor_type`` enable to switch from a CV reactor (``=1``) to a CVH reactor (``=2``). +- ``cvode.solve_type`` controls the CVODE linear integration method: choose ``1`` to enable the dense direct linear solver, + ``5`` for the sparse direct linear solver (if the KLU library has been linked) and ``99`` for the Krylov iterative solver +- ``ode.analytical_jacobian`` is a bit less obvious: + + - If ``cvode.solve_type = 1``, then ``ode.analytical_jacobian = 1`` will activate the use of an Analytical Jacobian. + + - If ``cvode.solve_type = 99``, then ``ode.analytical_jacobian = 1`` will activate the preconditioned GMRES solver while ``ode.analytical_jacobian = 0`` will activate the non-preconditioned GMRES solver. + + - If ``cvode.solve_type = 99``, ``ode.analytical_jacobian = 1`` **and** the KLU library is linked, then the preconditioned solve is done in a sparse format. + + - With ``cvode.solve_type = 5``, the only allowed option is ``ode.analytical_jacobian = 1``. + + +.. _sec:subsReactEvalCvode: + +The ReactEval_C test case with CVODE in details +----------------------------------------------- + +This tutorial has been adapted from the `ReactEval_FORTRAN` tutorial employed in the series of regression tests to monitor the DVODE chemistry integration. +The domain considered is a :math:`2x1024x2` box, where the initial temperature is different in each :math:`(i,j,k)-` cell, according to a :math:`y-` evolving sinusoidal profile, see Fig. :numref:`fig:ErrH2`: + +.. math:: + + T(i,j,k) = T_l + (T_h-T_l)\frac{y(i,j,k)}{L} + dTsin\left(2\pi\frac{y(i,j,k)}{P}\right) + +The different parameters involved are summarized in Table :numref:`tab::ParamReactEvalCvode`. The initial pressure is 1 atm. The initial composition is the same in every cell, and is a mixture of 0.1 :math:`C_nH_m`, 0.2 :math:`O_2` and 0.7 :math:`N_2` in mass fractions. + +Various fuels and kinetic mechanisms can be employed. For the purpose of this tutorial, two common fuels will be considered: **methane** (n=1 and m=4) and **n-dodecane** (n=12 and m=26), modelled via the **drm** and **dodecane_wang** kinetic schemes, respectively. Both mechanisms are available in `PelePhysics`. + +The following focuses on the :math:`CH_4`/:math:`O_2` example, but performances for both mechanisms and initial composition will be reported in the results section. + + +.. _tab::ParamReactEvalCvode: + +.. table:: Parameters used to initialize T in the ReactEval_C test case + :align: center + + +------------+-----------------+-------------+----------------+-------------+ + | Tl | Th | dT | L | P | + +------------+-----------------+-------------+----------------+-------------+ + | 2000 K | 2500 K | 100 K | 1024 | L/4 | + +------------+-----------------+-------------+----------------+-------------+ + + +.. _fig:ErrH2: + +.. figure:: ./Visualization/Case_ReactEvalCvode.001.png + :width: 50% + :align: center + :name: fig-ReactEvalCVODE + :target: ./Visualization/Case_ReactEvalCvode.001.png + :alt: The ReactEval_C test case + + The ReactEval_C test case + +The GNUmakefile +^^^^^^^^^^^^^^^ + +For this example, the ``USE_SUNDIALS_PP`` flag should be set to true, as the ODE integration +is called from the C++ routine directly using CVODE. +Additionally, the ``FUEGO_GAS`` flag should be set to true and the chemistry model should be set to ``drm19``. The full file reads as follows: + +.. code-block:: + + PRECISION = DOUBLE + PROFILE = FALSE + + DEBUG = FALSE + + DIM = 3 + + COMP = gcc + FCOMP = gfortran + + USE_MPI = TRUE + USE_OMP = FALSE + + FUEGO_GAS = TRUE + + TINY_PROFILE = TRUE + + # define the location of the PELE_PHYSICS top directory + PELE_PHYSICS_HOME := ../../../.. + + ####################### + DEFINES += -DMOD_REACTOR + + ####################### + # ODE solver OPTIONS: DVODE (default) / SUNDIALS / RK explicit + ####################### + # Activates use of SUNDIALS: CVODE (default) / ARKODE + USE_SUNDIALS_PP = TRUE + ifeq ($(USE_SUNDIALS_PP), TRUE) + # provide location of sundials lib if needed + SUNDIALS_LIB_DIR=$(PELE_PHYSICS_HOME)/ThirdParty/sundials/instdir/lib/ + # use KLU sparse features -- only useful if CVODE is used + PELE_USE_KLU = FALSE + ifeq ($(PELE_USE_KLU), TRUE) + # provide location of KLU lib if needed + SUITESPARSE_DIR=$(PELE_PHYSICS_HOME)/ThirdParty/SuiteSparse/ + endif + endif + + ####################### + ifeq ($(FUEGO_GAS), TRUE) + Eos_Model = Fuego + Chemistry_Model = drm19 + Reactions_dir = Fuego + Transport_Model = Simple + else + Eos_Model = GammaLaw + Reactions_dir = Null + Transport_Model = Constant + endif + + Bpack := ./Make.package + Blocs := . + + include $(PELE_PHYSICS_HOME)/Testing/Exec/Make.PelePhysics + +Note that the ``TINY_PROFILE`` flag has been activated to obtain statistics on the run. This is an `AMREX` option. + +The input file +^^^^^^^^^^^^^^ + +The run parameters that can be controlled via ``inputs.3d`` input file for this example are as follows: :: + + #ODE solver options + # REACTOR mode + ode.dt = 1.e-05 + ode.ndt = 10 + # Reactor formalism: 1=full e, 2=full h + ode.reactor_type = 1 + # Tolerances for ODE solve + ode.rtol = 1e-9 + ode.atol = 1e-9 + # Select ARK/CV-ODE Jacobian eval: 0=FD 1=AJ + ode.analytical_jacobian = 0 + #CVODE SPECIFICS + # Choose between sparse (5) dense (1/101) iterative (99) solver + cvode.solve_type = 1 + + #OTHER + # Max size of problem + max_grid_size = 2 + # Choose name of output pltfile + amr.plot_file = plt + # Fuel species + fuel_name = CH4 + +so in this example, a **CV reactor model is chosen** to integrate each cell, and the **dense direct solve without analytical Jacobian** is activated. +Each cell is then integrated for a total of :math:`1.e-05` seconds, with 10 external time steps. +This means that the actual :math:`dt` is :math:`1.e-06s`, which is more than what is typically used in the `PeleC` code, +but consistent with what is used in `PeleLM`. Note that the fuel is explicitly specified to be methane. +By default, the number of cells integrated simultaneously by one CVODE instance is 1 [#Foot1]_, but the `AMREX` block-integration proceeds by blocks of :math:`2x2x2`. + + +Results +^^^^^^^ + +It took 52.61s to integrate the 4096 cells of this box, with 4 MPI processes and no OMP process. +The resulting temperature evolution for all cells in the y-direction is displayed in Fig. :numref:`fig:ReacEvalCv`. + + +.. _fig:ReacEvalCv: + +.. figure:: ./Visualization/ReactEvalCv.001.png + :width: 100% + :align: center + :name: fig-ReactEvalCv + :alt: Evolution of temperature in the 2x1024x2 example box, using a CV reactor and a dense direct solve, and computed with the DRM mechanism. Black: $t=0$, red: $t=1e-05s$ + + Evolution of temperature in the 2x1024x2 example box, using a CV reactor and a dense direct solve, and computed with the DRM mechanism. Black: t=0s, red: t=1e-05s + + +To go further: ReactEval_C with CVODE and the KLU library +--------------------------------------------------------- + +The GNUmakefile +^^^^^^^^^^^^^^^ + +Only the middle part of the ``GNUmakefile`` needs to be modified compared to the previous example. + +.. code-block:: + + ... + ####################### + # ODE solver OPTIONS: DVODE (default) / SUNDIALS / RK explicit + ####################### + # Activates use of SUNDIALS: CVODE (default) / ARKODE + USE_SUNDIALS_PP = TRUE + ifeq ($(USE_SUNDIALS_PP), TRUE) + ... + # use KLU sparse features -- only useful if CVODE is used + PELE_USE_KLU = TRUE + ... + else + ... + endif + + ####################### + ... + + +The input file +^^^^^^^^^^^^^^ + +For the KLU library to be of use, a solver utilizing sparsity features should +be selected. We modify the input file as follows: + +.. code-block:: + + ... + ####################### + #ODE solver options + ... + # Select ARK/CV-ODE Jacobian eval: 0=FD 1=AJ + ode.analytical_jacobian = 1 + #CVODE SPECIFICS + # Choose between sparse (5) dense (1/101) iterative (99) solver + cvode.solve_type = 99 + ... + #OTHER + ... + +So that now, a preconditioned iterative Krylov solver is selected, where the preconditioner is specified in a sparse format. + +Results +^^^^^^^ + +This run now takes 1m34s to run. As expected from the dense Jacobian of the system obtained when using the small DRM mechanism +(the fill in pattern is :math:`>90 \%`), using an iterative solver does not enable to reach speed-ups over the simple dense direct +solve. **NOTE**, and this is important, that this tendency will revert when sufficiently small time steps are used. +For example, if instead of :math:`1e-6s` we took time steps of :math:`1e-8s` (consistent with `PeleC` time steps), then using +the iterative GMRES solver would have provided significant time savings. This is because the smaller the time step the +closer the system matrix is from the identity matrix and the GMRES iterations become really easy to complete. + +This example illustrates that choosing the "best" and "most efficient" algorithm is far from being a trivial task, +and will depend upon many factors. Table :numref:`tab:RunsReactEvalCvode` provides a summary of the CPU run time in solving the +ReactEval_C example with a subset of the various available CVODE linear solvers. As can be seen from the numbers, using an AJ is much more efficient than relying upon CVODE's built-in difference quotients. Using a sparse solver does not appear to provide additional time savings. + +.. _tab:RunsReactEvalCvode: + +.. table:: Summary of ReactEval_C runs with various algorithms (methane/air) + :align: center + + +-------------------------------+-----------------+----------------+-------------+----------------+-----------------+ + | Solver | Direct | Direct | Direct | Iter. | Iter. | + | | Dense | Dense AJ | Sparse AJ | not Precond. | Precond. (S) | + +-------------------------------+-----------------+----------------+-------------+----------------+-----------------+ + | KLU | OFF | OFF | ON | OFF | ON | + +===============================+=================+================+=============+================+=================+ + | ode.reactor_type | 1 | 1 | 1 | 1 | 1 | + +-------------------------------+-----------------+----------------+-------------+----------------+-----------------+ + | cvode.solve_type | 1 | 1 | 5 | 99 | 99 | + +-------------------------------+-----------------+----------------+-------------+----------------+-----------------+ + | ode.analytical_jacobian | 0 | 1 | 1 | 1 | 1 | + +-------------------------------+-----------------+----------------+-------------+----------------+-----------------+ + | Run time | 52.61s | 44.87s | 48.64s | 1m42s | 1m34s | + +-------------------------------+-----------------+----------------+-------------+----------------+-----------------+ + + +The same series of tests are performed for a mixture of n-dodecane and air (see :ref:`sec:subsReactEvalCvode`), the configuration being otherwise the same as in the methane/air case. Results are summarized in Table :numref:`tab:RunsReactEvalCvodeDOD`. The overall tendencies remain similar. Note that the non-preconditioned GMRES solver becomes very inefficient for this larger system. Here also, the direct sparse solve --which relies upon the KLU library, does not seem to provide additional time savings. The fill-in pattern is :math:`70 \%`. + +.. _tab:RunsReactEvalCvodeDOD: + +.. table:: Summary of ReactEvalCvode runs with various algorithms (n-dodecane/air) + :align: center + + +-------------------------------+-----------------+----------------+-------------+----------------+-----------------+ + | Solver | Direct | Direct | Direct | Iter. | Iter. | + | | Dense | Dense AJ | Sparse AJ | not Precond. | Precond. (S) | + +-------------------------------+-----------------+----------------+-------------+----------------+-----------------+ + | KLU | OFF | OFF | ON | OFF | ON | + +===============================+=================+================+=============+================+=================+ + | ode.reactor_type | 1 | 1 | 1 | 1 | 1 | + +-------------------------------+-----------------+----------------+-------------+----------------+-----------------+ + | cvode.solve_type | 1 | 1 | 5 | 99 | 99 | + +-------------------------------+-----------------+----------------+-------------+----------------+-----------------+ + | ode.analytical_jacobian | 0 | 1 | 1 | 1 | 1 | + +-------------------------------+-----------------+----------------+-------------+----------------+-----------------+ + | Run time | 6m25s | 5m33s | 6m32s | 21m44s | 10m14s | + +-------------------------------+-----------------+----------------+-------------+----------------+-----------------+ + + + +Current Limitations +------------------- + +Note that currently, all sparse operations rely on an Analytical Jacobian. This AJ is provided via the chemistry routines dumped by the CEPTR code. Those routines are generated in a pre-processing step, when the sparsity pattern of the AJ is still unknown. As such, all entries of the AJ are computed at all times, and when a sparsity solver is chosen, the AJ is in fact "sparsified" to take advantage of the sparse linear algebra. The "sparsification" process involves a series of loop in the cpp that takes a significant amount of the CPU time most of the time. However, it is always good to verify that this is the case. `AMREX`'s ``TINY_PROFILER`` features is a handy tool to do so. + +.. _sec:subssubsTricks: + +Tricks and hacks, stuff to know +------------------------------- + +When using DVODE, there is a `hack` enabling the user to reuse the Jacobian instead of reevaluating it from scratch. +This option is triggered when setting the ``extern_probin_module`` flag ``new_Jacobian_each_cell`` to ``0``. +This can be done in `PelePhysics` by adding the following line in the ``probin`` file: + +.. code-block:: c++ + + &extern + new_Jacobian_each_cell = 0 + / + +A similar feature is currently not available in CVODE, although it would be possible to modify the ``CVodeReInit`` function +to reinitialize only a subset of counters. This is currently under investigation. +The user still has some control via the CVODE flag ``CVodeSetMaxStepsBetweenJac``. + +How does CVODE compare with DVODE ? +----------------------------------- + +Depending on whether the famous Jacobian `hack` is activated or not in DVODE, +the completion time of the run can be decreased significantly. The same test case as that described in the previous section can also be integrated with DVODE. +For that purpose, the FORTRAN routines implementing the DVODE integration have been interfaced with C++ via a FORTRAN header. The run is thus identical to ReactEval_C with CVODE. +Only the ``GNUmakefile`` needs to be modified: + +.. code-block:: c++ + + ... + ####################### + # ODE solver OPTIONS: DVODE (default) / SUNDIALS / RK explicit + ####################### + # Activates use of SUNDIALS: CVODE (default) / ARKODE + USE_SUNDIALS_PP = FALSE + ... + + ####################### + ... + +and, as explained in section :ref:`sec:subssubsTricks`, the famous AJ `hack` can be activated via the ``probin`` file. + +Two runs are performed, activating the hack or not. Times are reported in Table :numref:`tab:CVODEvsDVODE`. + +.. _tab:CVODEvsDVODE: + +.. table:: Summary of a CVODE vs a DVODE chemistry integration on the same test case + :align: center + + +-------------------------------+-----------------+----------------+-----------------+ + | Solver | Direct | Direct | Direct | + | | Dense | Dense | Dense + `hack` | + +-------------------------------+-----------------+----------------+-----------------+ + | KLU | OFF | OFF | OFF | + +-------------------------------+-----------------+----------------+-----------------+ + | USE_SUNDIALS_PP | ON (CVODE) | OFF (DVODE) | OFF (DVODE) | + +===============================+=================+================+=================+ + | ode.reactor_type | 1 | 1 | 1 | + +-------------------------------+-----------------+----------------+-----------------+ + | cvode.solve_type | 1 | N/A | N/A | + +-------------------------------+-----------------+----------------+-----------------+ + | ode.analytical_jacobian | 0 | N/A | N/A | + +-------------------------------+-----------------+----------------+-----------------+ + | Run time | 52.61s | 53.21s | 52.83s | + +-------------------------------+-----------------+----------------+-----------------+ + + +In this case, the hack does not seem to provide significant time savings. Note also that CVODE is usually slightly more efficient than DVODE, consistently with findings of other studies available in the literature -- although in this case all options give comparable results. + + +CVODE implementation in `PelePhysics` on GPU +============================================ + +Requirements and input files +---------------------------- + +**To use CVODE on a GPU, Sundials should be build with the flag** ``CUDA_ENABLE`` **. A CUDA compiler also needs to be specified. Relevant information is provided in the Sundials install guide, and an automatic script is distributed with PelePhysics to ease the process. Refer to** :ref:`sec:GetCVODE`. + +Note that the SuiteSparse package does not support GPU architecture and is thus no longer required. Sparse linear algebra operations, when needed, are performed with the help of CUDA's `cuSolver `_. + +The GNUmakefile +^^^^^^^^^^^^^^^ + +To run on GPUs, `AMREX` should be build with CUDA enabled. To do so, add this line to the ``GNUmakefile``: :: + + USE_CUDA = TRUE + +This should activate the CUDA features of CVODE in `PelePhysics` too. + + +The input file +^^^^^^^^^^^^^^ + +In the ``inputs.3d``, the same three main keywords control the algorithm (``ode.reactor_type``, ``cvode.solve_type``, ``ode.analytical_jacobian``). However, note that there are less linear solver options available. + +- Both preconditioned or non-preconditioned GMRES options are available (``cvode.solve_type = 99``). The preconditioned version is triggered via the same flag as on the CPU (``ode.analytical_jacobian = 1``). +- The user has the choice between two different sparse solvers. + + - Sundials offers one option (the SUNLinSol_cuSolverSp_batchQR) relying upon the cuSolver to perform batched sparse QR factorizations. This version is enabled via ``cvode.solve_type = 5`` and ``ode.analytical_jacobian = 1``. + - Another version is available via ``cvode.solve_type = 1`` and ``ode.analytical_jacobian = 1``. This version relies upon a pre-computed Gauss-Jordan `Solver `_, and is fairly efficient for problems of moderate size. + + +Grouping cells together +----------------------- + +To take full advantage of the GPU power, many intensive operations of similar nature should be performed in parallel. In `PelePhysics`, this is achieved by grouping many cells together, and integrating each one in separate threads within one CVODE instance. Indeed, the flow of operations to solve one set of ODEs is very similar from one cell to the next, and one could expect limited thread divergence from this approach. Fig. :numref:`fig:GroupingCells` summarizes the idea. Note that the Jacobian of the group of cells is block-sparse, and any chosen integration method should take advantage of this. + + +.. _fig:GroupingCells: + +.. figure:: ./Visualization/GroupingOfCells.png + :width: 40% + :align: center + :name: fig-GroupingCells + :alt: Grouping of cells + + n cells are solved together in one CVODE instance. The big-matrix is block-sparse. + +In the current implementation, the number of cells that are grouped together is equal to the number of cells contained in the box under investigation within a MultiFab iteration. + +The ReactEval_C_GPU test case in details +---------------------------------------- + +A series of tests are performed on the GPU for a mixture of methane and air, with the intent of evaluationg the performance of the chemistry solvers. +The test case, configuration and initial conditions are similar to that described in :ref:`sec:subsReactEvalCvode`. The mechanism employed is the **drm**. + +The GNUmakefile +^^^^^^^^^^^^^^^ + +The full file reads as follows: + +.. code-block:: + + PRECISION = DOUBLE + PROFILE = FALSE + + DEBUG = FALSE + + DIM = 3 + + COMP = gcc + FCOMP = gfortran + + USE_MPI = FALSE + USE_OMP = FALSE + + FUEGO_GAS = TRUE + + USE_CUDA = TRUE + + TINY_PROFILE = TRUE + + # define the location of the PELE_PHYSICS top directory + PELE_PHYSICS_HOME := ../../.. + + ####################### + # this flag activates the subcycling mode in the D/Cvode routines + DEFINES += -DMOD_REACTOR + + ####################### + # ODE solver OPTIONS on GPU: SUNDIALS + ####################### + # Activates use of SUNDIALS: CVODE (default) + USE_SUNDIALS_PP = TRUE + + ############################################## + ifeq ($(FUEGO_GAS), TRUE) + Eos_Model = Fuego + Chemistry_Model = drm19 + Reactions_dir = Fuego + Transport_Model = Simple + else + Eos_Model = GammaLaw + Reactions_dir = Null + Transport_Model = Constant + endif + + Bpack := ./Make.package + Blocs := . + + include $(PELE_PHYSICS_HOME)/Testing/Exec/Make.PelePhysics + + +The input file +^^^^^^^^^^^^^^ + +The Results +^^^^^^^^^^^ + +Results are summarized in Table :numref:`tab:RunsReactEvalCvodeDRMGPU`. + + +.. _tab:RunsReactEvalCvodeDRMGPU: + +.. table:: Summary of ReactEvalCvode_GPU runs with various algorithms (methane/air) + :align: center + + +-------------------------------+-----------------+----------------+----------------+-----------------+ + | Solver | Direct | Direct | Iter. | Iter. | + | | Sparse I | Sparse II | not Precond. | Precond. (S) | + +===============================+=================+================+================+=================+ + | reactor_type | 1 | 1 | 1 | 1 | + +-------------------------------+-----------------+----------------+----------------+-----------------+ + | cvode.solve_type | 1 | 5 | 99 | 99 | + +-------------------------------+-----------------+----------------+----------------+-----------------+ + | ode.analytical_jacobian | 1 | 1 | 0 | 1 | + +-------------------------------+-----------------+----------------+----------------+-----------------+ + | Run time | 13s | 20s | 19s | 36s | + +-------------------------------+-----------------+----------------+----------------+-----------------+ + + + +Current Limitations +------------------- + +The current GPU implementation of CVODE relies on the launch of many kernels from the host. As such, a CVODE instance does not live *directly* on the GPU; rather, the user is in charge of identifying and delegating computation-intensive part of the RHS, Jacobian evaluation, etc. +The current implementation thus suffers from the cost of data movement, and parallelization is limited due to required device synchronizations within CVODE. + +.. [#Foot1] NOTE that only one cell at a time should be integrated with CVODE right now. The vectorized version on CPU is still WIP and not properly implemented for all linear solvers so that no computational gain should be expected from solving several cells at a time. diff --git a/_sources/DeveloperGuide.rst.txt b/_sources/DeveloperGuide.rst.txt new file mode 100644 index 000000000..3784295a3 --- /dev/null +++ b/_sources/DeveloperGuide.rst.txt @@ -0,0 +1,49 @@ +.. highlight:: rst + + +Developer Guidelines +==================== + +The following developer guidelines apply to all code that is to be committed to the `Pele` suite. + +Before adding files for a commit to be pushed to a branch of `PelePhysics`, first run the following formatting tools depending on the type of code: + + +C++ Code +-------- +All C++ code should be processed by the Clang formatter prior to being added for commit. + +Run ``clang-format``:: + + clang-format -i FILE.cpp + clang-format -i FILE.H + +Will apply all of the correct formatting and make the changes directly to the cpp source files. + + +Python +------ + +The tools necessary to format Python code (currently only used within CEPTR) are maintained through Poetry. + +1) Run ``isort``:: + + poetry run isort . + +This will perform proper sorting of the installed Python libraries. + +2) Run ``black``:: + + poetry run black . + +This will perform proper formatting of all Python files to be consistent with all current files. + +3) Run ``flake8``:: + + poetry run flake8 . + +This will run diagnostics on all the Python files and will list a series of issues that need to be addressed to adhere to current Python best practices. + + +Once all ``flake8`` messages have been addressed, the code will match the `Pele` suite standard. + diff --git a/_sources/EOS.rst.txt b/_sources/EOS.rst.txt new file mode 100644 index 000000000..adce621e1 --- /dev/null +++ b/_sources/EOS.rst.txt @@ -0,0 +1,295 @@ +.. highlight:: rst + +.. _sec:eos: + +***************** +Equation of State +***************** + +PelePhysics allows the user to use different equation of state (EOS) as the constitutive equation and close the compressible Navier-Stokes system of equations. All the routines needed to fully define an EOS are implemented through PelePhysics module. Available models include: + +* A simple ``GammaLaw`` model for a single component perfect gas +* An ideal gas mixture model (similar to the CHEMKIN-II approach) labeled ``Fuego`` +* The ``Soave-Redlich-Kwong`` cubic equation of state; ``Peng-Robinson`` support was started in the original Fortran version of the code but stalled and is not supported. + +Examples of EOS implementation can be seen in ``PelePhysics/Eos``. The choice between these Eos models is made at compile time. When using GNUmake, this is done by setting the ``Eos_Model`` parameter in the ``GNUmakefile``. + +The following sections will fully describe the implementation of Soave-Redlich-Kwong, a non-ideal cubic EOS, for a general mixture of species. Some examples of the old Fortran implementation of the code are given; these have since been ported to C++. Integration with CEPTR, for a chemical mechanism described in a chemkin format, will also be highlighted. For an advanced user interested in implementing a new EOS this chapter should provide a good starting point. + +.. note:: For the flow solvers in the Pele suite, the SRK EOS is presently only supported in PeleC, and not PeleLM(eX). + +GammaLaw +======== + +This EOS corresponds to a single component perfect gas, i.e. a gas that follows :math:`p = \rho \hat{R} T` and :math:`e = c_v T`, with constant :math:`c_v`, which together imply that :math:`p = (\gamma - 1)\rho e`, where :math:`\gamma = c_p / c_v`. The values of the relevant physical properties (:math:`\gamma = 1.4`, :math:`MW=28.97` g/mol) are chosen to correspond to air at standard conditions and are set in ``PelePhysics/Source/PhysicsConstants.H``. + +When the GammaLaw EOS is used, the ``Chemistry_Model`` should be set to ``Null``. + +Fuego +===== + +This is a multi-component ideal gas EOS to be used for mutli-component (reacting) calculations with any ``Chemistry_Model`` besides ``Null``. The gas mixture follows :math:`p = \rho \hat{R} T`, but with :math:`h(T) \equiv \sum Y_i h_i(T)` and :math:`h_i(T)` computed based on `NASA polynomials `_ that are included in the ``Chemistry_Model``. + +Soave-Redlich-Kwong (SRK) +========================= + +The cubic model is built on top of the ideal gas models. It should be used for multi-component (reacting) calculations where the pressure is sufficiently high that real gas effects are important; there is a significant computational cost penalty relative ideal gas calculations. Note that the function to compute the analytical Jacobian of the chemical system using the SRK EOS has not been implemented, so this EOS is not compatible with reaction integrators that rely on computing the analytical Jacobian. Any additional parameters (e.g., attractions, repulsions, critical states) are either included in the underlying Fuego database used to generate the source file model implementation, or else are inferred from the input model data. + +SRK EOS as a function of Pressure (p), Temperature(T), and :math:`\tau` (specific volume) is given by + +.. math:: + p = R T \sum \frac{Y_k}{W_k} \frac{1}{\tau - b_m} - \frac{a_m}{\tau(\tau + b_m)} + +where :math:`Y_k` are species mass fractions, :math:`R` is the universal gas constant, and +:math:`b_m` and :math:`a_m` are mixture repulsion and attraction terms, respectively. + +Mixing rules +------------ + +For a mixture of species, the following mixing rules are used to compute :math:`b_m` and :math:`a_m`. + +.. math:: + a_m = \sum_{ij} Y_i Y_j \alpha_i \alpha_j \;\;\; b_m = \sum_k Y_k b_k + +where :math:`b_i` and :math:`a_i` for each species is defined using critical pressure and temperature. + +.. math:: + a_i(T) = 0.42748 \frac{\left(R T_{c,i} \right)^2}{W_i^2 p_{c,i}} \bar{a}_i \left(T/T_{c,i}\right) \;\;\; + b_i = 0.08664 \frac{R T_{c,i}}{W_i p_{c,i}} + +where + +.. math:: + \bar{a}_i (T/T_{c,i}) = \left(1 + \mathcal{A} \left[ f\left( \omega_i \right) \left(1-\sqrt{T/T_{c,i}} \right ) \right] \right)^2 + +where :math:`\omega_i` are the accentric factors and + +.. math:: + f\left( \omega_i \right) = 0.48508 + 1.5517 \omega_i - 0.151613 \omega_{i}^2 + +For chemically unstable species such as radicals, critical temperatures and pressures are not available. +For species where critical properties are not available, we use the Lennard-Jones potential for that species to construct attractive and repulsive coefficients. + +.. math:: + T_{c,i} = 1.316 \frac{\epsilon_i}{k_b} \;\;\; a_i(T_{c,i}) = 5.55 \frac{\epsilon_i \sigma_i^3}{m_i^2} \;\;\; + \mathrm{and} \;\;\; b_i = 0.855 \frac{\sigma_i^3}{m_i} + +where :math:`\sigma_i`, :math:`\epsilon_i` are the Lennard-Jones potential molecular diameter and well-depth, respectively, +:math:`m_i` the molecular mass, and :math:`k_b` is Boltzmann's constant. + +In terms of implementation, a routine called `MixingRuleAmBm` can be found in the SRK eos implementation. The following code block shows the subroutine which receives species mass fractions and temperature as input. The outputs of this routine are :math:`b_m` and :math:`a_m` . + +.. code-block:: fortran + + do i = 1, nspecies + Tr = T*oneOverTc(i) + amloc(i) = (1.0d0 + Fomega(i)*(1.0d0-sqrt(Tr))) *sqrtAsti(i) + + bm = bm + massFrac(i)*Bi(i) + + enddo + do j = 1, nspecies + do i = 1, nspecies + + am = am + massFrac(i)*massFrac(j)*amloc(i)*amloc(j) + + end do + end do + +Thermodynamic Properties +------------------------ + +Most of the thermodynamic properties can be calculated from the equation of state and involve derivatives of various thermodynamic quantities and of EOS parameters. In the following, some of these thermodynamic properties for SRK and the corresponding routines are presented. + +Specific heat +^^^^^^^^^^^^^ + +For computing mixture specific heat at constant volume and pressure, the ideal gas contribution and the departure from the ideal gas are computed. Specific heat at constant volume can be computed using the following + +.. math:: + c_v = \left( \frac{\partial e_m}{\partial T}\right)_{\tau,Y} + +For SRK EOS, the formula for :math:`c_v` reduces to + +.. math:: + c_v = c_v^{id} - T \frac{\partial^2 a_m}{\partial T^2} \frac{1}{b_m} ln ( 1 + \frac{b_m}{\tau}) + +where :math:`c_v^{id}` is the specific heat at constant volume. Mixture specific heat at constant volume is implemented through the routine `SRK_EOS_GetMixtureCv` + +.. code-block:: fortran + + subroutine SRK_EOS_GetMixtureCv(state) + implicit none + type (eos_t), intent(inout) :: state + real(amrex_real) :: tau, K1 + + state % wbar = 1.d0 / sum(state % massfrac(:) * inv_mwt(:)) + + call MixingRuleAmBm(state%T,state%massFrac,state%am,state%bm) + + tau = 1.0d0/state%rho + + ! Derivative of the EOS AM w.r.t Temperature - needed for calculating enthalpy, Cp, Cv and internal energy + call Calc_dAmdT(state%T,state%massFrac,state%am,state%dAmdT) + + ! Second Derivative of the EOS AM w.r.t Temperature - needed for calculating enthalpy, Cp, Cv and internal energy + call Calc_d2AmdT2(state%T,state%massFrac,state%d2AmdT2) + + ! Ideal gas specific heat at constant volume + call ckcvbs(state%T, state % massfrac, iwrk, rwrk, state % cv) + + ! Real gas specific heat at constant volume + state%cv = state%cv + state%T*state%d2AmdT2* (1.0d0/state%bm)*log(1.0d0+state%bm/tau) + + end subroutine SRK_EOS_GetMixtureCv + +Specific heat at constant pressure is given by + +.. math:: + + c_p = \left( \frac{\partial h_m}{\partial T}\right)_{p,Y} \;\; \\ + c_p = \frac{\partial h_m}{\partial T} - \frac {\frac{\partial h}{\partial \tau}} {\frac{\partial p}{\partial \tau}} \frac{\partial p}{\partial T} + +where all the derivatives in the above expression for SRK EOS are given by + +.. math:: + + \frac{\partial p}{\partial T} = \sum Y_k / W_k \frac{R}{\tau-b_m} - \frac{\partial a_m}{\partial T} \frac{1}{\tau(\tau +b_m)} \\ + \frac{\partial p}{\partial \tau} = -\sum Y_k / W_k \frac{R T}{(\tau-b_m)^2} + \frac{a_m (2 \tau + b_m)}{[\tau(\tau +b_m)]^2} \\ + \frac{\partial h_m}{\partial \tau} = -\left(T \frac{\partial a_m}{\partial T} - a_m \right) \frac{1}{\tau(\tau+b_m)} + \frac{a_m}{(\tau+b_m)^2} -\sum Y_k / W_k \frac{R T b_m}{(\tau-b_m)^2} \\ + \frac{\partial h_m}{\partial T} = c_p^{id} +T \frac{\partial^2 a_m}{\partial T^2} \frac{1}{b_m} ln ( 1 + \frac{b_m}{\tau}) - \frac{\partial a_m}{\partial T} \frac{1}{\tau+b_m} +\sum Y_k / W_k \frac{R b_m}{\tau-b_m} + +.. code-block:: fortran + + subroutine SRK_EOS_GetMixtureCp(state) + implicit none + type (eos_t), intent(inout) :: state + real(amrex_real) :: tau, K1 + real(amrex_real) :var: : Cpig + real(amrex_real) :: eosT1Denom, eosT2Denom, eosT3Denom + real(amrex_real) :: InvEosT1Denom,InvEosT2Denom,InvEosT3Denom + real(amrex_real) :: dhmdT,dhmdtau + real(amrex_real) :: Rm + + state % wbar = 1.d0 / sum(state % massfrac(:) * inv_mwt(:)) + + call MixingRuleAmBm(state%T,state%massFrac,state%am,state%bm) + + tau = 1.0d0/state%rho + + ! Derivative of the EOS AM w.r.t Temperature - needed for calculating enthalpy, Cp, Cv and internal energy + call Calc_dAmdT(state%T,state%massFrac,state%dAmdT) + + ! Second Derivative of the EOS AM w.r.t Temperature - needed for calculating enthalpy, Cp, Cv and internal energy + call Calc_d2AmdT2(state%T,state%massFrac,state%d2AmdT2) + + K1 = (1.0d0/state%bm)*log(1.0d0+state%bm/tau) + + eosT1Denom = tau-state%bm + eosT2Denom = tau*(tau+state%bm) + eosT3Denom = tau+state%bm + + InvEosT1Denom = 1.0d0/eosT1Denom + InvEosT2Denom = 1.0d0/eosT2Denom + InvEosT3Denom = 1.0d0/eosT3Denom + + Rm = (Ru/state%wbar) + + ! Derivative of Pressure w.r.t to Temperature + state%dPdT = Rm*InvEosT1Denom - state%dAmdT*InvEosT2Denom + + ! Derivative of Pressure w.r.t to tau (specific volume) + state%dpdtau = -Rm*state%T*InvEosT1Denom*InvEosT1Denom + state%am*(2.0*tau+state%bm)*InvEosT2Denom*InvEosT2Denom + + ! Ideal gas specific heat at constant pressure + call ckcpbs(state % T, state % massfrac, iwrk, rwrk,Cpig) + + ! Derivative of enthalpy w.r.t to Temperature + dhmdT = Cpig + state%T*state%d2AmdT2*K1 - state%dAmdT*InvEosT3Denom + Rm*state%bm*InvEosT1Denom + + ! Derivative of enthalpy w.r.t to tau (specific volume) + dhmdtau = -(state%T*state%dAmdT - state%am)*InvEosT2Denom + state%am*InvEosT3Denom*InvEosT3Denom - & + Rm*state%T*state%bm*InvEosT1Denom*InvEosT1Denom + + ! Real gas specific heat at constant pressure + state%cp = dhmdT - (dhmdtau/state%dpdtau)*state%dPdT + + end subroutine SRK_EOS_GetMixtureCp + +Internal energy and Enthalpy +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Similarly mixture internal energy for SRK EOS is given by + +.. math:: + e_m = \sum_k Y_k e_k^{id} + \left( T \frac{\partial a_m}{\partial T} - a_m \right)\frac{1}{b_m} ln \left( 1 + \frac{b_m}{\tau}\right) + +and mixture enthalpy :math:`h_m = e + p \tau` + +.. math:: + h_m = \sum_k Y_k h_k^{id} + \left ( T \frac{\partial a_m}{\partial T} - a_m \right) \frac{1}{b_m} \ln \left( 1 + \frac{b_m}{\tau}\right) + R T \sum \frac{Y_k}{W_k} \frac{b_m}{\tau -b_m} - \frac{a_m}{\tau + b_m} + +and the implementation can be found in the routine `SRK_EOS_GetMixture_H`. + +Speed of Sound +^^^^^^^^^^^^^^ + +The sound speed for SRK EOS is given by + +.. math:: + + a^2 = -\frac{c_p}{c_v} \tau^2 \frac{\partial p}{\partial \tau} + +Species enthalpy +^^^^^^^^^^^^^^^^ + +For computation of kinetics and transport fluxes we will also need the species partial enthalpies and the chemical potential. The species enthalpies for SRK EOS are given by + +.. math:: + + h_k = \frac{\partial h_m}{\partial Y_k } - \frac {\frac{\partial h}{\partial \tau}} {\frac{\partial p}{\partial \tau}} \frac{\partial p}{\partial Y_k} + +where + +.. math:: + \frac{\partial h_m}{\partial Y_k } &= h_k^{id} + (T \frac{\partial^2 a_m}{\partial T \partial Y_k} - \frac{\partial a_m }{\partial Y_k}) \frac{1}{b_m} \ln\left(1+ \frac{b_m}{\tau}\right) \\&-\left(T \frac{\partial a_m}{\partial T} - a_m \right) \left[ \frac{1}{b_m^2} \ln\left(1+ \frac{b_m}{\tau}\right) - \frac{1}{b_m(\tau+b_m)} \right ] \frac{\partial b_m}{\partial Y_k} \nonumber \\&+ \frac{a_m}{(\tau+b_m)^2} \frac{\partial b_m}{\partial Y_k} - \frac{1}{\tau+b_m} \frac{\partial a_m}{\partial Y_k} + 1 / W_k \frac{R T b_m}{\tau-b_m}\\&+\sum_i \frac{Y_i}{W_i} R T \left( \frac{1}{\tau -b_m} + \frac{b_m}{(\tau-b_m)^2} \right) \frac{ \partial b_m}{\partial Y_k} + +.. math:: + + \frac{\partial p}{\partial Y_k} &= R T \frac{1}{W_k} \frac{1}{\tau - b_m} - \frac{\partial a_m}{\partial Y_k} \frac{1}{\tau(\tau + b_m)} \\&+\left(R T \sum \frac{Y_i}{W_i} \frac{1}{(\tau - b_m)^2} + \frac{a_m}{\tau(\tau + b_m)^2} \right ) \frac{\partial b_m}{\partial Y_k} + +Chemical potential +^^^^^^^^^^^^^^^^^^ + +The chemical potentials are the derivative of the free energy with respect to composition. Here the free energy `f`` is given by + +.. math:: + f &= \sum_i Y_i (e_i^{id} - T s_i^{id,*}) + \sum_i \frac{Y_i R T}{W_i} ln (\frac{Y_i R T}{W_i \tau p^{st}}) \nonumber \\ &+ \sum_i \frac{Y_i R T}{W_i} ln (\frac{\tau}{\tau-b_m}) - a_m \frac{1}{b_m}ln (1+ \frac{b_m}{\tau}) \nonumber \\ &= \sum_i Y_i (e_i^{id} - T s_i^{id,*}) + \sum_i \frac{Y_i R T}{W_i} ln (\frac{Y_i R T}{W_i (\tau-b_m) p^{st}} )- a_m \frac{1}{b_m} ln (1+ \frac{b_m}{\tau}) \nonumber + +Then + +.. math:: + + \mu_k &= \frac{\partial f}{\partial Y_k} = e_k^{id} - T s_k^{id,*} + \frac{RT}{W_k} ln (\frac{Y_k R T}{W_k (\tau-b_m) p^{st}}) + \frac{RT}{W_k} + \frac{RT}{\bar{W}} \frac{1}{\tau-b_m} \frac {\partial b_m}{\partial Y_k} \nonumber \\ + &- \frac{1}{b_m} ln(1 + \frac{b_m}{\tau}) \frac{\partial a_m}{\partial Y_k}+ \frac{a_m}{b_m^2} ln(1 + \frac{b_m}{\tau}) \frac{\partial b_m}{\partial Y_k}- \frac{a_m}{b_m} \frac{1}{\tau+b_m} \frac{\partial b_m}{\partial Y_k} + +Other primitive variable derivatives +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The Godunov (FV) algorithm also needs some derivatives to express source terms in terms of primitive variables. In particular one needs + +.. math:: + + \left . \frac{\partial p}{\partial \rho} \right|_{e,Y} =-\tau^2 \left( \frac{\partial p}{\partial \tau}- \frac {\frac{\partial e}{\partial \tau}} {\frac{\partial e}{\partial T}} \frac{\partial p}{\partial T} \right ) + +and + +.. math:: + + \left . \frac{\partial p}{\partial e} \right|_{\rho,Y} = \frac{1}{c_v} \frac{\partial p}{\partial T} + +All of the terms needed to evaluate this quantity are known except for + +.. math:: + + \frac{\partial e}{\partial \tau} = \frac{1}{\tau ( \tau + b_m)} \left( a_m - T \frac{\partial a_m}{\partial T} \right) \;\; . diff --git a/_sources/GettingStarted.rst.txt b/_sources/GettingStarted.rst.txt new file mode 100644 index 000000000..59d406466 --- /dev/null +++ b/_sources/GettingStarted.rst.txt @@ -0,0 +1,98 @@ +.. highlight:: rst + +************************ +`PelePhysics` Quickstart +************************ + +Greetings impatient user. As a word of caution, this documentation is in progress. Some parts of the code remain undocumented, +and some parts of the documentation are out of data. If you are confused by something you read here, or otherwise +need help with `PelePhysics`, the best course of action is to open a Discussion on the `GitHub page `_, +so the development team and other users can help. + +- If you are a complete beginner, I urge you to carefully read the two following chapters :ref:`sec:GetPP` and :ref:`sec:GetCVODE`, to properly set-up your working environment. +- If you are familiar with `PelePhysics`, have it installed already and would simply like to know which chemistry-related keywords and/or environment variables to set in your various input files to perform a simulation with one of the codes available in the `PeleSuite`, then I invite you to directly skip to section :ref:`sec:subsPPOptions`. +- If you are in a hurry but still would like more context, visit section :ref:`sec:subsWD` to be referred to portions of this document that are of interest to you. + +.. _sec:GetPP: + +Obtaining `PelePhysics` +======================= + +PelePhysics is primarily intended as a library for use in the other `Pele codes `_, and is automatically downloaded as +a submodule of both PeleC and PeleLMeX. However, it can also be used as a stand-alone solver for chemical reactions and thermodynamic properties, +or as a library for other codes. Instructions for how to obtain `PelePhysics` for these purposes are provided here. + +First, make sure that "Git" is installed on your machine---we recommend version 1.7.x or higher. Then... + +1. Clone the `PelePhysics` repository and its submodules: :: + + git clone --recursive https://github.com/AMReX-Combustion/PelePhysics.git + + This will create a ``PelePhysics`` directory on your machine. The ``--recursive`` option ensures that the required :ref:`sec:GetCVODE` are also downloaded to the + ``PelePhysics/Submodules`` directory. Set the environment variable ``PELE_PHYSICS_HOME`` to point to the location of this folder (``export PELE_PHYSICS_HOME=$(pwd)/PelePhysics``) + +2. Periodically update the repository and its dependencies by typing ``git pull && git submodule update`` within the repository. + + +.. _sec:GetCVODE: + +Dependencies +============ + +PelePhysics has two required dependencies: `AMReX `_ and `SUNDIALS `_. +These dependencies are shipped with PelePhysics as git submodules and the proper versions are cloned to the ``PelePhysics/Submodules/`` directory automatically when +doing the recursive git clone described in :ref:`sec:GetPP`. Users also have the option to download their own versions of these dependencies elsewhere on their machine, in which case +the paths to these libraries must be specified by exporting ``AMREX_HOME`` and ``SUNDIALS_HOME`` environment variables or defining these variables in +the ``GNUmakefile`` when building. + +1. `AMReX` is a library that provides data structures and methods for operating on data in the context of + block-structured adaptive mesh refinement that are used throughout the Pele suite of codes. + +2. `SUNDIALS` is a library of differential and algebraic equation solvers that is used by PelePhysics + primarily for its CVODE package for implicit solution of stiff ODE systems. CVODE is used for integration of stiff chemical reaction systems in PelePhysics. + +PelePhysics has two optional dependencies: `SuiteSparse `_ and `MAGMA `_. +These dependencies are not shipped with PelePhysics by default, but the proper versions are automatically downloaded if needed during the building +process (:ref:`sec:BuildingRunning`). Both of these dependencies are libraries that aid in solving the linear systems that arise during implicit integration of a chemical system using CVODE. +There are several other options available for solvers within CVODE, so these libraries are not strictly required, but they may enable options that +lead to better performance on certain computing architectures. + +1. `SuiteSparse` is a suite of Sparse Matrix software that is very handy when dealing with big kinetic mechanisms (the Jacobian of which are usually very sparse). + In such a case, CVODE can make use of the KLU library, which is part of `SuiteSparse`, to perform sparse linear algebra. + Documentation and further information can be found on `SuiteSparse website `_. + +2. `MAGMA` is a collection of linear algebra libraries for heterogeneous computing. + + +.. _sec:BuildingRunning: + +Building and Running Test Cases +=============================== + +PelePhysics has several short programs that are used to test its various capabilities, located in the ``Testing/Exec`` directory. For example, +we will consider the `ReactEval` case, which tests the chemical reaction integration capability. :: + + cd ${PELE_PHYSICS_HOME}/Testing/Exec/ReactEval + +The ``GNUmakefile`` in this directory specifies several key build options, like the compiler (``COMP``) and whether it will be a debug (``DEBUG``) build. + +First, build the necessary dependencies. `SUNDIALS` is always built. +`SuiteSparse` is downloaded and built if ``PELE_USE_KLU = TRUE`` is specified in the ``GNUmakefile``. +`MAGMA` is downloaded and built if ``PELE_USE_MAGMA = TRUE`` is specified in the ``GNUmakefile``. +All dependencies are installed in the ${PELE_PHYSICS_HOME}/ThirdParty directory. For a given set of +compile-time options, this step only needs to be done once, but it needs to be redone whenever compile-time +options are changed :: + + make TPL + +Now, build the `ReactEval` executable (the ``-j 4`` option specified to compile in parallel on 4 processors): :: + + make -j 4 + +To run the program, execute: :: + + ./Pele3d.gnu.ex inputs.3d-regt_GPU + +If you need to clean your build, you can run :: + + make TPLrealclean && make realclean diff --git a/_sources/Introduction.rst.txt b/_sources/Introduction.rst.txt new file mode 100644 index 000000000..bafaab84d --- /dev/null +++ b/_sources/Introduction.rst.txt @@ -0,0 +1,88 @@ +.. highlight:: rst + +.. _sec:subsWD: + +************ +Introduction +************ + +Objectives and State-Of-The-Art +=============================== + +What we will call the `PeleSuite` is currently composed of 3 separate codes: + +- `PelePhysics `_ is a repository of physics databases and implementation code for use within the other `Pele` codes. In particular, the choice of chemistry and transport models as well as associated functions and capabilities are managed in `PelePhysics`. +- `PeleLM `_ is an adaptive-mesh Low-Mach number hydrodynamics code for reacting flows. It has a sibling, `PeleLMeX `_, that solves for the same type of flow using a subtly different numerical approach. +- `PeleC `_ is an adaptive-mesh compressible hydrodynamics code for reacting flows. + +All three codes rely on `AMReX `_, which is a software frameworks that provides the data structure and enable massive parallelization. + +.. |a| image:: ./Visualization/PeleSuite.png + +.. table:: + :align: center + + +-----+ + | |a| | + +-----+ + + + +`PelePhysics` (as well as the `ChemDriver` object of `PeleLM` ) used to rely upon DVODE [VODE1989]_ +to perform the chemistry integration, no matter the problem at hand. +DVODE is a very robust, but slightly outdated, variable-coefficient Ordinary Differential Equation (ODE) solver written in Fortran 77. +At its core, it uses a direct dense linear solver. DVODE is very efficient in the resolution of small stiff systems +of equations but can become prohibitively expensive when dealing with bigger systems of equations, such as those frequently encountered in combustion systems. + +In recent years, the Sundials team at LLNL [LLNL2005]_ has been involved in the active development of a modern, +C++ version, of DVODE called CVODE. +CVODE implements the same functionalities as those available in DVODE, but offers much more flexibility through +its user-friendly set of interface routines. Additionally, other linear solvers are available, +such as iterative or sparse solvers which can prove to be very efficient in handling "larger" systems of equations. + +The objective of this user-guide is to document the CVODE-based chemistry integration implemented in `PelePhysics`. Although it is possible to use CVODE in `PeleC`, the following is mainly intended for `PeleLM` users. This user-guide will cover: + +- ODE equations (`reactor type`) +- Default settings (tolerances/order/...) +- Linear solvers available --along with examples of performance +- Setting-up a `PelePhysics` test case +- ... + + + +How to naviguate this documentation +=================================== + +`This section provides a short overview of the chemistry-related features of PelePhysics. For an in-depth discussion, relevant references to specific sections of this manuscript are given.` + + +- In `PelePhysics`, the user can select between **two different reactor types**. + The first type is a `constant volume` reactor, were the choice of fixed variables are the internal energy and the density, + to comply with `PeleC` transported variables. This reproduces what was originally + implemented with DVODE in `PelePhysics`. + A second reactor type formulated in terms of enthalpy and density has been put in place, to comply with `PeleLM`. + Both reactors are available in DVODE (in fortran 90) and CVODE (in cpp). + See sections :ref:`sec:subsDiffReacts` for additional details, + and :ref:`sec:subsPPOptions` to see how to activate one or the other via the input files. + +- With both reactors, it is possible to use an **Analytical Jacobian** (depending upon the choice of linear solver, see section :ref:`sec:subslinalg`.) + +- Three different types of **linear solvers** are implemented, see section :ref:`sec:subslinalg` for additional details, and :ref:`sec:subsPPOptions` to see how to make a selection: + + - a dense direct solver -- with or without Analytical Jacobian + - a sparse direct solver (requires the KLU library) -- always requires an Analytical Jacobian + - a couple of sparse iterative solvers from the GMRES family -- preconditioned or not + +- **Regression testings** have been put in place in `PelePhysics` to test the CVODE integration. See section :ref:`sec:subsubValidCVreact` for validations, and section :ref:`sec:subsReactEvalCvode` for a step-by-step example. + +- A CVODE version running on **GPU** is also technically available but the documentation is a WIP. The interested user can + contact code developers for additional information + +- `PelePhysics` uses an automatic chemistry-related routine generator: + **CEPTR**. CEPTR is part of the sources of `PelePhysics`. With + CEPTR, a unique chemistry file is generated for a specific kinetic + scheme. Instructions to generate your own chemistry files (all you + need are chemistry files in the famous `Cantera + `_ yaml format) are discussed in section + :ref:`sec:ceptr`. Note that `PelePhysics` already offers a large + choice of more than 20 different kinetic schemes. diff --git a/_sources/IntroductionToCvode.rst.txt b/_sources/IntroductionToCvode.rst.txt new file mode 100644 index 000000000..27930ad3c --- /dev/null +++ b/_sources/IntroductionToCvode.rst.txt @@ -0,0 +1,114 @@ +.. highlight:: rst + +A brief introduction to CVODE +============================= + +CVODE is part of a software family called sundials for SUite of Nonlinear and DIfferential / ALgebraic equation Solver [LLNL2005]_. + +**The version used with PelePhysics for the tests presented in this document is v4.0.2. This does not mean this is the recommended version to link with PelePhysics. Always refer to** :ref:`sec:GetCVODE` **to know which versions of CVODE/SuiteSparse to use !!** + +In the following, details pertaining to the methods implemented in `PelePhysics` are provided. +The interested user is referred to the very exhaustive `CVODE User-guide `_ for more information. + +`Most of this section is adapted from the v4.1.0 Cvode Documentation.` + +.. _sec:NMO: + +Numerical methods overview +-------------------------- + +The methods implemented in CVODE are variable-order, variable-step `multistep` methods, based on formulas of the form + +.. math:: + + \sum_{i=0}^{K_1} \alpha_{n,i} y^{n-i} + h_n \sum_{i=0}^{K_2} \beta_{n,i} \dot{y}^{n-i} = 0 + +Here the :math:`y^n` are computed approximations to :math:`y(t_n)`, and :math:`h_n = t_n-t_{n-1}` is the step size. +For stiff problems, CVODE includes the Backward Differentiation Formulas (BDF) in so-called fixed-leading coefficient (FLC) form, +given by :math:`K_1=q` and :math:`K_2= 0`, with order :math:`q` varying between 1 and 5. The coefficients are uniquely determined by the method type, +its order, the recent history of the step sizes, and the normalization :math:`\alpha_{n,0}=-1` [BYRNE1975]_, [JAC1980]_. + +A nonlinear system must be solved (approximately) at each integration step. This nonlinear system can be formulated as a root-finding problem + +.. math:: + + F(y^{n}) = y^n - h_n \beta_{n,0} f(t_n,y^{n}) - a_n = 0 + +where :math:`a_n = \sum_{i>0} (\alpha_{n,i} y^{n-i} + h_n\beta_{n,i} \dot{y}^{n-i})`. CVODE provides several non-linear solver choices. +By default, CVODE solves this problem with a Newton iteration, which requires the solution of linear systems + +.. math:: M[y^{n(m+1)} - y^{n(m)}] = -F(y^{n(m)}) + :label: eqc + +in which + +.. math:: + M \approx I-\gamma J, \; \; \; J = \frac{\partial f}{ \partial y}, \;\;\; and \;\;\; \gamma = h_n \beta_{n,0} + + +.. _sec:subslinalg: + +Linear Algebra +-------------- + +To find the solution of the linear system :eq:`eqc`; CVODE provides several linear solver choices. +The linear solver modules distributed with Sundials are organized in two families, a `direct` family comprising direct linear solvers +for dense, banded, or sparse matrices, and a `spils` family comprising scaled preconditioned iterative (Krylov) linear solvers. +The solvers offered through these modules that are of interest to us are: + +- a dense direct solver +- a sparse direct solver interface using the `KLU` sparse solver library +- SPGMR, a scaled -possibly preconditioned- GMRES (Generalized Minimal Residual method) solver [BROWN1990]_ + +When using a dense direct solver, the user has the option to specify an Analytical Jacobian. +If none is provided, a difference quotients is performed. When a sparse direct solver is employed however, +the user **must** specify an analytical Jacobian. All of these options have been enabled in `PelePhysics`. + +For large stiff systems, where direct methods are often not feasible, the combination of a BDF integrator and a `preconditioned` Krylov method +yields a powerful tool. In this case, the linear solve is `matrix-free`, and the default Newton iteration is an +`Inexact` Newton iteration, in which :math:`M` is applied with matrix-vector products :math:`Jv` obtained by either difference quotients +or a user-supplied routine. In `PelePhysics`, it is possible to use either a non-preconditioned or a preconditioned GMRES solver. +In the latter case, the preconditioner can be either specified in a dense or sparse format (if the KLU library is linked to CVODE), +and it is provided in the form of a Jacobian approximation, based on the work of [McNenly2015]_. + + + +Error control, step-sizing, order determination +----------------------------------------------- + +In the process of controlling errors at various levels, CVODE uses a weighted root-mean-square norm, +denoted :math:`|| \bullet ||_{WRMS}`, for all error-like quantities. The multiplicative weights used are based +on the current solution and on the relative and absolute tolerances input by the user, namely + +.. math:: + + W_i= \frac{1}{[rtol |y_i|+atol_i]} + +Because :math:`1/W_i` represents a tolerance in the component :math:`y_i`, a vector whose norm is 1 is regarded as small. +In `PelePhysics`, both these tolerances are fixed to a value of :math:`1.0e-10`. + +A critical part of CVODE - making it an ODE `solver` rather than just an ODE method, is its control +of the local error. At every step, the local error is estimated and required to satisfy tolerance conditions, +and the step is redone with reduced step size whenever that error test fails. +Note that in `PelePhysics`, the first time step is always forced to :math:`1.0e-9`. + +In addition to adjusting the step size to meet the local error test, CVODE periodically adjusts the order, +with the goal of maximizing the step size. The integration starts out at order 1 and varies the order dynamically after that. +The basic idea is to pick the order :math:`q` for which a polynomial of order :math:`q` best fits the discrete data involved +in the multistep method. In `PelePhysics`, the maximum order is limited to 2 for stability reasons. + +The various algorithmic features of CVODE are inherited from VODE and VODPK, and are documented in [VODE1989]_ and [BROWN1990]_. +They are also summarized in the `CVODE User-guide `_ as well as in [LLNL2005]_. + + +.. [LLNL2005] A. C. Hindmarsh, P. N. Brown, K. E. Grant, S. L. Lee, R. Serban, D. E. Shumaker, and C. S. Woodward. SUNDIALS: Suite of nonlinear and differential/algebraic-equation solvers. ACM Transactions on Mathematical Software (TOMS), 31(3):363-396, 2005. + +.. [BYRNE1975] G. D. Byrne, A. C. Hindmarsh. A polyalgorithm for the numerical solution of ordinary differential equations. ACM Transactions on Mathematical Software (TOMS), 1(1):71-96, 1975. + +.. [JAC1980] K. R Jackson and R. Sacks-Davis. An alternative implementation of variable step-size multistep formulas for stiff odes. ACM Transactions on Mathematical Software (TOMS), 6(3):295–318, 1980. + +.. [BROWN1990] P. N. Brown and Y. Saad. Hybrid krylov methods for nonlinear systems of equations. SIAM Journal on Scientific and Statistical Computing, 11(3):450–481, 1990. + +.. [McNenly2015] M. J. McNenly, R. A. Whitesides, and D. L. Flowers. Faster solvers for large kinetic mechanisms using adaptive preconditioners. Proceedings of the Combustion Institute, 35(1):581–587, 2015. + +.. [VODE1989] P. N. Brown, G. D. Byrne, and A. C. Hindmarsh. VODE, a variable-coefficient ODE solver. SIAM journal on scientific and statistical computing, 10(5):1038-1051, 1989. diff --git a/_sources/QSS.rst.txt b/_sources/QSS.rst.txt new file mode 100644 index 000000000..e83e8d6eb --- /dev/null +++ b/_sources/QSS.rst.txt @@ -0,0 +1,178 @@ +.. _sec_qss: + +.. highlight:: rst + +.. role:: cpp(code) + :language: c++ + +Analytically reduced chemistry via quasi-steady state (QSS) assumption in `PelePhysics` +======================================================================================= + +.. _sec:QSSAssumption: + +The QSS assumption +------------------ + +Given a detailed chemical mechanism, some species can sometimes be assumed to be in a `quasi-steady state (QSS)`. +Formally, if species :math:`A` is assumed to be in a QSS then + +.. math:: + + \frac{\partial [A]}{\partial t} = 0, + +where :math:`[A]` is the molar concentration of species :math:`A`. +If the set of QSS species is judiciously chosen, macroscopic quantities of interest such as ignition delay or laminar flame speed are only mildly affected by the QSS assumption [DRG2005]_. + +.. _sec:advantageQSS: + +The advantage of the QSS assumption +----------------------------------- + +Using the elementary reactions of the chemical mechanism, it is possible to write a set of algebraic equations that relate `QSS species` to `non-QSS species`. In turn, it is not necessary to transport the `QSS species` in the flow solver, as their concentration can be directly obtained from the `non-QSS species`. + +In addition, `QSS species` are typically species that induce stiffness in the chemical mechanism since they evolve on scales different that the `non-QSS species`. + +.. _sec:invertAlgebraicSystem: + +From `non-QSS species` to `QSS species` concentration +----------------------------------------------------- + +The set of algebraic equations that result from the QSS assumption does not always easily result in a simple algebraic relation between a given `QSS species` and all the `non-QSS species`. To do this, it is necessary to apply some form of linearization to the reactions involved [SYS2006]_. In addition, even in the presence of linear relations, `QSS species` may depend on one another. The following figure shows the relation graph between the `QSS species` of a reduced :math:`N-C_{12}H_{26}` mechanism [ND2018]_. The arrows indicate that a `QSS species` concentration depends on another `QSS species` concentration. It can also be seen that dependency groups exist among the `QSS species`. In `PelePhysics` it is possible to deduce invert analytically the linear system of equations given an arbitrary relation graph. + +.. _fig:DepGraph: + +.. figure:: ./Visualization/directedGraphQSS.png + :width: 90% + :align: center + :name: fig-DRG + :target: ./Visualization/directedGraphQSS.png + :alt: Directed graph of dependencies between QSS species + + Relation graph between QSS species for N-dodecane mechanism [ND2018]_ + + +.. _sec:linearizing: + +Linearizing the set of equations +-------------------------------- + +In general, the QSS assumption results in a set of equations that are non-linearly coupled making it difficult to invert the system. The non-linear relations can arise if two or more `QSS-species` are on the same side of an elementary reaction, or if the stoichiometric coefficient of a `QSS-species` is not equal to one. Below, the relation graph between the QSS species plotted above is expanded with dots that denote reactions that relate `QSS-species`. Dots or species are colored in red if they are involved in a quadratic coupling. + + +.. _fig:QuadGraph: + +.. figure:: ./Visualization/quadGraphQSS.png + :width: 90% + :align: center + :name: fig-Quad + :target: ./Visualization/quadGraphQSS.png + :alt: Graph of dependencies between QSS species augmented with reactions. + + Graph of dependencies between QSS species for N-dodecane mechanism [ND2018]_, augmented with reactions. Red species or dots denote species and reactions involved in quadratic coupling. + + +From here, it is necessary to eliminate the quadratic coupling to linearize the set of algebraic equations that result from the QSS assumption. Three methods can be envisioned: either one relaxes the QSS assumption by reducing the set of `QSS species` (Method 1) or one can eliminate the reactions that induce quadratic coupling. In case reactions are reversible, it can happen that either the forward or the backward reaction induces the quadratic coupling. Either one can remove both the forward and the backward reaction (Method 2) or remove either the backward or the forward reaction (Method 3). + +All three methods are available in `PelePhysics`. By default, Method 3 is activated as it is computationally efficient and accurate (as will be shown below). Method 1 is the most accurate and Method 2 is the most computationally efficient in our experience. Given that each method has its advantage, we decided to allow the user to choose either one according to his/her needs. + +.. _sec:validation: + +Validation +---------- + +The three linearization methods are validated against the skeletal :math:`N-C_{12}H_{26}` [SKEL2017]_. Using 343 0D calculation that span the range of applicability of the QSS assumption (:math:`\phi = [0.5, 2.0], p=[1atm, 50atm], T=[800K, 1600K]`), the ignition delay is computed using the skeletal mechanism (SK53) and each one of the three linearization methods for the QSS mechanism (RedXX). The left plot shows the correlation between the ignition delay from the skeletal mechanism and the reduced version. The statistics of the relative error between the reduced and the skeletal mechanism are shown in the title of that plot. The right plot shows the ignition delay values at high-pressure conditions only. + + +.. _fig:val: + +.. figure:: ./Visualization/validationQSS.png + :width: 90% + :align: center + :name: fig-val + :target: ./Visualization/validationQSS.png + :alt: Validation of linearization method + + Left: Scatter plot of the ignition delay measured with the QSS mechanism linearized and the skeletal mechanism. + Right: Ignition delays measured for the skeletal mechanism and QSS mechanism linearized at high-pressure conditions. + Top: Method 1. Middle: Method 2. Bottom: Method 3. + + +Analytical Jacobian +------------------- + +In several computational experiments, using analytical Jacobians was found to provide better stability or efficiency compared with finite difference approximation or numerical inversion (see also fig:qss_integrator_). +Compared with non-QSS mechanisms, analytical Jacobians need to reflect the dependence of each QSS species on non-QSS species. However, QSS species may depend on an ensemble of other non-QSS species and therefore ensemble of reactions. Therefore, analytical Jacobian cannot be constructed by sequentially adding the contribution of each reaction. This significantly complicates the analytical jacobian generation. Failure to include the dependence of QSS species with respect to non-QSS species typically results in wrong ignition profiles, unless very small timesteps are used, as seen in figure fig:qss_aj_. + + +.. _fig:qss_aj: + +.. figure:: ./Visualization/aj_0D_QSS.png + :width: 90% + :align: center + :name: fig-qss-constant + :target: ./Visualization/aj_0D_QSS.png + :alt: + + Temperature of a 0D reactor at constant pressure for NC12H26. Initial temperature is 600K, initial molar fraction of O2 is 0.7 and initial molar fraction of fuel is 0.3. + Left: Results without inclusion of dependence of QSS species with respect to non-QSS species. + Right: Result with inclusion of dependence of QSS species with respect to non-QSS species. + + +To ease the implementation of analytical Jacobian in presence of QSS species, a symbolic approach is used to construct the analytical Jacobian. This strategy has the advantage of not requiring complex logic, and being flexible and readable for future development. For the last row of the Jacobian (partial difference of reaction rate with respect to temperature), finite difference is used since perturbations in temperature are less susceptible to numerical errors than perturbations in species concentrations. During the construction of the reaction rates, the operations printed to file are recorded symbolically using the ``sympy`` and ``symengine`` library [SYMPY]_. For computational efficiency during the symbolic differentiation, the chain-rules terms are computed and the final expressions are computed and assembled by chain-ruling using logic internal to `CEPTR` rather than ``sympy``. We have found that this speeds up the Jacobian construction cost by a factor 10. + +To activate the use of symbolic jacobian, one needs to pass the flag ``--qss_symbolic_jacobian`` to `CEPTR`. + +Printing the Jacobian terms one by one is not possible since the expressions that include QSS species are typically very large. Instead, the expressions are reduced via common sub-expression precomputing that are later used in each term of the Jacobian. The number of subexpressions may be orders of magnitude larger than the number of Jacobian entries which can be problematic if the computational architecture has limited memory. + +Several formatting strategies have been implemented to mitigate the memory footprint of the symbolic Jacobian. They can be adjusted by providing a ``.toml`` file to `CEPTR` via the ``qss_format_input`` flag. A model input file is provided in the `Tutorials` section of this documentation. A model execution script for generating a mechanism for ``dodecane_lu_qss`` is available under the `Tutorials` section of this documentation. + +The formatting options are the following + +.. _optimCuda: https://docs.nvidia.com/cuda/cuda-c-best-practices-guide/index.html + +* ``hformat`` **(string)** + * ``cpu`` will print intermediate variables used for chainruling. This gives a "readable" version of the Jacobian entries, albeit memory consuming. + * ``gpu`` will not print intermediate variables used for chainruling, and instead will replace them directly in the Jacobian entries. This gives a less readable version of the Jacobian, but more memory efficient. +* ``remove_1`` **(boolean)** will replace expressions of the type ``1.0 * xxx`` into ``xxx``. +* ``remove_pow`` **(boolean)** will convert expressions of the type ``pow(xxx,n)`` into multiplications or division. The conversion occurs for ``n<=3`` and ``n>=-3`` consistent with optimCuda_ +* ``remove_pow10`` **(boolean)** will convert expressions of the type ``pow(10,xxx)`` into ``exp(ln(10)*xxx)``, consistent with optimCuda_ +* ``min_op_count`` **(integer)** counts number operations used to construct each common subexpression and replace the common subexpression if the number of operations is less or equal to ``n`` +* ``min_op_count_all`` **(integer)** is similar to ``min_op_count`` but also counts how many times that common subexpression is used later. The meaning of ``n`` is different than for ``min_op_count`` as it refers to how many more operations will be done if the common subexpression is eliminated. This option should be preferred to ``min_op_count`` as it tends to only marginally increase the file size (therefore compile time), while still being memory efficient. +* ``gradual_op_count`` **(boolean)** is useful if ``min_op_count`` or ``min_op_count_all`` are active. It loops from 1 to ``n`` and gradually eliminate the common subexpressions. This has the advantage of ensuring that the memory footprint is strictly monotonically decreasing as `n` is increased. +* ``store_in_jacobian`` **(boolean)** will use the Jacobian array as a temporary space to store intermediate variables. In particular, the last row of the Jacobian (dependence with respect to temperature) is done by finite difference which requires storing intermediate variables (production rate, forward and backward reactions). When the option is active, the ``productionRate`` function used to compute the finite difference is replaced with a ``productionRate_light`` functions where references to different parts of the Jacobian are used in place of allocating new arrays. +* ``round_decimals`` **(boolean)** will round floats printed by ``sympy`` when possible to minimize character count in the ``mechanism.H`` file. +* ``recycle_cse`` **(boolean)** will reuse subexpressions that are not used later to avoid declaring new temporary reals. +* ``remove_single_symbols_cse`` **(boolean)** will remove common subexpressions that are made of 1 operation and 1 symbol. Those common subexpressions are typically ``-xxx`` and may not appear as worth replacing because they save 1 operations and are reused multiple times. However, when replaced in the later expressions, the ``-`` operations typically disappear or is merged into another operations which actually does not increase the total number of operations. + +The analytical Jacobian for QSS mechanisms is typically more accurate and stable than GMRES, and is on par with the finite difference Jacobian of `CVODE` as seen in fig:qss_integrator_ + + +.. _fig:qss_integrator: + +.. figure:: ./Visualization/qss_integrator.png + :width: 70% + :align: center + :name: fig-qss-integrator + :target: ./Visualization/qss_integrator.png + :alt: + + Temperature of a 0D reactor at constant pressure for NC12H26. Initial temperature is 600K, initial molar fraction of O2 is 0.7 and initial molar fraction of fuel is 0.3. Results are shown for finite difference jacobian (red thick line), analytical jacobian (black line) and GMRES (crosses) using the same tolerances. + +In terms of speed, the analytical Jacobian 0D reactor is faster on CPU than finite difference Jacobian and GMRES. For the piston bowl challenge problem, the analytical Jacobian relative speed depends on the prevalence of chemical reactions. At some points, the AJ is slower than GMRES with PeleC, at others, AJ is faster. In PeleLM cases, AJ was found to be faster than GMRES. Further optimization and tests are still ongoing. + + +Using the Analytical Jacobian +----------------------------- + +To use the analytic Jacobian QSS mechanisms in a Pele run, one must specify the correct ``solve_type``. The choice of the ``solve_type`` will determine whether or not the analytic Jacobian is used. With CUDA, both ``magma_direct`` and ``sparse_direct`` will use the analytic Jacobian, while on HIP only ``magma_direct`` will trigger the use of the analytic Jacobian parts. + + +.. [DRG2005] T. Lu, C. K. Law, A directed relation graph method for mechanism reduction, Proceedings of the combustion institute, 30(1):1333-1341, 2005. + +.. [SYS2006] T. Lu, C. K. Law, Systematic approach to obtain analytic solutions of quasi steady state species in reduced mechanisms, The Journal of Physical Chemistry A, 110(49):13202-13208, 2006. + +.. [ND2018] G. Borghesi, A. Krisman, T. Lu, J. H. Chen, Direct numerical simulation of a temporally evolving air/n-dodecane jet at low-temperature diesel-relevant conditions, 195:183-202, 2018. + +.. [SKEL2017] T. Yao, Y. Pei, B. J. Zhong, S. Som, T. Lu, K. H. Luo, A compact skeletal mechanism for n-dodecane with optimized semi-global ! low-temperature chemistry for diesel engine simulations, 191:339-349, 2017. + +.. [SYMPY] A. Meurer, C. P. Smith, M. Paprocki, O. \v{C}ert\'{i}k, S. B. Kirpichev, M. Rocklin, A. Kumar, S. Ivanov, J. K. Moore, S. Singh, T. Rathnayake, S. Vig, B. E. Granger, R. P. Muller, F. Bonazzi, H. Gupta, S. Vats, F. Johansson, F. Pedregosa, M. J. Curry, A. R. Terrel, S. Rou\v{c}ka, A. Saboo, I. Fernando, S. Kulal, R. Cimrman, A. Scopatz, SymPy: symbolic computing in Python, 3:e103, 2017. diff --git a/_sources/Soot.rst.txt b/_sources/Soot.rst.txt new file mode 100644 index 000000000..488a69f02 --- /dev/null +++ b/_sources/Soot.rst.txt @@ -0,0 +1,49 @@ +.. highlight:: rst + +.. _Soot: + +**** +Soot +**** + +Soot Equations +============== + +Soot formation, growth, and oxidation is modeled using the hybrid-method of moments (HMOM) model developed by Mueller et al. [#mueller]_. This approach combines the numerical ease of the method of moments with interpolative closure (MOMIC) with the ability to capture the bimodal nature of the soot number density function (NDF) provided by the direct quadrature method of moments (DQMOM). :math:`M_{x,y}` is the moment of the soot NDF, where :math:`x` is the order for volume and :math:`y` for surface area; these terms are modeled according to + +.. math:: + M_{x,y} = N_0 V_0^x S_0^y + \exp{\left(\sum_{r=0}^R \sum_{k = 0}^r a_{r,k} x^k y^{r-k}\right)}, + +where :math:`R` is the order of the polynomial interpolation, :math:`a_{r,k}` are the interpolation coefficients, :math:`N_0` is the weight of the delta function, and :math:`V_0` and :math:`S_0` are the volume and surface area of the nucleated spherical soot particles, respectively. The location of the delta function is fixed at coordinates :math:`V_0` and :math:`S_0` and assumed to be equal to the nucleated particle size. +The nucleated particle volume and surface area are fixed according to :math:`V_0 = 2 W_C C_{\rm{dimer}} / \rho_{\rm{soot}}` and :math:`S_0 = (36 \pi)^{1/3} V_0^{2/3}`, where :math:`W_C` is the molar mass of carbon, :math:`C_{\rm{dimer}}` is the average number of carbon atoms per dimer, and :math:`\rho_{\rm{soot}}` is the density of soot (:math:`\rho_{\rm{soot}} = 1800 {\text{ kg/m}}^3`). If the first-order polynomial interpolation of the moments (:math:`R=1`) is used, the above equation reduces to + +.. math:: + M_{x,y} = N_0 V_0^x S_0^y + N_L V_L^x S_L^y, + +where :math:`V_L` and :math:`S_L` are the mean volume and surface area of the second mode (large particles). For first-order polynomial interpolation, four transport equations are solved: :math:`M_{0,0}` (number density), :math:`M_{1,0}` (volume fraction, also denoted as :math:`f_v`), :math:`M_{0,1}`, and :math:`N_0`. +The governing equations for the soot moments are [#bisetti]_ + +.. math:: + \frac{\partial M_{x,y}}{\partial t} + \frac{\partial M_{x,y} \mathbf{u}_g}{\partial \mathbf{X}} = -\frac{\partial \boldsymbol{J}_{M}}{\partial \mathbf{X}} + \dot{M}_{x,y}, + +where :math:`\boldsymbol{J}_{M}` is the soot mass flux and :math:`\dot{M}_{x,y}` is the soot source term. +The current formulation ignores the molecular diffusion and thermophoretic effects of the soot, making the first term of the right-hand side zero. + +For more details regarding the HMOM model, users are encouraged to consult the references cited. + +Soot Flags and Inputs +====================== + +* In the ``GNUmakefile``, specify ``USE_SOOT = TRUE`` and ``NUM_SOOT_MOMENTS = N`` where ``N`` is the number of moments to be used in the solution, either 3 or 6. + +* Depending on the gas phase solver, soot solving functionality can be turned on in the input file using ``pelec.add_soot_src = 1`` or ``peleLM.do_soot_solve = 1``. + +* The chemistry model specified with ``Chemistry_model =`` in ``GNUmakefile`` must contain the PAH inception species, as well as ``H2``, ``H``, ``OH``, ``H2O``, ``CO``, ``C2H2``, and ``O2``. + +* A PAH inception species must be provided in the input file using ``soot.incept_pah =``. Currently, only one of three inputs are accepted: ``A2``, ``A3``, or ``A4``; which correspond to naphthalene (C10H8), phenathrene (C14H10), or pyrene (C16H10). + + * If the inception species is named something other than ``A#`` in the chemistry model, a different name can be specified using ``soot.pah_name =``. However, ``soot.incept_pah`` must be set to ``A2``, ``A3``, or ``A4``. + +.. [#mueller] "Hybrid Method of Moments for modeling soot formation and growth", M. E. Mueller and G. Blanquart and H. Pitsch, Comb. Flame, Vol. 156, No. 6, pp. 1143-1155 (2009) + +.. [#bisetti] "On the formation and early evolution of soot in turbulent nonpremixed flames", F. Bisetti and G. Blanquart and M. E. Mueller and H. Pitsch, Comb. Flame, Vol. 159, No. 1, pp. 317-335 (2012) diff --git a/_sources/Spray.rst.txt b/_sources/Spray.rst.txt new file mode 100644 index 000000000..3ad8b4b23 --- /dev/null +++ b/_sources/Spray.rst.txt @@ -0,0 +1,490 @@ +.. highlight:: rst + +.. _Spray: + +***** +Spray +***** + +Spray Equations +=============== + +This section outlines the modeling and mathematics for the spray routines. +Firstly, spray modeling relies on the following assumptions: + +* Dilute spray: droplet volume inside an Eulerian cell is much smaller than the volume of the gas phase; the droplets can be modeled as Lagrangian point source terms relative to the Eulerian gas phase + +* Infinite conductivity model: temperature within a droplet is temporally varying but spatially uniform + +* One-third rule: the thermophysical properties in the film of an evaporating droplet can be approximated as a weighted average of the state at the droplet surface (weighted as 2/3) and the state of the surrounding gas (weighted as 1/3) + +* Ideal equilibrium: the liquid and vapor state at the surface of the droplet are in equilibrium + +* The radiation, Soret, and Dufour effects are neglected + +The evaporation models follow the work by Abramzon and Sirignano [#abram]_ and the multicomponent evaporation is based on work by Tonini. [#ton]_ Details regarding the energy balance are provided in Ge et al. [#Ge]_ + +The subscript notation for this section is: :math:`d` relates to the liquid droplet, :math:`v` relates to the vapor state that is in equilibrium with the liquid and gas phase, :math:`L` relates to the liquid phase, and :math:`g` relates to the gas phase. The subscript :math:`r` relates to the reference state with which to approximate the thermophysical and transport properties. This reference state is assumed to be in the evaporating film that surrounds the droplet state and is approximated as + +.. math:: + T_r &= T_d + A (T_g - T_d) + + Y_{r,n} &= Y_{v,n} + A (Y_{g,n} - Y_{v,n}) + +where :math:`A = 1/3` according the the one-third rule. +Additional nomenclature: :math:`M_n` is the molar mass of species :math:`n`, :math:`\overline{M}` is the average molar mass of a mixture, :math:`\mathcal{R}` is the universal gas constant, :math:`N_L` is the number of liquid species, and :math:`N_s` is the number of gas phase species. :math:`Y_n` and :math:`\chi_n` are the mass and molar fractions of species :math:`n`, respectively. +The user is required to provide a reference temperature for the liquid properties, :math:`T^*`, the critical temperature for each liquid species, :math:`T_{c,n}`, the boiling temperature for each liquid species at atmospheric pressure, :math:`T^*_{b,n}`, the latent heat and liquid specific heat at the reference temperature, :math:`h_{L,n}(T^*)` and :math:`c_{p,L,n}(T^*)`, respectively. +Note: this reference temperature is a constant value for all species and is not related to the reference state denoted by the subscript :math:`r`. + +The equations of motion, mass, momentum, and energy for the Lagrangian spray droplet are: + +.. math:: + \frac{d \mathbf{X}_d}{d t} &= \mathbf{u}_d, + + \frac{d m_d}{d t} &= \sum^{N_L}_{n=0} \dot{m}_n, + + m_d \frac{d Y_{d,n}}{d t} &= \dot{m}_n - Y_{d,n} \frac{d m_d}{d t}, + + m_d \frac{d \mathbf{u}_d}{d t} &= \mathbf{F}_d + m_d \mathbf{g}, + + m_d c_{p,L} \frac{d T_d}{d t} &= \sum^{N_L}_{n=0} \dot{m}_n h_{L,n}(T_d) + \mathcal{Q}_d. + +where :math:`\mathbf{X}_d` is the spatial vector, :math:`\mathbf{u}_d` is the velocity vector, :math:`T_d` is the droplet temperature, :math:`m_d` is the mass of the droplet, :math:`\mathbf{g}` is an external body force (like gravity), :math:`\dot{m}` is evaporated mass, :math:`\mathcal{Q}_d` is the heat transfer between the droplet and the surrounding gas, and :math:`\mathbf{F}_d` is the momentum source term. +The density of the liquid mixture, :math:`\rho_d`, depends on the liquid mass fractions of the dropet, :math:`Y_{d,n}`, + +.. math:: + \rho_d = \left( \sum^{N_L}_{n=0} \frac{Y_{d,n}}{\rho_{L,n}} \right)^{-1} + +The droplets are assumed to be spherical with diameter :math:`d_d`. Therefore, the mass is computed as + +.. math:: + m_d = \frac{\pi}{6} \rho_d d_d^3 + +The procedure is as follows for updating the spray droplet: + +#. Interpolate the gas phase state to the droplet location using a trilinear interpolation scheme. +#. Compute the boiling temperature for species :math:`n` at the current gas phase pressure using the Clasius-Clapeyron relation + + .. math:: + T_{b,n} = \left(\log\left(\frac{p_{\rm{atm}}}{p_g}\right) \frac{\mathcal{R}}{M_n h_{L,n}(T^*_{b,n})} + \frac{1}{T^*_{b,n}}\right) + + The boiling temperature of the droplet is computed as + + .. math:: + T_{d,b} = \sum^{N_L}_{n=0} Y_{d,n} T_{b,n} + + Since we only have the latent heat at the reference condition temperature, we estimate the enthalpy at the boiling condition using Watson's law + + .. math:: + h_{L,n}(T^*_{b,n}) = h_{L,n}(T^*) \left(\frac{T_{c,n} - T^*}{T_{c,n} - T^*_{b,n}} \right)^{-0.38} + +#. Compute the latent heat of the droplet using + + .. math:: + h_{L,n}(T_d) = h_{g,n}(T_d) - h_{g,n}(T^*) + h_{L,n}(T^*) - c_{p,L,n}(T^*) (T_d - T^*) \,. + + + and the saturation pressure using either the Clasius-Clapeyron relation + + + .. math:: + p_{{\rm{sat}}, n} = p_{\rm{atm}} \exp\left(\frac{h_{L,n}(T_d) M_n}{\mathcal{R}} \left(\frac{1}{T^*_{b,n}} - \frac{1}{T_d}\right)\right) + + or the Antoine curve fit + + .. math:: + p_{{\rm{sat}},n} = d 10^{a - b / (T_d + c)} + +#. Estimate the mass fractions in the vapor state using Raoult's law + + .. math:: + Y_{v,n} &= \frac{\chi_{v,n} M_n}{\overline{M}_v + \overline{M}_g (1 - \chi_{v,{\rm{sum}}})} \; \forall n \in N_L + + \chi_{v,{\rm{sum}}} &= \sum^{N_L}_{n=0} \chi_{v,n} + + \chi_{v,n} &= \frac{\chi_{d,n} p_{{\rm{sat}},n}}{p_g} + + \chi_{d,n} &= \frac{Y_{d,n}}{M_n}\left(\sum^{N_L}_{k=0} \frac{Y_{d,k}}{M_k}\right)^{-1} + + \overline{M}_v &= \sum^{N_L}_{n=0} \chi_{v,n} M_n + + If :math:`\chi_{g,n} p_g > p_{{\rm{sat}},n}`, then :math:`\chi_{v,n} = Y_{v,n} = 0` for that particular species in the equations above, since that means the gas phase is saturated. The mass fractions in the reference state for the fuel are computed using the one-third rule and the remaining reference mass fractions are normalized gas phase mass fractions to ensure they sum to 1 + + .. math:: + Y_{r,n} = \left\{\begin{array}{c l} + \displaystyle Y_{v,n} + A (Y_{g,n} - Y_{v,n}) & {\text{If $Y_{v,n} > 0$}}, \\ + \displaystyle\frac{1 - \sum^{N_L}_{k=0} Y_{v,k}}{1 - \sum^{N_L}_{k=0} Y_{g,k}} Y_{g,n} & {\text{Otherwise}}. + \end{array}\right. \; \forall n \in N_s. + +#. The average molar mass, specific heat, and density of the reference state in the gas film are computed as + + .. math:: + \overline{M}_r &= \left(\sum^{N_s}_{n=0} \frac{Y_{r,n}}{M_n}\right)^{-1}, + + c_{p,r} &= \sum^{N_s}_{n=0} Y_{s,n} c_{p,g,n}(T_r), + + \rho_r &= \frac{\overline{M}_r p_g}{\mathcal{R} T_r}. + +#. Transport properties are computed using the reference state: dynamic viscosity, :math:`\mu_r`, thermal conductivity, :math:`\lambda_r`, and mass diffusion coefficient for species :math:`n`, :math:`D_{r,n}`. + +#. It is important to note that `PelePhysics` provides mixture averaged mass diffusion coefficient :math:`\overline{(\rho D)}_{r,n}`, which is converted into the binary mass diffusion coefficient using + + .. math:: + (\rho D)_{r,n} = \overline{(\rho D)}_{r,n} \overline{M}_r / M_n. + + Mass diffusion coefficient is then normalized by the total fuel vapor molar fraction + + .. math:: + (\rho D)^*_{r,n} = \frac{\chi_{v,n} (\rho D)_{r,n}}{\chi_{v,{\rm{sum}}}} \; \forall n \in N_L + + and the total is + + .. math:: + (\rho D)_r = \sum_{n=0}^{N_L} (\rho D)_{r,n}^* + +#. The momentum source is a function of the drag force + + .. math:: + \mathbf{F}_d = \frac{1}{2} \rho_r C_D A_d \left\|\Delta \mathbf{u}\right\| \Delta \mathbf{u} + + where :math:`\Delta \mathbf{u} = \mathbf{u}_g - \mathbf{u}_d`, :math:`A_d = \pi d_d^2/4` is the frontal area of the droplet, and :math:`C_D` is the drag coefficient for a sphere, which is estimated using the standard drag curve for an immersed sphere + + .. math:: + C_D = \frac{24}{{\rm{Re}}_d}\left\{\begin{array}{c l} + 1 & {\text{If Re$_d$ < 1}}, \\ + \displaystyle 1 + \frac{{\rm{Re}}^{2/3}_d}{6} & {\text{Otherwise}}. + \end{array}\right. + + The droplet Reynolds number is defined as + + .. math:: + {\rm{Re}}_d = \frac{\rho_r d_d \left\|\Delta \mathbf{u}\right\|}{\mu_r} + + +#. The mass source term is modeled according to Abramzon and Sirignano (1989). The following non-dimensional numbers and factors are used: + + .. math:: + F(B) &= (1 + B)^{0.7}\frac{\log(1 + B)}{B} + + F_2 &= \max(1, \min(400, {\rm{Re}}_d)^{0.077}) + + {\rm{Pr}}_r &= \frac{\mu_r c_{p,r}}{\lambda_r} + + {\rm{Sc}}_r &= \frac{\mu_r}{(\rho D)_r} + + {\rm{Sh}}_0 &= 1 + (1 + {\rm{Re}}_d {\rm{Sc}}_r)^{1/3} F_2 + + {\rm{Nu}}_0 &= 1 + (1 + {\rm{Re}}_d {\rm{Pr}}_r)^{1/3} F_2 + + {\rm{Sh}}^* &= 2 + \frac{{\rm{Sh}}_0 - 2}{F(B_M)} + + {\rm{Nu}}^* &= 2 + \frac{{\rm{Nu}}_0 - 2}{F(B_T)} + + * The Spalding numbers for mass transfer, :math:`B_M`, and heat transfer, :math:`B_T`, are computed using + + .. math:: + B_M &= \displaystyle\frac{\sum^{N_L}_{n=0} Y_{v,n} - \sum^{N_L}_{n=0} Y_{g,n}}{1 - \sum^{N_L}_{n=0} Y_{v,n}} + + B_T &= \left(1 + B_M\right)^{\phi} - 1 + + where + + .. math:: + \phi = \frac{c_{p,r} (\rho D)_r {\rm{Sh}}^*}{\lambda_r {\rm{Nu}}^*} + + Note the dependence of :math:`{\rm{Nu}}^*` on :math:`B_T` means an iterative scheme is required to solve for both. The droplet vaporization rate and heat transfer become + + .. math:: + \dot{m}_n &= -\pi (\rho D)_{r,n}^* d_d {\rm{Sh}}^* \log(1 + B_M). \; \forall n \in N_L + + \mathcal{Q}_d &= \pi \lambda_r d_d (T_g - T_d) {\rm{Nu}}^* \frac{\log(1 + B_T)}{B_T} + + * If the gas phase is saturated for all liquid species, the equations for heat and mass transfer become + + .. math:: + \dot{m}_n &= 0 + + \mathcal{Q}_d &= \pi \lambda_r d_d (T_g - T_d) {\rm{Nu}}_0 + +#. To alleviate conservation issues at AMR interfaces, each parcel only contributes to the gas phase source term of the cell containing it. The gas phase source terms for a single parcel to the cell are + + .. math:: + S_{\rho} &= \mathcal{C} \sum^{N_L}_{n=0} \dot{m}_n, + + S_{\rho Y_n} &= \mathcal{C} \dot{m}_n, + + \mathbf{S}_{\rho \mathbf{u}} &= \mathcal{C} \mathbf{F}_d, + + S_{\rho h} &= \mathcal{C}\left(\mathcal{Q}_d + \sum_{n=0}^{N_L} \dot{m}_n h_{g,n}(T_d)\right), + + S_{\rho E} &= S_{\rho h} + \frac{1}{2}\left\|\mathbf{u}_d\right\| S_{\rho} + \mathcal{C} \mathbf{F}_d \cdot \mathbf{u}_d + + where + + .. math:: + \mathcal{C} = -\frac{N_{d}}{V_{\rm{cell}}}, + + :math:`N_{d}` is the number of droplets per computational parcel, and :math:`V_{\rm{cell}}` is the volume for the cell of interest. Note that the cell volume can vary depending on AMR level and if an EB is present. + +Spray Flags and Inputs +====================== + +* In the ``GNUmakefile``, specify ``USE_PARTICLES = TRUE`` and ``SPRAY_FUEL_NUM = N`` where ``N`` is the number of liquid species being used in the simulation. + +* Depending on the gas phase solver, spray solving functionality can be turned on in the input file using ``pelec.do_spray_particles = 1`` or ``peleLM.do_spray_particles = 1``. + +* The units for `PeleLM` and `PeleLMeX` are MKS while the units for `PeleC` are CGS. This is the same for the spray inputs. E.g. when running a spray simulation coupled with `PeleC`, the units for ``particles.fuel_cp`` must be in erg/g. + +* There are many required ``particles.`` flags in the input file. For demonstration purposes, 2 liquid species of ``NC7H16`` and ``NC10H22`` will be used. + + * The liquid fuel species names are specified using ``particles.fuel_species = NC7H16 NC10H22``. The number of fuel species listed must match ``SPRAY_FUEL_NUM``. + + * Many values must be specified on a per-species basis. Following the current example, one would have to specify ``particles.NC7H16_crit_temp = 540.`` and ``particles.NC10H22_crit_temp = 617.`` to set a critical temperature of 540 K for ``NC7H16`` and 617 K for ``NC10H22``. + + * Although this is not required or typical, if the evaporated mass should contribute to a different gas phase species than what is modeled in the liquid phase, use ``particles.dep_fuel_species``. For example, if we wanted the evaporated mass from both liquid species to contribute to a different species called ``SP3``, we would put ``particles.dep_fuel_species = SP3 SP3``. All species specified must be present in the chemistry transport and thermodynamic data. + +* The following table lists other inputs related to ``particles.``, where ``SP`` will refer to a fuel species name + +.. table:: + + +-----------------------+-------------------------------+-------------+-------------------+ + |Input |Description |Required |Default Value | + +=======================+===============================+=============+===================+ + |``fuel_species`` |Names of liquid species |Yes |None | + +-----------------------+-------------------------------+-------------+-------------------+ + |``dep_fuel_species`` |Name of gas phase species to |Yes |Inputs to | + | |contribute | |``fuel_species`` | + +-----------------------+-------------------------------+-------------+-------------------+ + |``fuel_ref_temp`` |Liquid reference temperature |Yes |None | + +-----------------------+-------------------------------+-------------+-------------------+ + |``SP_crit_temp`` |Critical temperature |Yes |None | + +-----------------------+-------------------------------+-------------+-------------------+ + |``SP_boil_temp`` |Boiling temperature at |Yes |None | + | |atmospheric pressure | | | + +-----------------------+-------------------------------+-------------+-------------------+ + |``SP_cp`` |Liquid :math:`c_p` at reference|Yes |None | + | |temperature | | | + +-----------------------+-------------------------------+-------------+-------------------+ + |``SP_latent`` |Latent heat at reference |Yes |None | + | |temperature | | | + +-----------------------+-------------------------------+-------------+-------------------+ + |``SP_rho`` |Liquid density |Yes |None | + | | | | | + +-----------------------+-------------------------------+-------------+-------------------+ + |``SP_lambda`` |Liquid thermal conductivity |No |0. | + | |(currently unused) | | | + +-----------------------+-------------------------------+-------------+-------------------+ + |``SP_mu`` |Liquid dynamic viscosity |No |0. | + | |(currently unused) | | | + +-----------------------+-------------------------------+-------------+-------------------+ + |``mom_transfer`` |Couple momentum with gas phase |No |``1`` | + | | | | | + +-----------------------+-------------------------------+-------------+-------------------+ + |``mass_transfer`` |Evaporate mass and exchange |No |``1`` | + | |heat with gas phase | | | + +-----------------------+-------------------------------+-------------+-------------------+ + |``fixed_parts`` |Fix particles in space |No |``0`` | + +-----------------------+-------------------------------+-------------+-------------------+ + |``parcel_size`` |:math:`N_{d}`; Number of |No |``1.`` | + | |droplets per parcel | | | + +-----------------------+-------------------------------+-------------+-------------------+ + |``write_ascii_files`` |Output ascii files of spray |No |``0`` | + | |data | | | + +-----------------------+-------------------------------+-------------+-------------------+ + |``cfl`` |Particle CFL number for |No |``0.5`` | + | |limiting time step | | | + +-----------------------+-------------------------------+-------------+-------------------+ + |``init_file`` |Ascii file name to initialize |No |Empty | + | |droplets | | | + +-----------------------+-------------------------------+-------------+-------------------+ + + +* If an Antoine fit for saturation pressure is used, it must be specified for individual species, :: + + particles.SP_psat = 4.07857 1501.268 -78.67 1.E5 + + where the numbers represent :math:`a`, :math:`b`, :math:`c`, and :math:`d`, respectively in: + + .. math:: + p_{\rm{sat}}(T) = d 10^{a - b / (T + c)} + + * If no fit is provided, the saturation pressure is estimated using the Clasius-Clapeyron relation; see + +* Temperature based fits for liquid density, thermal conductivity, and dynamic viscosity can be used; these can be specified as :: + + particles.SP_rho = 10.42 -5.222 1.152E-2 4.123E-7 + particles.SP_lambda = 7.243 1.223 4.223E-8 8.224E-9 + particles.SP_mu = 7.243 1.223 4.223E-8 8.224E-9 + + where the numbers represent :math:`a`, :math:`b`, :math:`c`, and :math:`d`, respectively in: + + .. math:: + \rho_L \,, \lambda_L = a + b T + c T^2 + d T^3 + + \mu_L = a + b / T + c / T^2 + d / T^3 + + If only a single value is provided, :math:`a` is assigned to that value and the other coefficients are set to zero, effectively using a constant value for the parameters. + +Spray Injection +--------------- + +Templates to facilitate and simplify spray injection are available. To use them, changes must be made to the input and ``SprayParticlesInitInsert.cpp`` files. Inputs related to injection use the ``spray.`` parser name. To create a jet in the domain, modify the ``InitSprayParticles()`` function in ``SprayParticleInitInsert.cpp``. Here is an example: :: + + void + SprayParticleContainer::InitSprayParticles( + const bool init_parts, ProbParm const& prob_parm) + { + amrex::ignore_unused(prob_parm); + int num_jets = 1; + m_sprayJets.resize(num_jets); + std::string jet_name = "jet1"; + m_sprayJets[0] = std::make_unique(jet_name, Geom(0)); + return; + } + + +This creates a single jet that is named ``jet1``. This name will be used in the input file to reference this particular jet. For example, to set the location of the jet center for ``jet1``, the following should be included in the input file, :: + + spray.jet1.jet_cent = 0. 0. 0. + +No two jets may have the same name. If an injector is constructed using only a name and geometry, the injection parameters are read from the input file. Here is a list of injection related inputs: + +.. table:: + :widths: 20 40 20 + + +--------------------+--------------------------------+--------------------+ + |Input |Description |Required | + | | | | + +====================+================================+====================+ + |``jet_cent`` |Jet center location |Yes | + +--------------------+--------------------------------+--------------------+ + |``jet_norm`` |Jet normal direction |Yes | + +--------------------+--------------------------------+--------------------+ + |``jet_vel`` |Jet velocity magnitude |Yes | + +--------------------+--------------------------------+--------------------+ + |``jet_dia`` |Jet diameter |Yes | + +--------------------+--------------------------------+--------------------+ + |``spread_angle`` |:math:`\theta_J`; Full spread |Yes | + | |angle in degrees from the jet | | + | |normal direction; droplets vary | | + | |from | | + | |:math:`[-\theta_J/2,\theta_J/2]`| | + +--------------------+--------------------------------+--------------------+ + |``T`` |Temperature of the injected |Yes | + | |liquid | | + +--------------------+--------------------------------+--------------------+ + |``Y`` |Mass fractions of the injected |Yes, if | + | |liquid based on |``SPRAY_FUEL_NUM`` >| + | |``particles.fuel_species`` |1 | + +--------------------+--------------------------------+--------------------+ + |``mass_flow_rate`` |:math:`\dot{m}_{\rm{inj}}`; Mass|Yes | + | |flow rate of the jet | | + +--------------------+--------------------------------+--------------------+ + |``hollow_spray`` |Sets hollow cone injection with |No (Default: 0) | + | |angle :math:`\theta_J/2` | | + +--------------------+--------------------------------+--------------------+ + |``hollow_spread`` |:math:`\theta_h`; Adds spread to|No (Default: 0) | + | |hollow cone :math:`\theta_J/2\pm| | + | |\theta_h` | | + +--------------------+--------------------------------+--------------------+ + |``swirl_angle`` |:math:`\phi_S`; Adds a swirling |No (Default: 0) | + | |component along azimuthal | | + | |direction | | + +--------------------+--------------------------------+--------------------+ + |``start_time`` and |Beginning and end time for jet |No | + |``end_time`` | | | + +--------------------+--------------------------------+--------------------+ + |``dist_type`` |Droplet diameter distribution |Yes | + | |type: ``Uniform``, ``Normal``, | | + | |``LogNormal``, ``Weibull``, | | + | |``ChiSquared`` | | + +--------------------+--------------------------------+--------------------+ + + +.. figure:: /Visualization/inject_transform.png + :align: center + :figwidth: 60% + + Demonstration of injection angles. :math:`\phi_J` varies uniformly from :math:`[0, 2 \pi]` + + +Care must be taken to ensure the amount of mass injected during a time step matches the desired mass flow rate. For smaller time steps, the risk of over-injecting mass increases. To mitigate this issue, each jet accounts for three values: :math:`N_{P,\min}`, :math:`m_{\rm{acc}}`, and :math:`t_{\rm{acc}}` (labeled in the code as ``m_minParcel``, ``m_sumInjMass``, and ``m_sumInjTime``, respectively). :math:`N_{P,\min}` is the minimum number of parcels that must be injected over the course of an injection event; this must be greater than or equal to one. :math:`m_{\rm{acc}}` is the amount of uninjected mass accumulated over the time period :math:`t_{\rm{acc}}`. The injection routine steps are as follows: + +#. The injected mass for the current time step is computed using the desired mass flow rate, :math:`\dot{m}_{\rm{inj}}` and the current time step + + .. math:: + m_{\rm{inj}} = \dot{m}_{\rm{inj}} \Delta t + m_{\rm{acc}} + +#. The time period for the current injection event is computed using + + .. math:: + t_{\rm{inj}} = \Delta t + t_{\rm{acc}} + +#. Using the average mass of an injected parcel, :math:`N_{d} m_{d,\rm{avg}}`, the estimated number of injected parcels is computed + + .. math:: + N_{P, \rm{inj}} = m_{\rm{inj}} / (N_{d} m_{d, \rm{avg}}) + + * If :math:`N_{P, \rm{inj}} < N_{P, \min}`, the mass and time is accumulated as :math:`m_{\rm{acc}} = m_{\rm{inj}}` and :math:`t_{\rm{acc}} = t_{\rm{inj}}` and no injection occurs this time step. + + * Otherwise, :math:`m_{\rm{inj}}` mass is injected and convected over time :math:`t_{\rm{inj}}` and :math:`m_{\rm{acc}}` and :math:`t_{\rm{acc}}` are reset. + +4. If injection occurs, the amount of mass injected, :math:`m_{\rm{actual}}`, is summed and compared with the desired mass flow rate. If :math:`m_{\rm{actual}} / t_{\rm{inj}} - \dot{m}_{\rm{inj}} > 0.05 \dot{m}_{\rm{inj}}`, then :math:`N_{P,\min}` is increased by one to reduce the likelihood of over-injecting in the future. A balance is necessary: the higher the minimum number of parcels, the less likely to over-inject mass but the number of time steps between injections can potentially grow as well. + +Spray Validation +================ + +Single Droplet Tests +-------------------- + +Single droplet tests are performed and compared with computational or experimental results published in literature. These tests are setup in ``PeleProduction/PeleMPruns/single_drop_test``. To run a test case, simply open ``Validate.py`` and set the case name from the table below :: + + case = TestCaseName() + +then do ``python Validate.py``. +The following table details the parameters of each test: + +.. table:: + + +---------------+-----------------+-----------------+-----------------+-----------------+-----------------------+-----------------+ + |Test Case Name | :math:`T_g` [K] |:math:`p_g` [bar]|:math:`T_d` [K] |:math:`d_d` [um] | :math:`\Delta u` [m/s]|Ref | + | | | | | | | | + +===============+=================+=================+=================+=================+=======================+=================+ + |``Tonini_4_33``|1000 |1 |300 |200 |6.786 |[#ton]_ | + +---------------+-----------------+-----------------+-----------------+-----------------+-----------------------+-----------------+ + |``Abramzon`` |1500 |10 |300 |100 |15 |[#abram]_ | + +---------------+-----------------+-----------------+-----------------+-----------------+-----------------------+-----------------+ + |``Daif`` |348 |1 |294 |1334 |3.10 |[#daif]_ | + +---------------+-----------------+-----------------+-----------------+-----------------+-----------------------+-----------------+ + |``RungeHep`` |273 |1 |272 |500-570 |2.5 |[#runge]_ | + |``RungeDec`` | | | | | | | + |``RungeMix`` | | | | | | | + +---------------+-----------------+-----------------+-----------------+-----------------+-----------------------+-----------------+ + +.. figure:: /Visualization/ton_res.png + :align: center + :figwidth: 80% + + Droplet diameter, temperature, and n-octane mass fraction comparisons with Figure 4.33 in [#ton]_ + +.. figure:: /Visualization/abram_res.png + :align: center + :figwidth: 80% + + Droplet diameter and temperature comparisons with [#abram]_ + +.. figure:: /Visualization/daif_res.png + :align: center + :figwidth: 80% + + Droplet diameter and temperature comparisons with [#daif]_ + +.. [#ton] "Fuel spray modeling in direct-injection diesel and gasoline engines", S. Tonini, Dissertation, City University London (2006) + +.. [#abram] "Droplet vaporization model for spray combustion calculations", B. Abramzon and W. A. Sirignano, Int. J. Heat Mass Transfer, Vol. 32, No. 9, pp. 1605-1618 (1989) + +.. [#daif] "Comparison of multicomponent fuel droplet vaporization experiments in forced convection with the Sirignano model", A. Daı̈f and M. Bouaziz and X. Chesneau and A. Ali Chérif, Exp. Therm. Fluid Sci., Vol. 18, No. 4, pp. 282-290, Issn 0894-1777 (1998) + +.. [#runge] "Low-temperature vaporization of JP-4 and JP-8 fuel droplets", T. Runge and M. Teske and C. E. Polymeropoulos, At. Sprays, Vol. 8, pp. 25-44 (1998) + +.. [#Ge] "Development of a CPU/GPU portable software library for Lagrangian-Eulerian simulations of liquid sprays", W. Ge and R. Sankaran and J. H. Chen, Int. J. Multiph. Flow, Vol. 128 (2020) diff --git a/_sources/Thermodynamics.rst.txt b/_sources/Thermodynamics.rst.txt new file mode 100644 index 000000000..ad66c2dbc --- /dev/null +++ b/_sources/Thermodynamics.rst.txt @@ -0,0 +1,9 @@ +.. highlight:: rst + +.. _sec:thermodynamics: + +************** +Thermodynamics +************** + +PelePhysics supports the computation of thermodynamic properties for different species. The thermodynamic property models currently supported are the NASA7 and NASA9 polynomial parameterizations. The reader is referred to the many discussions about these models to learn more specifics, including `Cantera's discussion about thermodynamics properties `_. diff --git a/_sources/Transport.rst.txt b/_sources/Transport.rst.txt new file mode 100644 index 000000000..2394746da --- /dev/null +++ b/_sources/Transport.rst.txt @@ -0,0 +1,65 @@ +.. highlight:: rst + +.. _sec:transport: + +********* +Transport +********* + +PelePhysics supports computation of several transport coefficients: dynamic viscosity (:math:`\mu`), bulk viscosity (:math:`\xi`), thermal conductivity (:math:`\lambda`), mixture-averaged species diffusion coefficients (:math:`D_i`), and Soret coefficients/thermal diffusion ratio (:math:`\chi_i`). There are three choices of model for computing these transport coefficients: + +* ``Constant`` with user-specified values +* ``Sutherland``, adding a simple temperature dependence to user-specified values +* ``Simple`` where transport coefficients are computed based on thermochemistry data for the multi-component mixture + +The choice between these transport models is made at compile time. When using GNUmake, this is done by setting the ``Transport_Model`` parameter in the ``GNUmakefile``. + +The appropriate choice of transport model depends on the EOS being used. For perfect gasses (GammaLaw), constant transport must be used. For reacting flow calculations using either the ideal gas (Fuego) or Soave-Redlich-Kwong equations of state, Simple transport is appropriate in most cases. Note that based on code implementation and physics considerations, the EOS/transport combinations of GammaLaw/Sutherland, GammaLaw/Simple, Soave-Redlich-Kwong/Constant and Soave-Redlich-Kwong/Sutherland are not supported and attempting to compile with any of those combinations will lead to an error message similar to this: :: + + error: static_assert failed due to requirement 'is_valid_physics_combination::value' "Invalid physics combination attempted" + +.. note:: For the flow solvers in the Pele suite, Soret effects are only supported in PeleLMeX at present. The bulk viscosity is utilized in PeleC but not in the low-Mach algorithm used in PeleLM and PeleLMeX. + +Constant +======== + +In this model, all transport coefficients are user-specified constants. They can be set in a simulation input file using: :: + + transport.const_viscosity = 1.81e-4 + transport.const_bulk_viscosity = 0.0 + transport.const_conducitivity = 2.623e2 + transport.const_diffusivity = 0.242 + transport.const_thermal_diffusion_ratio = 0.0 + transport.units = CGS + +Any unspecified quantity is assumed to be 0.0. The ``transport.units`` parameter indicates the units of the parameters set in the input file and can be ``CGS`` or ``MKS``. If not specified, CGS units are assumed, and regardless of the value of this parameter the output of all transport functions is in CGS units. + +Sutherland +========== + +This is another minimal model, based on the temperature dependence of viscosity proposed by `Sutherland (1893) `_: + +.. math:: + + \mu = \mu_{ref} \left(\frac{T}{T_{ref}} \right)^{3/2} \frac{T_{ref} + S} {T + S}, + +where :math:`\mu_{ref}` is the dynamic viscosity at a reference temperature :math:`T_{ref}` and :math:`S` is a constant. In the PelePhysics implementation, the thermal conductivity is then computed based on a user-specified Prandtl number, :math:`\lambda = \mu c_p / Pr`, where the heat capacity :math:`c_p` is evaluated using the EOS model. The user may specify constant values for the bulk viscosity and diffusvity (a single value for all species). Soret effects are not supported for this Transport model (:math:`\chi_i = 0`). + +For Sutherland transport, there are several runtime parameters that may be specified in the input file: :: + + transport.Prandtl_number = 0.7 + transport.viscosity_mu_ref = 17.16 + transport.viscosity_T_ref = 273.15 + transport.viscosity_S = 110.4 + transport.const_bulk_viscosity = 0.0 + transport.const_diffusivity = 1.0 + +The values listed above are the defaults for each parameter. Note that the temperature is specified in K and all other dimensional quantities must be specified in CGS units. + +Simple +====== + +In this model, transport coefficients are evaluated from data available in the chemical mechanisms (set at compilation using ``Chemistry_Model``). The implementation isbased on that in `EGlib `_ (see `Ern and Giovangigli (1995) `_) and simplified to compute only mixture-averaged diffusivities for each species. The only option that may be specified at run time is whether or not to compute Soret coefficients, which is done by setting the input file parameter ``transport.use_soret`` to 1 or 0, respectively (default: 0). + +When Simple transport is used with the Soave-Redlich-Kwong equation of state, additional corrections are used to modify the transport coefficients to account for real gas effects based on `Chung et al. (1988) `_. Soret effects are not supported for SRK. diff --git a/_sources/Tutorials.rst.txt b/_sources/Tutorials.rst.txt new file mode 100644 index 000000000..7bba5e199 --- /dev/null +++ b/_sources/Tutorials.rst.txt @@ -0,0 +1,101 @@ +.. role:: cpp(code) + :language: c++ + +.. _sec:tutorials: + +Tutorials +========= + +.. toctree:: + :maxdepth: 1 + +Tutorial 1 - Generating NC12H26 QSS mechanism with analytical Jacobian +---------------------------------------------------------------------- +.. _sec_tutqss1: + +Update ``poetry``:: + + $ cd ${PELE_PHYSICS_HOME}/Support/ceptr + $ poetry update + +Make sure the list of non-QSS species is correct in ``${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/non_qssa_list.yaml`` + + +In the next step, ``skeletal.yaml`` is the ``mechanism.yaml`` of the skeletal version of the mechanism (here available under ``${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu``). +If only CHEMKIN files are available for the skeletal mechanism, see :ref:`Converting CHEMKIN files ` for generating ``skeletal.yaml``. + +Generate ``qssa.yaml`` from ``skeletal.yaml`` and ``non_qssa_list.yaml``:: + + $ cd ${PELE_PHYSICS_HOME}/Support/ceptr + $ poetry run qssa -f ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/skeletal.yaml -n ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/non_qssa_list.yaml + +Generate ``mechanism.H`` and ``mechanism.cpp`` from ``qssa.yaml``:: + + $ cd ${PELE_PHYSICS_HOME}/Support/ceptr + $ poetry run convert -f ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/qssa.yaml --qss_format_input ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/qssa_input.toml --qss_symbolic_jacobian + +We recommend using the following ``qssa_input.toml``:: + + $ [Readability] + hformat = "gpu" + + [Arithmetic] + remove_1 = true + remove_pow = true + remove_pow10 = true + + [Replacement] + min_op_count = 0 + min_op_count_all = 10 + gradual_op_count = true + remove_single_symbols_cse = true + + [Recycle] + store_in_jacobian = true + recycle_cse = true + + [Characters] + round_decimals = true + + +Tutorial 2 - Generating NC12H26 QSS mechanism without analytical Jacobian +------------------------------------------------------------------------- +.. _sec_tutqss2: + +Update ``poetry``:: + + $ cd ${PELE_PHYSICS_HOME}/Support/ceptr + $ poetry update + +Make sure the list of non-QSS species is correct in ``Mechanisms/dodecane_lu_qss/non_qssa_list.yaml`` + +In the next step, ``skeletal.yaml`` is the ``mechanism.yaml`` of the skeletal version of the mechanism (here available under ``${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu``). +If only CHEMKIN files are available for the skeletal mechanism, see :ref:`Converting CHEMKIN files ` for generating ``skeletal.yaml``. + +Generate ``qssa.yaml`` from ``skeletal.yaml`` and ``non_qssa_list.yaml``:: + + $ cd ${PELE_PHYSICS_HOME}/Support/ceptr + $ poetry run qssa -f ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/skeletal.yaml -n ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/non_qssa_list.yaml + +Generate ``mechanism.H`` and ``mechanism.cpp`` from ``qssa.yaml``:: + + $ cd ${PELE_PHYSICS_HOME}/Support/ceptr + $ poetry run convert -f ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu_qss/qssa.yaml + +Tutorial 3 - Generating NC12H26 Skeletal mechanism +-------------------------------------------------- +.. _sec_tutskel3: + +Update ``poetry``:: + + $ cd ${PELE_PHYSICS_HOME}/Support/ceptr + $ poetry update + +For all the available mechanisms, a Cantera yaml format is provided. +If only CHEMKIN files are available, see :ref:`Converting CHEMKIN files ` for generating ``mechanism.yaml``. + +Generate ``mechanism.H`` and ``mechanism.cpp`` from ``mechanism.yaml``:: + + $ cd ${PELE_PHYSICS_HOME}/Support/ceptr + $ poetry run convert -f ${PELE_PHYSICS_HOME}/Mechanisms/dodecane_lu/mechanism.yaml + diff --git a/_sources/Utility.rst.txt b/_sources/Utility.rst.txt new file mode 100644 index 000000000..d2b7fbc88 --- /dev/null +++ b/_sources/Utility.rst.txt @@ -0,0 +1,113 @@ +.. highlight:: rst + +.. _sec:Utility: + +******* +Utility +******* + +In addition to routines for evaluating chemical reactions, transport properties, and equation of state functions, PelePhysics includes other shared utilities that are utilized by both PeleC and PeleLM(eX). These utilities include support for: + +* Premixed Flame (``PMF``) initialization from precomputed 1D flame profiles +* Turbulent inflows (``TurbInflow``) on domain boundaries from saved turbulence data +* Plt file management (``PltFileManager``) +* Output of runtime ``Diagnostics`` + +This section provides relevant notes on using these utilities across the Pele family of codes. There may be additional subtleties based on the code-specific implementation of these capabilities, in which case it will be necessary to refer to the documentation of the code of interest. + +Premixed Flame Initialization +============================= + +Pre-computed profiles from 1D freely propagating premixed flames are used to initialize a wrinkled `flamesheet `_ in PeleLMeX, among other problems. Right now, this capability is not used in PeleC, but similar code that accomplishes the same task using data files of the same format is applied in PeleC. The code has two parts, a data container defined in ``PMFData.{H,cpp}`` that loads and stores data from the pre-computed profile, and a function defined in ``PMF.H`` that, when provided this data structure and the bounds of a cell of interest, returns temperature, velocity, and mole fractions from that location. + +This code has two runtime parameters that may be set in the input file: :: + + pmf.datafile = pmf.dat + pmf.do_cellAverage = 1 + +The first parameter specifies the path to the PMF data file. This file contains a two-line header followed by whitespace-delimited data columns in the order: position (cm), temperature (K), velocity (cm/s), density(g/cm3), species mole fractions. Sample files are provided in the relevant PeleLMeX (and PeleC) examples, and the procedure to generate these files with a provided script is described below. The second parameter specifies whether the PMF code does a finite volume-style integral over the queried cell (``pmf.do_cellAverage = 1``) or whether the code finds an interpolated value at the midpoint of the queried cell (``pmf.do_cellAverage = 0``) + +Generating a PMF file +~~~~~~~~~~~~~~~~~~~~~ + +The script ``cantera_pmf_generator.py`` solves a 1D unstrained premixed flame using `Cantera `_ and saves it in the appropriate file format for use by the Pele codes. To use this script, first follow the :ref:`CEPTR instructions ` for setting up ``poetry``. Then return to the ``Utility/PMF/`` directory and run the script: :: + + poetry -C ../../Support/ceptr/ run python cantera_pmf_generator.py -m dodecane_lu -f NC12H26 -d 0.01 -o ./ + +This example computes a dodecane/air flame using the ``dodecane_lu`` mechanism on a 0.01 m domain, and saves the resulting file to the present directory. You may choose any mechanism included with PelePhysics, as the Cantera ``.yaml`` format is included for all mechanisms. If you choose a reduced mechanism with QSS species, the 1D solution will be obtained using the skeletal version of the mechanism without QSS species being remove, as Cantera does not support QSS by default. In this case, the script will also save a data file with QSS species removed (ending in ``-qssa-removed.dat``) that is suitable for use with the QSS mechanisms in Pele. A range of additional conditions may be specified at the command line. To see the full set of options, use the help feature: :: + + poetry -C ../../Support/ceptr/ run python cantera_pmf_generator.py --help + +Note that when running Cantera, you may need to adjust the domain size to be appropriate for your conditions in order for the solver to converge. At times, you may also need to adjust the solver tolerances and other parameters that are specified within the script. + +An additional script is provided to allow plotting of the PMF solutions. This script is used as follows (if no variable index is specified, temperature is plotted by default): :: + + poetry -C ../../Support/ceptr/ run python plotPMF.py + + +Turbulent Inflows +================= + +Placeholder. PelePhysics supports the capability of the flow solvers to have spatially and temporally varying inflow conditions based on precomputed turbulence data. + +Generating a turbulence file +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A python script is used to generate a synthetic turbulence spectrum. + +Plt File Management +=================== + +This code contains data structures used to handle data read from plt files that is utilized by the routines that allow the code to be restarted based on data from plt files. + +Diagnostics +=========== + +Placeholder. Once the porting of diagnostics from PeleLMeX to PelePhysics/PeleC is complete, documentation can be added here. + +Filter +====== + +A utility for filtering data stored in AMReX data structures. When initializing the ``Filter`` class, the filter type +and filter width to grid ratio are specified. A variety of filter types are supported: + +* ``type = 0``: no filtering +* ``type = 1``: standard box filter +* ``type = 2``: standard Gaussian filter + +We have also implemented a set of filters defined in Sagaut & Grohens (1999) Int. J. Num. Meth. Fluids: + +* ``type = 3``: 3 point box filter approximation (Eq. 26) +* ``type = 4``: 5 point box filter approximation (Eq. 27) +* ``type = 5``: 3 point box filter optimized approximation (Table 1) +* ``type = 6``: 5 point box filter optimized approximation (Table 1) +* ``type = 7``: 3 point Gaussian filter approximation +* ``type = 8``: 5 point Gaussian filter approximation (Eq. 29) +* ``type = 9``: 3 point Gaussian filter optimized approximation (Table 1) +* ``type = 10``: 5 point Gaussian filter optimized approximation (Table 1) + +.. warning:: This utility is not aware of EB or domain boundaries. If the filter stencil extends across these boundaries, + the boundary cells are treated as if they are fluid cells. + It is up to the user to ensure an adequate number of ghost cells in the arrays are appropriately populated, + using the ``get_filter_ngrow()`` member function of the class to determine the required number of ghost cells. + + +Developing +~~~~~~~~~~ + +The weights for these filters are set in ``Filter.cpp``. To add a +filter type, one needs to add an enum to the ``filter_types`` and +define a corresponding ``set_NAME_weights`` function to be called at +initialization. + +The application of a filter can be done on a Fab or MultiFab. The loop nesting +ordering was chosen to be performant on existing HPC architectures and +discussed in PeleC milestone reports. An example call to the filtering operation is + +:: + + les_filter = Filter(les_filter_type, les_filter_fgr); + ... + les_filter.apply_filter(bxtmp, flux[i], filtered_flux[i], Density, NUM_STATE); + +The user must ensure that the correct number of grow cells is present in the Fab or MultiFab. diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 000000000..f81e1c72d --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,50 @@ +.. PelePhysics documentation master file, created by + sphinx-quickstart on Sat Oct 20 12:17:48 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +=========== +PelePhysics +=========== + +`PelePhysics` is a repository of physics databases and implementation code for use within the other `Pele` codes. In particular, the choice of chemistry and transport models as well as associated functions and capabilities are managed in `PelePhysics`. `PelePhysics` has an official project `homepage `_, and can be obtained via +`GitHub `_. The documentation pages appearing here are distributed with the code in the ``Docs/sphinx`` folder as "restructured text" files. +The html is built automatically with certain pushes to the `PelePhysics` GibHub repository. A local version can also be built as follows :: + + cd ${PELE_PHYSICS_DIR}/build + sphinx-build -M html ../Docs/sphinx . + +where ``PELE_PHYSICS_DIR`` is the location of your clone of the `PelePhysics` repository. To view the local pages, +point your web browser at the file ``${PELE_PHYSICS_DIR}/build/html/index.html``. + +.. |a| image:: ./Visualization/PeleSuite.png + +.. table:: + :align: center + + +-----+ + | |a| | + +-----+ + + +.. toctree:: + :maxdepth: 2 + :caption: Documentation contents: + + GettingStarted.rst + Introduction.rst + Chemistry.rst + Transport.rst + Thermodynamics.rst + EOS.rst + Spray.rst + Soot.rst + Utility.rst + Tutorials.rst + DeveloperGuide.rst + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` diff --git a/_static/_sphinx_javascript_frameworks_compat.js b/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 000000000..81415803e --- /dev/null +++ b/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 000000000..30fee9d0f --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/css/badge_only.css b/_static/css/badge_only.css new file mode 100644 index 000000000..c718cee44 --- /dev/null +++ b/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff b/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 000000000..6cb600001 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff2 b/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 000000000..7059e2314 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff b/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 000000000..f815f63f9 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff2 b/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 000000000..f2c76e5bd Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/_static/css/fonts/fontawesome-webfont.eot b/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 000000000..e9f60ca95 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/_static/css/fonts/fontawesome-webfont.svg b/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 000000000..855c845e5 --- /dev/null +++ b/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_static/css/fonts/fontawesome-webfont.ttf b/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 000000000..35acda2fa Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/_static/css/fonts/fontawesome-webfont.woff b/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 000000000..400014a4b Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/_static/css/fonts/fontawesome-webfont.woff2 b/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 000000000..4d13fc604 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/_static/css/fonts/lato-bold-italic.woff b/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 000000000..88ad05b9f Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff differ diff --git a/_static/css/fonts/lato-bold-italic.woff2 b/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 000000000..c4e3d804b Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/_static/css/fonts/lato-bold.woff b/_static/css/fonts/lato-bold.woff new file mode 100644 index 000000000..c6dff51f0 Binary files /dev/null and b/_static/css/fonts/lato-bold.woff differ diff --git a/_static/css/fonts/lato-bold.woff2 b/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 000000000..bb195043c Binary files /dev/null and b/_static/css/fonts/lato-bold.woff2 differ diff --git a/_static/css/fonts/lato-normal-italic.woff b/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 000000000..76114bc03 Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff differ diff --git a/_static/css/fonts/lato-normal-italic.woff2 b/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 000000000..3404f37e2 Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/_static/css/fonts/lato-normal.woff b/_static/css/fonts/lato-normal.woff new file mode 100644 index 000000000..ae1307ff5 Binary files /dev/null and b/_static/css/fonts/lato-normal.woff differ diff --git a/_static/css/fonts/lato-normal.woff2 b/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 000000000..3bf984332 Binary files /dev/null and b/_static/css/fonts/lato-normal.woff2 differ diff --git a/_static/css/theme.css b/_static/css/theme.css new file mode 100644 index 000000000..19a446a0e --- /dev/null +++ b/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 000000000..d06a71d75 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 000000000..753d484aa --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '2022.10', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 000000000..a858a410e Binary files /dev/null and b/_static/file.png differ diff --git a/_static/jquery.js b/_static/jquery.js new file mode 100644 index 000000000..c4c6022f2 --- /dev/null +++ b/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/html5shiv.min.js b/_static/js/html5shiv.min.js new file mode 100644 index 000000000..cd1c674f5 --- /dev/null +++ b/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/theme.js b/_static/js/theme.js new file mode 100644 index 000000000..1fddb6ee4 --- /dev/null +++ b/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 000000000..d96755fda Binary files /dev/null and b/_static/minus.png differ diff --git a/_static/mywrap.css b/_static/mywrap.css new file mode 100644 index 000000000..b02c250e5 --- /dev/null +++ b/_static/mywrap.css @@ -0,0 +1,6 @@ + + +/* override table no-wrap */ +.wy-table-responsive table td, .wy-table-responsive table th { +white-space: inherit; +} diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 000000000..7107cec93 Binary files /dev/null and b/_static/plus.png differ diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 000000000..0d49244ed --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #eeffcc; } +.highlight .c { color: #408090; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #007020; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #333333 } /* Generic.Output */ +.highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #007020 } /* Keyword.Pseudo */ +.highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #902000 } /* Keyword.Type */ +.highlight .m { color: #208050 } /* Literal.Number */ +.highlight .s { color: #4070a0 } /* Literal.String */ +.highlight .na { color: #4070a0 } /* Name.Attribute */ +.highlight .nb { color: #007020 } /* Name.Builtin */ +.highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ +.highlight .no { color: #60add5 } /* Name.Constant */ +.highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #007020 } /* Name.Exception */ +.highlight .nf { color: #06287e } /* Name.Function */ +.highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #bb60d5 } /* Name.Variable */ +.highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #208050 } /* Literal.Number.Bin */ +.highlight .mf { color: #208050 } /* Literal.Number.Float */ +.highlight .mh { color: #208050 } /* Literal.Number.Hex */ +.highlight .mi { color: #208050 } /* Literal.Number.Integer */ +.highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ +.highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ +.highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ +.highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #4070a0 } /* Literal.String.Double */ +.highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ +.highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ +.highlight .sx { color: #c65d09 } /* Literal.String.Other */ +.highlight .sr { color: #235388 } /* Literal.String.Regex */ +.highlight .s1 { color: #4070a0 } /* Literal.String.Single */ +.highlight .ss { color: #517918 } /* Literal.String.Symbol */ +.highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ +.highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ +.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ +.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ +.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 000000000..7918c3fab --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,574 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + `Search finished, found ${resultCount} page(s) matching the search query.` + ); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + htmlElement.querySelectorAll(".headerlink").forEach((el) => { el.remove() }); + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent !== undefined) return docContent.textContent; + console.warn( + "Content block not found. Sphinx search tries to obtain it via '[role=main]'. Could you check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + /** + * execute search (requires search index to be loaded) + */ + query: (query) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + // array of [docname, title, anchor, descr, score, filename] + let results = []; + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + results.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id] of foundEntries) { + let score = Math.round(100 * queryLower.length / entry.length) + results.push([ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // lookup as object + objectTerms.forEach((term) => + results.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + results.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) results.forEach((item) => (item[4] = Scorer.score(item))); + + // now sort the results by score (in opposite order of appearance, since the + // display function below uses pop() to retrieve items) and then + // alphabetically + results.sort((a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; + }); + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + results = results.reverse(); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord) && !terms[word]) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord) && !titleTerms[word]) + arr.push({ files: titleTerms[word], score: Scorer.partialTitle }); + }); + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (fileMap.has(file) && fileMap.get(file).indexOf(word) === -1) + fileMap.get(file).push(word); + else fileMap.set(file, [word]); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords) => { + const text = Search.htmlToText(htmlText); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 000000000..8a96c69a1 --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/genindex.html b/genindex.html new file mode 100644 index 000000000..bba8b9dda --- /dev/null +++ b/genindex.html @@ -0,0 +1,121 @@ + + + + + + Index — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Index

+ +
+ +
+ + +
+
+
+ +
+ +
+

© Copyright AMReX Copyright (c) 2022, The Regents of the University of California, through Lawrence Berkeley National Laboratory and the Alliance for Sustainable Energy, LLC., through National Renewable Energy Laboratory (subject to receipt of any required approvals from the U.S. Dept. of Energy). All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 000000000..0771be366 --- /dev/null +++ b/index.html @@ -0,0 +1,212 @@ + + + + + + + PelePhysics — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

PelePhysics

+

PelePhysics is a repository of physics databases and implementation code for use within the other Pele codes. In particular, the choice of chemistry and transport models as well as associated functions and capabilities are managed in PelePhysics. PelePhysics has an official project homepage, and can be obtained via +GitHub. The documentation pages appearing here are distributed with the code in the Docs/sphinx folder as “restructured text” files. +The html is built automatically with certain pushes to the PelePhysics GibHub repository. A local version can also be built as follows

+
cd ${PELE_PHYSICS_DIR}/build
+sphinx-build -M html ../Docs/sphinx .
+
+
+

where PELE_PHYSICS_DIR is the location of your clone of the PelePhysics repository. To view the local pages, +point your web browser at the file ${PELE_PHYSICS_DIR}/build/html/index.html.

+ + + + + +

a

+ +
+

Indices and tables

+ +
+
+ + +
+
+
+ +
+ +
+

© Copyright AMReX Copyright (c) 2022, The Regents of the University of California, through Lawrence Berkeley National Laboratory and the Alliance for Sustainable Energy, LLC., through National Renewable Energy Laboratory (subject to receipt of any required approvals from the U.S. Dept. of Energy). All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 000000000..37f93a19f Binary files /dev/null and b/objects.inv differ diff --git a/search.html b/search.html new file mode 100644 index 000000000..e61299574 --- /dev/null +++ b/search.html @@ -0,0 +1,136 @@ + + + + + + Search — PelePhysics 2022.10 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+
+ +
+ +
+

© Copyright AMReX Copyright (c) 2022, The Regents of the University of California, through Lawrence Berkeley National Laboratory and the Alliance for Sustainable Energy, LLC., through National Renewable Energy Laboratory (subject to receipt of any required approvals from the U.S. Dept. of Energy). All rights reserved..

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 000000000..ca06f14ef --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"docnames": ["Ceptr", "Chemistry", "CvodeInPP", "DeveloperGuide", "EOS", "GettingStarted", "Introduction", "IntroductionToCvode", "QSS", "Soot", "Spray", "Thermodynamics", "Transport", "Tutorials", "Utility", "index"], "filenames": ["Ceptr.rst", "Chemistry.rst", "CvodeInPP.rst", "DeveloperGuide.rst", "EOS.rst", "GettingStarted.rst", "Introduction.rst", "IntroductionToCvode.rst", "QSS.rst", "Soot.rst", "Spray.rst", "Thermodynamics.rst", "Transport.rst", "Tutorials.rst", "Utility.rst", "index.rst"], "titles": ["CEPTR: Chemistry Evaluation for Pele Through Recasting", "Chemistry", "CVODE implementation in PelePhysics", "Developer Guidelines", "Equation of State", "PelePhysics Quickstart", "Introduction", "A brief introduction to CVODE", "Analytically reduced chemistry via quasi-steady state (QSS) assumption in PelePhysics", "Soot", "Spray", "Thermodynamics", "Transport", "Tutorials", "Utility", "PelePhysics"], "terms": {"we": [0, 2, 4, 5, 6, 8, 10, 13, 14], "us": [0, 1, 3, 4, 5, 6, 7, 9, 10, 12, 13, 14, 15], "c": [0, 2, 4, 6, 7, 8, 10, 14, 15], "mechan": [0, 4, 5, 7, 8, 12, 14, 15], "from": [0, 1, 2, 4, 6, 7, 10, 12, 13, 14], "cantera": [0, 1, 6, 11, 13, 14], "yaml": [0, 6, 13, 14], "i": [0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], "python": [0, 8, 10, 14, 15], "packag": [0, 2, 5], "part": [0, 2, 5, 6, 7, 8, 14], "pelephys": [0, 1, 3, 4, 6, 7, 10, 11, 12, 14], "sourc": [0, 2, 3, 4, 6, 9, 10], "code": [0, 2, 4, 5, 6, 10, 12, 14, 15], "The": [0, 1, 3, 4, 5, 7, 9, 10, 11, 12, 14, 15], "poetri": [0, 3, 13, 14], "manag": [0, 6, 15], "depend": [0, 2, 3, 6, 7, 8, 9, 10, 12, 15], "therefor": [0, 8, 10], "can": [0, 2, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15], "typic": [0, 2, 8, 10], "instal": [0, 2, 3, 5], "system": [0, 2, 4, 5, 6, 7, 8], "e": [0, 2, 4, 7, 8, 9, 10], "g": [0, 4, 7, 9, 10, 14], "homebrew": 0, "follow": [0, 2, 3, 4, 5, 6, 7, 8, 10, 13, 14, 15], "instruct": [0, 5, 6, 14], "": [0, 2, 4, 7, 8, 10, 11, 12, 14], "document": [0, 2, 5, 7, 8, 14], "To": [0, 1, 5, 7, 8, 10, 14, 15], "cd": [0, 5, 13, 15], "pele_physics_hom": [0, 2, 5, 13], "support": [0, 2, 4, 11, 12, 13, 14], "updat": [0, 5, 10, 13], "There": [0, 2, 5, 10, 12, 14], "ar": [0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], "three": [0, 2, 6, 8, 9, 10, 12], "wai": 0, "given": [0, 4, 5, 6, 7, 8], "directli": [0, 2, 3, 5, 8], "run": [0, 3, 6, 8, 10, 12, 13, 14, 15], "f": [0, 4, 7, 8, 9, 10, 13, 14], "lidryer": 0, "helper": 0, "script": [0, 2, 8, 14], "directori": [0, 2, 5, 14], "contain": [0, 2, 9, 10, 14], "sh": [0, 10], "model": [0, 2, 4, 6, 8, 9, 10, 11, 12, 15], "bash": 0, "If": [0, 2, 5, 7, 8, 9, 10, 12, 13, 14], "you": [0, 5, 6, 14], "outlin": [0, 10], "here": [0, 2, 4, 5, 7, 8, 10, 13, 14, 15], "automat": [0, 2, 5, 6, 15], "multiprocess": 0, "parallel": [0, 2, 5, 6], "all": [0, 2, 3, 4, 5, 6, 7, 8, 10, 12, 13, 14], "cpu": [0, 2, 8, 10], "detect": 0, "machin": [0, 5], "want": [0, 10], "chang": [0, 2, 3, 5, 10], "pass": [0, 8], "option": [0, 1, 5, 6, 7, 8, 12, 14], "argument": 0, "n": [0, 7, 8, 9, 10, 13], "npcu": 0, "wheren": 0, "ncpu": 0, "an": [0, 2, 4, 6, 7, 8, 10, 12, 14, 15], "integ": [0, 8], "indic": [0, 8, 12], "number": [0, 2, 6, 8, 9, 10, 12, 14], "process": [0, 2, 3, 5, 7], "For": [0, 2, 4, 5, 6, 7, 8, 9, 10, 12, 13], "non": [0, 1, 2, 4, 7, 10, 13], "reduc": [0, 1, 4, 7, 9, 10, 14, 15], "take": [0, 2], "list": [0, 3, 10, 12, 13], "l": [0, 2, 7, 10], "list_mech": 0, "qssa": [0, 13, 14], "qssa_input": [0, 13], "toml": [0, 8, 13], "lq": 0, "list_qss_mech": 0, "skelet": [0, 8, 14, 15], "non_qssa_list": [0, 13], "reli": [0, 2, 4, 6, 10], "ck2yaml": 0, "util": [0, 2, 12, 15], "format": [0, 2, 3, 4, 6, 7, 8, 9, 13, 14], "proce": [0, 2], "abov": [0, 2, 4, 8, 9, 10, 12], "result": [0, 1, 8, 10, 14], "input": [0, 1, 4, 5, 6, 7, 8, 12, 14, 15], "path_to_chemkin_dir": 0, "inp": 0, "thermo": 0, "therm": [0, 10], "dat": [0, 14], "transport": [0, 2, 4, 6, 8, 9, 10, 14, 15], "tran": 0, "permiss": 0, "alreadi": [0, 5, 6], "includ": [0, 2, 4, 7, 8, 10, 11, 14], "anoth": [0, 2, 8, 12], "one": [0, 2, 4, 5, 6, 8, 9, 10, 14], "execut": [0, 5, 8], "path_to_yaml": 0, "full": [0, 2, 10, 14], "h": [0, 2, 3, 4, 8, 9, 10, 13, 14], "fname": 0, "nqssa": 0, "m": [0, 2, 7, 8, 9, 10, 14, 15], "0": [0, 2, 4, 7, 8, 9, 10, 12, 13, 14], "1": [0, 2, 4, 5, 7, 8, 9, 10, 12, 14, 15], "2": [0, 2, 4, 7, 8, 9, 10, 12, 14, 15], "v": [0, 8, 10], "help": [0, 2, 5, 14], "show": [0, 4, 8], "thi": [0, 2, 3, 4, 5, 7, 8, 9, 10, 12, 14, 15], "messag": [0, 3, 12], "exit": 0, "speci": [0, 1, 9, 10, 11, 12, 13, 14], "method": [0, 1, 2, 5, 8, 9], "default": [0, 2, 5, 6, 7, 8, 10, 12, 14], "visual": 0, "quadrat": [0, 8], "coupl": [0, 6, 8, 10], "detail": [0, 1, 6, 7, 8, 9, 10], "descript": [0, 10], "further": [0, 1, 5, 8], "inform": [0, 2, 5, 6, 7], "treat": [0, 14], "reader": [0, 11], "mai": [0, 5, 8, 10, 12, 14], "consult": [0, 9], "section": [0, 2, 4, 5, 6, 7, 8, 10, 14], "see": [0, 2, 6, 8, 10, 12, 13, 14], "tutori": [0, 2, 8, 15], "nc12h26": [0, 8, 14, 15], "analyt": [0, 1, 2, 4, 6, 7, 15], "jacobian": [0, 1, 2, 4, 5, 6, 7, 15], "without": [0, 2, 6, 8, 14, 15], "A": [1, 2, 4, 6, 8, 9, 10, 14, 15], "brief": [1, 15], "introduct": [1, 5, 15], "cvode": [1, 5, 6, 8, 15], "numer": [1, 2, 6, 8, 9], "overview": [1, 6], "linear": [1, 2, 5, 6], "algebra": [1, 2, 5, 6, 8], "error": [1, 8, 12], "control": [1, 2], "step": [1, 2, 5, 6, 10, 13], "size": [1, 2, 8, 9, 14], "order": [1, 6, 8, 9, 14], "determin": [1, 2, 8, 14], "implement": [1, 4, 6, 7, 8, 12, 14, 15], "differ": [1, 4, 5, 6, 7, 8, 9, 10, 11], "reactor": [1, 6, 8], "valid": [1, 6, 15], "cv": [1, 4, 6], "activ": [1, 5, 6, 8], "solver": [1, 4, 5, 6, 7, 8, 9, 10, 12, 14], "via": [1, 5, 6, 15], "file": [1, 3, 4, 5, 6, 8, 9, 10, 12, 13, 15], "gnumakefil": [1, 4, 5, 9, 10, 12], "reacteval_c": [1, 6], "test": [1, 6, 7, 8, 15], "case": [1, 6, 7, 8, 10, 12, 14, 15], "go": 1, "klu": [1, 5, 6, 7], "librari": [1, 3, 5, 6, 7, 8, 10], "current": [1, 3, 6, 7, 9, 10, 11], "limit": [1, 7, 8, 10], "trick": 1, "hack": 1, "stuff": 1, "know": [1, 5, 7], "how": [1, 5, 8, 15], "doe": [1, 7, 8, 14], "compar": [1, 8, 10], "dvode": [1, 6], "gpu": [1, 6, 8, 10, 13, 15], "requir": [1, 5, 6, 7, 8, 10, 12, 14], "group": [1, 8], "cell": [1, 10, 14], "togeth": [1, 4], "reacteval_c_gpu": 1, "quasi": [1, 15], "steadi": [1, 15], "state": [1, 2, 10, 12, 14, 15], "qss": [1, 14, 15], "assumpt": [1, 10, 15], "advantag": [1, 2], "concentr": 1, "set": [1, 2, 4, 5, 6, 9, 10, 12, 14], "equat": [1, 2, 5, 6, 7, 12, 14, 15], "ceptr": [1, 2, 3, 4, 6, 8, 13, 14, 15], "evalu": [1, 2, 4, 6, 12, 14, 15], "pele": [1, 2, 3, 4, 5, 6, 8, 12, 14, 15], "through": [1, 3, 4, 6, 7, 15], "recast": [1, 6, 15], "softwar": [1, 5, 6, 7, 10], "usag": 1, "gener": [1, 2, 4, 6, 7, 8, 15], "singl": [1, 4, 12], "batch": [1, 2], "convert": [1, 8, 10, 13], "chemkin": [1, 4, 13], "throughout": [2, 5], "what": [2, 6, 10], "call": [2, 4, 6, 7, 10, 14], "fact": 2, "zero": [2, 9, 10], "dimension": [2, 10, 12], "simplest": 2, "represent": 2, "chemic": [2, 5, 8, 12, 14], "react": [2, 4, 6, 12], "upon": [2, 6], "choic": [2, 4, 6, 7, 8, 12, 15], "variabl": [2, 5, 6, 7, 8, 14], "drive": 2, "sever": [2, 5, 7, 8, 12], "type": [2, 3, 4, 5, 6, 7, 8, 10, 14], "consid": [2, 5], "correct": [2, 3, 8, 12, 13, 14], "In": [2, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15], "mass": [2, 4, 9, 10], "volum": [2, 4, 6, 9, 10, 14], "energi": [2, 6, 10], "fraction": [2, 4, 8, 9, 10, 14], "each": [2, 4, 7, 8, 10, 12], "most": [2, 4, 7, 8, 12], "common": [2, 8], "constant": [2, 4, 6, 8, 10, 15], "which": [2, 4, 5, 6, 7, 8, 9, 10, 12, 14], "advanc": [2, 4], "within": [2, 3, 5, 6, 10, 14, 15], "pelec": [2, 4, 5, 6, 8, 9, 10, 12, 14], "equival": 2, "rigid": 2, "vessel": 2, "fix": [2, 6, 7, 9, 10], "constraint": 2, "ensur": [2, 5, 8, 10, 14], "keep": 2, "densiti": [2, 6, 9, 10, 14], "rho": [2, 4, 10], "sinc": [2, 4, 8, 10], "indirect": 2, "total": [2, 8, 10], "our": [2, 8], "sole": 2, "due": [2, 12], "extern": [2, 10], "term": [2, 4, 6, 8, 9, 10], "dot": [2, 7, 8, 9, 10], "_": [2, 4, 7, 9, 10], "ext": 2, "account": [2, 10, 12], "effect": [2, 4, 9, 10, 12], "advect": 2, "convect": [2, 10], "spectral": 2, "defer": 2, "sdc": 2, "scheme": [2, 6, 10], "pelelm": [2, 4, 6, 8, 9, 10, 12, 14], "exampl": [2, 4, 5, 6, 10, 14], "sens": 2, "abstract": 2, "true": [2, 5, 9, 10, 13], "close": [2, 4], "note": [2, 4, 6, 7, 10, 12, 14], "still": [2, 5, 8], "y": [2, 4, 7, 8, 9, 10], "stabil": [2, 7, 8], "reason": [2, 7], "appli": [2, 3, 7, 8, 14], "c_v": [2, 4], "frac": [2, 4, 7, 8, 9, 10, 12], "partial": [2, 4, 7, 8, 9], "sum_k": [2, 4], "e_k": [2, 4], "omega": 2, "_k": 2, "where": [2, 4, 7, 8, 9, 10, 12, 15], "intern": [2, 6, 8], "k": [2, 7, 8, 9, 10, 12, 14], "product": [2, 7, 8], "rate": [2, 8, 10], "second": [2, 4, 6, 9, 14], "label": [2, 4, 10], "cvh": 2, "weight": [2, 7, 9, 10, 14], "conserv": [2, 10], "along": [2, 6, 10], "also": [2, 4, 5, 6, 7, 8, 9, 14, 15], "evolv": [2, 8], "accord": [2, 8, 9, 10], "c_p": [2, 4, 10, 12], "h_k": [2, 4], "open": [2, 5, 10], "suit": [2, 3, 4, 5, 7, 12], "tool": [2, 3, 7], "problem": [2, 6, 7, 8, 14], "involv": [2, 4, 6, 7, 8], "kinet": [2, 4, 5, 6, 7], "thermodynam": [2, 5, 10, 15], "It": [2, 4, 6, 8, 10, 14], "veri": [2, 5, 6, 7, 8], "robust": [2, 6], "fast": 2, "written": [2, 6], "base": [2, 4, 6, 7, 10, 12, 14], "perform": [2, 3, 5, 6, 7, 10, 14], "well": [2, 4, 6, 7, 9, 10, 15], "recogn": 2, "combust": [2, 5, 6, 7, 8, 10], "commun": 2, "abl": 2, "onli": [2, 3, 4, 5, 8, 9, 10, 12, 13], "describ": [2, 4, 5, 14], "discuss": [2, 5, 6, 11, 14], "befor": [2, 3], "need": [2, 3, 4, 5, 6, 8, 14], "low": [2, 6, 8, 10, 12], "mach": [2, 6, 12], "have": [2, 3, 4, 5, 6, 7, 8, 10, 14], "real": [2, 4, 8, 12], "been": [2, 3, 4, 6, 7, 8], "chosen": [2, 4, 8, 14], "both": [2, 5, 6, 7, 8, 10, 14], "tabl": [2, 10, 14], "hydrogen": 2, "avail": [2, 4, 5, 6, 8, 10, 12, 13], "small": [2, 6, 7, 8], "sub": [2, 8], "explicitli": 2, "taken": [2, 10], "until": 2, "final": [2, 8], "time": [2, 4, 5, 7, 8, 10, 12, 14], "reach": 2, "machineri": 2, "subdivid": 2, "dt": 2, "even": [2, 8], "purpos": [2, 5, 10], "direct": [2, 6, 7, 8, 9, 10], "dens": [2, 6, 7], "select": [2, 6], "mixtur": [2, 4, 10, 12], "phi": [2, 8, 10], "li": 2, "dryer": 2, "h2": [2, 9], "o2": [2, 8, 9], "1500": [2, 10], "8": [2, 10, 14], "101325": 2, "pa": 2, "0e": [2, 7], "3": [2, 4, 6, 7, 8, 9, 10, 12, 14, 15], "6": [2, 7, 9, 10, 14], "plot": [2, 8, 14], "fig": [2, 8], "h_2": 2, "o_2": 2, "curv": [2, 10], "indistinguish": 2, "so": [2, 4, 5, 7], "quantiti": [2, 4, 7, 8, 12], "4": [2, 4, 5, 10, 12, 14], "similar": [2, 4, 8, 12, 14], "featur": [2, 6, 7, 14], "observ": 2, "h_2o": 2, "repres": [2, 7, 10], "those": [2, 6, 8, 12], "exhibit": 2, "respect": [2, 4, 8, 9, 10, 12], "intermedi": [2, 8], "overal": 2, "mani": [2, 8, 10, 11], "deem": 2, "accept": [2, 9], "conclud": 2, "point": [2, 4, 5, 8, 10, 14, 15], "believ": 2, "user": [2, 4, 5, 6, 7, 8, 9, 10, 12, 14], "ha": [2, 4, 5, 6, 7, 8, 14, 15], "properli": [2, 5], "suitespars": [2, 5, 7], "refer": [2, 5, 6, 7, 8, 9, 10, 11, 12, 14], "choos": [2, 8, 14], "between": [2, 4, 6, 7, 8, 10, 12], "other": [2, 5, 6, 8, 9, 10, 12, 14, 15], "od": [2, 5, 6, 7], "done": [2, 4, 5, 8, 12, 14], "compil": [2, 4, 5, 8, 12], "On": [2, 9], "hand": [2, 6, 9], "specif": [2, 6, 10, 11, 14], "keyword": [2, 5], "subtleti": [2, 14], "though": 2, "when": [2, 4, 5, 6, 7, 8, 10, 12, 14], "ani": [2, 4, 12, 14], "sparsiti": 2, "should": [2, 3, 4, 8, 10], "made": [2, 4, 8, 10, 12], "subsequ": 2, "either": [2, 4, 7, 8, 9, 10, 12], "lead": [2, 5, 7, 12], "fall": 2, "back": 2, "formul": [2, 6, 7, 9], "more": [2, 5, 6, 7, 8, 9, 11], "depth": [2, 4, 6], "modif": 2, "origin": [2, 4, 6], "reacteval_fortran": 2, "must": [2, 5, 7, 8, 9, 10, 12, 14], "first": [2, 3, 5, 6, 7, 9, 14], "sundial": [2, 5, 6, 7], "line": [2, 8, 14], "use_sundials_pp": 2, "flag": [2, 8, 15], "howev": [2, 5, 7, 8, 9], "prescrib": 2, "specifi": [2, 5, 7, 8, 9, 10, 12, 14], "locat": [2, 5, 9, 10, 14, 15], "ad": [2, 3, 8, 12, 14], "cvode_lib_dir": 2, "pathtosundi": 2, "instdir": 2, "lib": 2, "By": [2, 7, 8], "implicit": [2, 4, 5], "aris": [2, 5, 8], "dure": [2, 5, 8, 10], "solv": [2, 5, 6, 7, 9, 10, 14], "add": [2, 10, 14], "pele_use_klu": [2, 5], "likewis": 2, "its": [2, 5, 6, 7, 8], "suitesparse_dir": 2, "pathtosuitespars": 2, "subect": 2, "thirdpartythirdparti": 2, "make": [2, 3, 5, 6, 7, 8, 9, 13], "thirdparti": [2, 5], "up": [2, 5, 6, 8, 14], "block": [2, 4, 5], "area": [2, 9, 10], "integrationof": 2, "suffix": 2, "associ": [2, 6, 15], "hi": [2, 8], "enabl": [2, 5, 6, 7], "start": [2, 4, 7], "relev": [2, 4, 6, 8, 14], "share": [2, 14], "thu": 2, "reactor_typ": 2, "switch": 2, "solve_typ": [2, 8], "5": [2, 4, 7, 8, 10, 14], "spars": [2, 5, 6, 7], "link": [2, 7], "99": 2, "krylov": [2, 7], "iter": [2, 6, 7, 10], "analytical_jacobian": 2, "bit": 2, "less": [2, 8, 10], "obviou": 2, "precondit": [2, 6, 7], "gmre": [2, 6, 7, 8], "while": [2, 8, 10], "With": [2, 6, 8], "allow": [2, 4, 8, 14], "adapt": [2, 5, 6, 7], "emploi": [2, 7], "seri": [2, 3], "regress": [2, 6], "monitor": 2, "domain": [2, 10, 14], "2x1024x2": 2, "box": [2, 14], "j": [2, 4, 5, 7, 8, 9, 10, 14], "sinusoid": 2, "profil": [2, 8, 14], "t_l": 2, "t_h": 2, "dtsin": 2, "left": [2, 4, 8, 9, 10, 12], "pi": [2, 9, 10], "p": [2, 4, 7, 8, 10], "right": [2, 4, 8, 9, 10, 12, 14], "summar": [2, 7], "atm": [2, 10], "composit": [2, 4], "everi": [2, 7], "c_nh_m": 2, "7": [2, 5, 8, 10, 12, 14], "n_2": 2, "fuel": [2, 8, 10], "two": [2, 5, 6, 7, 8, 10, 14], "12": [2, 8], "26": [2, 8, 14], "drm": 2, "dodecane_wang": 2, "focus": 2, "ch_4": 2, "report": [2, 14], "tl": 2, "th": 2, "2000": 2, "2500": 2, "100": [2, 10], "1024": 2, "routin": [2, 4, 6, 7, 10, 14], "addition": [2, 6], "fuego_ga": 2, "drm19": 2, "read": [2, 5, 10, 14], "precis": 2, "doubl": 2, "fals": 2, "debug": [2, 5], "dim": 2, "comp": [2, 5], "gcc": 2, "fcomp": 2, "gfortran": 2, "use_mpi": 2, "use_omp": 2, "tiny_profil": 2, "defin": [2, 4, 5, 10, 14], "pele_phys": 2, "top": [2, 4, 8], "dmod_reactor": 2, "rk": 2, "explicit": 2, "arkod": 2, "ifeq": 2, "provid": [2, 4, 5, 6, 7, 8, 9, 10, 13, 14], "sundials_lib_dir": 2, "endif": 2, "eos_model": [2, 4], "fuego": [2, 12, 15], "chemistry_model": [2, 4, 9, 12], "reactions_dir": 2, "transport_model": [2, 12], "simpl": [2, 4, 8, 15], "els": [2, 4], "gammalaw": [2, 12, 15], "null": [2, 4], "bpack": 2, "bloc": 2, "exec": [2, 5], "obtain": [2, 7, 8, 14, 15], "statist": [2, 7, 8], "amrex": [2, 5, 6, 10, 14], "3d": [2, 5], "mode": [2, 9], "05": [2, 10], "ndt": 2, "10": [2, 7, 8, 10, 13, 14], "formal": [2, 8], "toler": [2, 6, 7, 8, 14], "rtol": [2, 7], "1e": 2, "9": [2, 7, 10, 14], "atol": 2, "ark": 2, "eval": 2, "fd": 2, "aj": [2, 8], "101": 2, "max": [2, 10], "max_grid_s": 2, "name": [2, 7, 9, 10], "output": [2, 4, 10, 12, 14], "pltfile": 2, "amr": [2, 10], "plot_fil": 2, "plt": [2, 15], "fuel_nam": 2, "ch4": 2, "mean": [2, 7, 8, 9, 10], "actual": [2, 8, 10], "06": 2, "than": [2, 6, 7, 8, 9, 10], "consist": [2, 3, 8], "simultan": 2, "instanc": 2, "2x2x2": 2, "took": 2, "52": 2, "61": 2, "4096": 2, "mpi": 2, "omp": 2, "displai": 2, "middl": [2, 8], "modifi": [2, 10, 12], "previou": 2, "now": [2, 5, 14], "precondition": [2, 7], "1m34": 2, "As": [2, 5], "expect": 2, "fill": 2, "pattern": 2, "90": [2, 6], "speed": [2, 8], "over": [2, 10, 14], "import": [2, 4, 10], "tendenc": 2, "revert": 2, "suffici": [2, 4], "instead": [2, 8], "would": [2, 5, 10], "signific": [2, 4], "save": [2, 8, 14], "becaus": [2, 7, 8], "smaller": [2, 10], "closer": 2, "matrix": [2, 5, 7], "ident": 2, "becom": [2, 6, 10], "realli": 2, "easi": 2, "complet": [2, 5, 14], "illustr": 2, "best": [2, 3, 5, 7], "effici": [2, 6, 8], "far": 2, "being": [2, 3, 8, 10, 12, 14], "trivial": 2, "task": [2, 14], "factor": [2, 4, 8, 10], "subset": 2, "seen": [2, 4, 8], "much": [2, 6, 10], "built": [2, 4, 5, 15], "quotient": [2, 7], "appear": [2, 8, 15], "addit": [2, 4, 6, 7, 8, 10, 12, 14], "precond": 2, "off": 2, "ON": 2, "44": [2, 10], "87": 2, "48": 2, "64": 2, "1m42": 2, "configur": 2, "otherwis": [2, 5, 10], "remain": [2, 5, 10], "ineffici": 2, "larger": [2, 6, 8], "seem": 2, "70": 2, "6m25": 2, "5m33": 2, "6m32": 2, "21m44": 2, "10m14": 2, "oper": [2, 5, 8, 14], "dump": 2, "pre": [2, 14], "unknown": 2, "entri": [2, 8], "sparsifi": 2, "sparsif": 2, "loop": [2, 8, 14], "cpp": [2, 3, 6, 10, 13, 14], "amount": [2, 10], "alwai": [2, 5, 6, 7, 8], "good": [2, 4], "verifi": 2, "handi": [2, 5], "do": [2, 4, 5, 8, 10], "reus": [2, 8], "reevalu": 2, "scratch": 2, "trigger": [2, 8], "extern_probin_modul": 2, "new_jacobian_each_cel": 2, "probin": 2, "although": [2, 6, 10], "possibl": [2, 6, 7, 8], "cvodereinit": 2, "function": [2, 4, 6, 8, 9, 10, 12, 14, 15], "reiniti": 2, "counter": 2, "under": [2, 8, 13], "investig": 2, "some": [2, 4, 5, 8], "cvodesetmaxstepsbetweenjac": 2, "whether": [2, 5, 8, 12, 14], "famou": [2, 6], "decreas": [2, 8], "significantli": [2, 8], "fortran": [2, 4, 6], "interfac": [2, 6, 7, 10], "header": [2, 14], "explain": 2, "53": 2, "21": 2, "83": 2, "usual": [2, 5], "slightli": [2, 6], "find": [2, 7, 14], "studi": 2, "literatur": [2, 10], "give": [2, 8], "build": [2, 15], "cuda_en": 2, "cuda": [2, 8], "guid": [2, 6, 7], "distribut": [2, 7, 10, 15], "eas": [2, 8, 9], "architectur": [2, 5, 8, 14], "longer": 2, "cusolv": 2, "use_cuda": 2, "too": 2, "main": 2, "version": [2, 4, 5, 6, 7, 8, 13, 14, 15], "offer": [2, 6, 7], "sunlinsol_cusolversp_batchqr": 2, "qr": 2, "gauss": 2, "jordan": 2, "fairli": 2, "moder": 2, "power": [2, 7], "intens": 2, "natur": [2, 9], "achiev": 2, "separ": [2, 6], "thread": 2, "inde": 2, "flow": [2, 4, 6, 8, 10, 12, 14], "next": [2, 13], "could": 2, "diverg": 2, "approach": [2, 4, 6, 8, 9], "idea": [2, 7], "big": [2, 5], "equal": [2, 8, 9, 10], "multifab": [2, 14], "intent": [2, 4], "evaluationg": 2, "condit": [2, 4, 7, 8, 10, 14], "subcycl": 2, "d": [2, 7, 10, 14], "ii": [2, 4], "13": 2, "20": [2, 6], "19": 2, "36": [2, 9], "launch": 2, "kernel": 2, "host": 2, "live": 2, "rather": [2, 7, 8], "charg": 2, "identifi": 2, "deleg": 2, "rh": 2, "etc": 2, "suffer": 2, "cost": [2, 4, 8], "data": [2, 4, 5, 6, 7, 10, 12, 14], "movement": 2, "devic": 2, "synchron": 2, "vector": [2, 7, 10], "wip": [2, 6], "gain": 2, "commit": 3, "push": [3, 15], "branch": 3, "clang": 3, "formatt": 3, "prior": 3, "Will": 3, "necessari": [3, 5, 8, 10, 14], "maintain": 3, "isort": 3, "proper": [3, 5], "sort": 3, "black": [3, 8], "flake8": 3, "diagnost": [3, 15], "issu": [3, 10], "address": 3, "adher": 3, "practic": 3, "onc": [3, 5, 14], "match": [3, 10], "standard": [3, 4, 10, 14], "eo": [4, 12], "constitut": 4, "compress": [4, 6], "navier": 4, "stoke": 4, "fulli": 4, "modul": [4, 7], "compon": [4, 7, 10, 12], "perfect": [4, 12], "ga": [4, 9, 10, 12], "ideal": [4, 10, 12], "cubic": 4, "peng": 4, "robinson": 4, "wa": [4, 6, 8, 14], "stall": 4, "gnumak": [4, 12], "paramet": [4, 10, 12, 14], "old": 4, "port": [4, 14], "integr": [4, 5, 6, 7, 14], "highlight": 4, "interest": [4, 5, 6, 7, 8, 10, 14], "new": [4, 8], "chapter": [4, 5], "present": [4, 7, 10, 12, 14], "ex": [4, 5, 14], "correspond": [4, 9, 14], "hat": 4, "r": [4, 7, 8, 9, 10], "t": [4, 8, 9, 10, 12], "impli": 4, "gamma": [4, 7], "valu": [4, 7, 8, 10, 12, 14], "physic": [4, 6, 8, 12, 15], "mw": 4, "28": 4, "97": 4, "mol": 4, "air": [4, 8, 14], "physicsconst": 4, "multi": [4, 12], "mutli": 4, "calcul": [4, 8, 10, 12], "besid": 4, "equiv": 4, "sum": [4, 10], "y_i": [4, 7], "h_i": 4, "comput": [4, 5, 7, 8, 10, 11, 12, 14], "nasa": 4, "polynomi": [4, 7, 9, 11], "pressur": [4, 8, 10], "high": [4, 8], "penalti": 4, "rel": [4, 7, 8, 10], "compat": 4, "reaction": [4, 5, 8, 14], "attract": 4, "repuls": 4, "critic": [4, 7, 10], "underli": 4, "databas": [4, 6, 15], "infer": 4, "temperatur": [4, 8, 10, 12, 14], "tau": 4, "y_k": 4, "w_k": 4, "b_m": [4, 10], "a_m": 4, "univers": [4, 10], "sum_": [4, 7, 9, 10], "ij": 4, "y_j": 4, "alpha_i": 4, "alpha_j": 4, "b_k": 4, "b_i": 4, "a_i": 4, "42748": 4, "t_": [4, 7, 10, 12], "w_i": [4, 7], "p_": [4, 10], "bar": [4, 10], "_i": 4, "08664": 4, "mathcal": [4, 10], "omega_i": 4, "sqrt": 4, "accentr": 4, "48508": 4, "5517": 4, "151613": 4, "omega_": 4, "unstabl": 4, "radic": 4, "lennard": 4, "jone": 4, "construct": [4, 8, 10], "coeffici": [4, 6, 7, 8, 9, 10, 12], "316": 4, "epsilon_i": 4, "k_b": 4, "55": 4, "sigma_i": 4, "m_i": 4, "mathrm": 4, "855": 4, "molecular": [4, 9], "diamet": [4, 10], "boltzmann": 4, "mixingruleambm": 4, "found": [4, 5, 8], "subroutin": 4, "receiv": 4, "nspeci": 4, "tr": 4, "oneovertc": 4, "amloc": 4, "0d0": 4, "fomega": 4, "sqrtasti": 4, "bm": 4, "massfrac": 4, "bi": 4, "enddo": 4, "am": 4, "end": [4, 10, 14], "variou": [4, 5, 7], "contribut": [4, 8, 10], "departur": 4, "e_m": 4, "formula": [4, 7], "id": 4, "ln": [4, 8], "srk_eos_getmixturecv": 4, "none": [4, 7, 10], "eos_t": 4, "inout": 4, "amrex_r": 4, "k1": 4, "wbar": 4, "d0": 4, "inv_mwt": 4, "w": [4, 10], "cp": 4, "calc_damdt": 4, "damdt": 4, "calc_d2amdt2": 4, "d2amdt2": 4, "ckcvb": 4, "iwrk": 4, "rwrk": 4, "log": [4, 10], "h_m": 4, "express": [4, 8], "srk_eos_getmixturecp": 4, "var": 4, "cpig": 4, "eost1denom": 4, "eost2denom": 4, "eost3denom": 4, "inveost1denom": 4, "inveost2denom": 4, "inveost3denom": 4, "dhmdt": 4, "dhmdtau": 4, "rm": [4, 9, 10], "ru": 4, "dpdt": 4, "dpdtau": 4, "ckcpb": 4, "similarli": 4, "srk_eos_getmixture_h": 4, "flux": [4, 9, 14], "nonumb": 4, "sum_i": 4, "free": [4, 7], "e_i": 4, "s_i": 4, "st": 4, "Then": [4, 5, 14], "mu_k": 4, "s_k": 4, "rt": 4, "godunov": 4, "fv": 4, "algorithm": [4, 7, 12], "particular": [4, 6, 8, 10, 15], "known": 4, "except": 4, "greet": 5, "impati": 5, "word": 5, "caution": 5, "progress": 5, "undocu": 5, "out": [5, 7], "confus": 5, "someth": [5, 9], "cours": [5, 10], "action": 5, "github": [5, 15], "page": [5, 15], "develop": [5, 6, 8, 9, 10, 15], "team": [5, 6], "beginn": 5, "urg": 5, "carefulli": 5, "your": [5, 6, 14, 15], "work": [5, 7, 10], "environ": 5, "familiar": 5, "simpli": [5, 10], "like": [5, 7, 10], "chemistri": [5, 6, 9, 10, 15], "relat": [5, 6, 8, 10], "simul": [5, 8, 10, 12], "pelesuit": [5, 6], "invit": 5, "skip": 5, "hurri": 5, "context": 5, "visit": 5, "portion": 5, "primarili": 5, "intend": [5, 6], "download": 5, "submodul": 5, "pelelmex": [5, 6, 10, 12, 14], "stand": 5, "alon": 5, "properti": [5, 10, 11, 14], "sure": [5, 13], "git": 5, "recommend": [5, 7, 13], "x": [5, 9, 10], "higher": [5, 10], "clone": [5, 15], "repositori": [5, 6, 15], "recurs": 5, "http": 5, "com": 5, "creat": [5, 10], "folder": [5, 15], "export": 5, "pwd": 5, "period": [5, 7, 10], "pull": 5, "These": [5, 10, 14], "ship": 5, "own": [5, 6], "elsewher": 5, "path": [5, 14], "amrex_hom": 5, "sundials_hom": 5, "structur": [5, 6, 14], "mesh": [5, 6], "refin": 5, "differenti": [5, 6, 7, 8], "solut": [5, 7, 8, 9, 14], "stiff": [5, 6, 7, 8], "magma": 5, "aid": 5, "strictli": [5, 8], "thei": [5, 7, 8, 10, 12, 14], "better": [5, 8], "certain": [5, 15], "deal": [5, 6], "websit": 5, "collect": 5, "heterogen": 5, "short": [5, 6], "program": 5, "capabl": [5, 6, 14, 15], "reactev": 5, "kei": 5, "pele_use_magma": 5, "redon": [5, 7], "whenev": [5, 7], "tpl": 5, "processor": 5, "pele3d": 5, "gnu": 5, "regt_gpu": 5, "clean": 5, "tplrealclean": 5, "realclean": 5, "compos": 6, "hydrodynam": 6, "sibl": 6, "same": [6, 8, 10, 14], "subtli": 6, "framework": 6, "massiv": 6, "chemdriv": 6, "vode1989": [6, 7], "matter": 6, "outdat": 6, "ordinari": [6, 7], "77": 6, "At": [6, 7, 8, 10, 14], "core": 6, "resolut": 6, "prohibit": 6, "expens": 6, "bigger": 6, "frequent": 6, "encount": 6, "recent": [6, 7], "year": 6, "llnl": 6, "llnl2005": [6, 7], "modern": 6, "flexibl": [6, 8], "friendli": 6, "prove": 6, "handl": [6, 14], "mainli": 6, "cover": 6, "manuscript": 6, "were": 6, "compli": 6, "reproduc": 6, "enthalpi": [6, 10], "put": [6, 10], "place": [6, 8], "famili": [6, 7, 14], "technic": 6, "contact": 6, "uniqu": [6, 7], "larg": [6, 7, 8, 9], "nonlinear": 7, "v4": 7, "pertain": 7, "exhaust": 7, "multistep": 7, "form": [7, 8], "k_1": 7, "alpha_": 7, "h_n": 7, "k_2": 7, "beta_": 7, "approxim": [7, 8, 10, 14], "t_n": 7, "backward": [7, 8], "bdf": 7, "flc": 7, "q": [7, 10], "vari": [7, 10, 14], "histori": 7, "normal": [7, 10], "byrne1975": 7, "jac1980": 7, "root": 7, "a_n": 7, "newton": 7, "approx": 7, "organ": 7, "compris": 7, "band": 7, "matric": 7, "spil": 7, "scale": [7, 8], "u": [7, 9, 10], "spgmr": 7, "possibli": 7, "minim": [7, 8, 12], "residu": 7, "brown1990": 7, "often": 7, "feasibl": 7, "combin": [7, 9, 12], "yield": 7, "inexact": 7, "jv": 7, "suppli": 7, "latter": 7, "mcnenly2015": 7, "level": [7, 10], "squar": 7, "norm": 7, "denot": [7, 8, 9, 10], "bullet": 7, "wrm": 7, "multipl": [7, 8], "absolut": 7, "atol_i": 7, "whose": 7, "regard": [7, 9, 10], "just": 7, "local": [7, 15], "estim": [7, 10], "satisfi": 7, "fail": [7, 12], "forc": [7, 10], "adjust": [7, 8, 14], "meet": 7, "goal": 7, "maxim": 7, "dynam": [7, 10, 12], "after": 7, "basic": 7, "pick": 7, "fit": [7, 10], "discret": 7, "maximum": 7, "inherit": 7, "vode": 7, "vodpk": 7, "hindmarsh": 7, "brown": 7, "grant": 7, "lee": 7, "serban": 7, "shumak": 7, "woodward": 7, "acm": 7, "transact": 7, "mathemat": [7, 10], "tom": 7, "31": 7, "363": 7, "396": 7, "2005": [7, 8], "byrn": 7, "polyalgorithm": 7, "71": 7, "96": 7, "1975": 7, "jackson": 7, "sack": 7, "davi": 7, "altern": 7, "295": 7, "318": 7, "1980": 7, "saad": 7, "hybrid": [7, 9], "siam": 7, "journal": [7, 8], "scientif": 7, "11": 7, "450": 7, "481": 7, "1990": 7, "mcnenli": 7, "whitesid": 7, "flower": 7, "faster": [7, 8], "proceed": [7, 8], "institut": [7, 8], "35": 7, "581": 7, "587": 7, "2015": 7, "1038": 7, "1051": 7, "1989": [7, 10], "sometim": 8, "assum": [8, 9, 10, 12], "molar": [8, 9, 10], "judici": 8, "macroscop": 8, "ignit": 8, "delai": 8, "laminar": 8, "flame": [8, 9, 15], "mildli": 8, "affect": 8, "drg2005": 8, "elementari": 8, "write": 8, "turn": [8, 9, 10], "induc": 8, "easili": 8, "sys2006": 8, "presenc": 8, "figur": [8, 10], "graph": 8, "c_": [8, 9, 10], "h_": [8, 10], "nd2018": 8, "arrow": 8, "exist": [8, 14], "among": [8, 14], "deduc": 8, "invert": 8, "arbitrari": 8, "dodecan": [8, 14], "linearli": 8, "difficult": 8, "side": [8, 9], "stoichiometr": 8, "below": [8, 10, 14], "expand": 8, "color": 8, "red": 8, "augment": 8, "elimin": 8, "envis": 8, "relax": 8, "revers": 8, "happen": 8, "forward": 8, "remov": [8, 14], "computation": 8, "accur": 8, "shown": 8, "experi": [8, 10], "decid": 8, "her": 8, "against": 8, "skel2017": 8, "343": 8, "0d": 8, "span": 8, "rang": [8, 14], "applic": [8, 14], "1atm": 8, "50atm": 8, "800k": 8, "1600k": 8, "sk53": 8, "redxx": 8, "correl": 8, "titl": 8, "scatter": 8, "measur": 8, "bottom": 8, "finit": [8, 14], "invers": 8, "qss_integr": 8, "reflect": 8, "ensembl": 8, "cannot": 8, "sequenti": 8, "complic": 8, "failur": 8, "wrong": 8, "unless": 8, "timestep": 8, "qss_aj": 8, "initi": [8, 10, 15], "600k": 8, "inclus": 8, "symbol": 8, "strategi": 8, "complex": 8, "logic": 8, "readabl": [8, 13], "futur": [8, 10], "last": 8, "row": 8, "perturb": 8, "suscept": 8, "print": 8, "record": 8, "sympi": 8, "symengin": 8, "chain": 8, "rule": [8, 10], "assembl": 8, "qss_symbolic_jacobian": [8, 13], "precomput": [8, 14], "later": 8, "subexpress": 8, "magnitud": [8, 10], "problemat": 8, "memori": 8, "mitig": [8, 10], "footprint": 8, "qss_format_input": [8, 13], "dodecane_lu_qss": [8, 13], "hformat": [8, 13], "string": [8, 10], "chainrul": 8, "albeit": 8, "consum": 8, "replac": [8, 13], "them": [8, 10], "remove_1": [8, 13], "boolean": 8, "xxx": 8, "remove_pow": [8, 13], "pow": 8, "divis": 8, "convers": 8, "occur": [8, 10], "optimcuda": 8, "remove_pow10": [8, 13], "exp": [8, 9, 10], "min_op_count": [8, 13], "count": 8, "min_op_count_al": [8, 13], "prefer": 8, "tend": 8, "margin": 8, "increas": [8, 10], "gradual_op_count": [8, 13], "gradual": 8, "monoton": 8, "store_in_jacobian": [8, 13], "arrai": [8, 10, 14], "temporari": 8, "space": [8, 10], "store": [8, 14], "productionr": 8, "productionrate_light": 8, "alloc": 8, "round_decim": [8, 13], "round": 8, "float": 8, "charact": [8, 13], "recycle_cs": [8, 13], "avoid": 8, "declar": 8, "remove_single_symbols_cs": [8, 13], "worth": 8, "disappear": 8, "merg": 8, "stabl": 8, "par": 8, "thick": 8, "cross": 8, "piston": 8, "bowl": 8, "challeng": 8, "preval": 8, "slower": 8, "optim": [8, 14], "ongo": 8, "magma_direct": 8, "sparse_direct": 8, "hip": 8, "lu": 8, "law": [8, 10], "reduct": 8, "30": 8, "1333": 8, "1341": 8, "systemat": 8, "110": [8, 12], "49": 8, "13202": 8, "13208": 8, "2006": [8, 10], "borghesi": 8, "krisman": 8, "chen": [8, 10], "tempor": [8, 10, 14], "jet": [8, 10], "diesel": [8, 10], "195": 8, "183": 8, "202": 8, "2018": 8, "yao": 8, "pei": 8, "b": [8, 10], "zhong": 8, "som": 8, "luo": 8, "compact": 8, "semi": 8, "global": 8, "engin": [8, 10], "191": 8, "339": 8, "349": 8, "2017": 8, "meurer": 8, "smith": 8, "paprocki": 8, "o": [8, 14], "ert": 8, "kirpichev": 8, "rocklin": 8, "kumar": 8, "ivanov": 8, "moor": 8, "singh": 8, "rathnayak": 8, "vig": 8, "granger": 8, "muller": 8, "bonazzi": 8, "gupta": 8, "vat": 8, "johansson": 8, "pedregosa": 8, "curri": 8, "terrel": 8, "rouv": 8, "ka": 8, "saboo": 8, "fernando": 8, "kulal": 8, "cimrman": 8, "scopatz": 8, "e103": 8, "growth": 9, "oxid": 9, "moment": 9, "hmom": 9, "mueller": 9, "et": [9, 10, 12], "al": [9, 10, 12], "interpol": [9, 10, 14], "closur": 9, "momic": 9, "abil": 9, "captur": 9, "bimod": 9, "ndf": 9, "quadratur": 9, "dqmom": 9, "m_": [9, 10], "surfac": [9, 10], "n_0": 9, "v_0": 9, "s_0": 9, "a_": 9, "delta": [9, 10], "nucleat": 9, "spheric": [9, 10], "particl": [9, 10], "coordin": 9, "w_c": 9, "dimer": 9, "rho_": [9, 10], "carbon": 9, "averag": [9, 10, 12], "atom": 9, "per": [9, 10], "1800": 9, "text": [9, 10, 15], "kg": 9, "n_l": [9, 10], "v_l": 9, "s_l": 9, "four": 9, "f_v": 9, "govern": 9, "mathbf": [9, 10], "_g": [9, 10], "boldsymbol": 9, "ignor": 9, "diffus": [9, 10, 12], "thermophoret": 9, "encourag": 9, "cite": 9, "use_soot": 9, "num_soot_mo": 9, "phase": [9, 10], "add_soot_src": 9, "do_soot_solv": 9, "pah": 9, "incept": 9, "oh": 9, "h2o": 9, "co": 9, "c2h2": 9, "incept_pah": 9, "a2": 9, "a3": 9, "a4": 9, "naphthalen": 9, "c10h8": 9, "phenathren": 9, "c14h10": 9, "pyren": 9, "c16h10": 9, "pah_nam": 9, "blanquart": 9, "pitsch": 9, "comb": 9, "vol": [9, 10], "156": 9, "No": [9, 10], "pp": [9, 10], "1143": 9, "1155": 9, "2009": 9, "earli": 9, "evolut": 9, "turbul": [9, 15], "nonpremix": 9, "bisetti": 9, "159": 9, "317": 9, "335": 9, "2012": 9, "firstli": 10, "dilut": 10, "insid": 10, "eulerian": 10, "lagrangian": 10, "infinit": 10, "conduct": [10, 12], "spatial": [10, 14], "uniform": 10, "One": 10, "third": 10, "thermophys": 10, "film": 10, "evapor": 10, "surround": 10, "equilibrium": 10, "liquid": 10, "vapor": 10, "radiat": 10, "soret": [10, 12], "dufour": 10, "neglect": 10, "abramzon": 10, "sirignano": 10, "multicompon": 10, "tonini": 10, "balanc": 10, "ge": 10, "subscript": 10, "notat": 10, "t_r": 10, "t_d": 10, "t_g": 10, "y_": 10, "nomenclatur": 10, "m_n": 10, "overlin": 10, "n_": 10, "y_n": 10, "chi_n": 10, "boil": 10, "atmospher": 10, "latent": 10, "heat": [10, 12], "motion": 10, "momentum": 10, "_d": 10, "m_d": 10, "_n": 10, "veloc": [10, 14], "bodi": 10, "graviti": 10, "transfer": 10, "rho_d": 10, "dropet": 10, "d_d": 10, "procedur": [10, 14], "trilinear": 10, "clasiu": 10, "clapeyron": 10, "p_g": 10, "watson": 10, "38": 10, "satur": 10, "sat": 10, "antoin": 10, "raoult": 10, "chi_": 10, "_v": 10, "foral": 10, "m_k": 10, "begin": 10, "displaystyl": 10, "_r": 10, "rho_r": 10, "viscos": [10, 12], "mu_r": 10, "thermal": [10, 12], "lambda_r": 10, "d_": 10, "binari": 10, "drag": 10, "c_d": 10, "a_d": 10, "frontal": 10, "sphere": 10, "immers": 10, "24": 10, "re": 10, "reynold": 10, "f_2": 10, "min": 10, "400": 10, "077": 10, "pr": [10, 12], "sc": 10, "_0": 10, "nu": 10, "b_t": 10, "spald": 10, "allevi": 10, "parcel": 10, "s_": 10, "cdot": 10, "v_": 10, "eb": [10, 14], "use_particl": 10, "spray_fuel_num": 10, "do_spray_particl": 10, "unit": [10, 12], "mk": [10, 12], "cg": [10, 12], "fuel_cp": 10, "erg": 10, "demonstr": 10, "nc7h16": 10, "nc10h22": 10, "fuel_speci": 10, "basi": 10, "nc7h16_crit_temp": 10, "540": 10, "nc10h22_crit_temp": 10, "617": 10, "dep_fuel_speci": 10, "sp3": 10, "sp": 10, "ye": 10, "fuel_ref_temp": 10, "sp_crit_temp": 10, "sp_boil_temp": 10, "sp_cp": 10, "sp_latent": 10, "sp_rho": 10, "sp_lambda": 10, "unus": 10, "sp_mu": 10, "mom_transf": 10, "mass_transf": 10, "exchang": 10, "fixed_part": 10, "parcel_s": 10, "write_ascii_fil": 10, "ascii": 10, "cfl": 10, "init_fil": 10, "empti": 10, "individu": 10, "sp_psat": 10, "07857": 10, "1501": 10, "268": 10, "78": 10, "67": 10, "e5": 10, "42": 10, "222": 10, "152e": 10, "123e": 10, "243": 10, "223": 10, "223e": 10, "224e": 10, "rho_l": 10, "lambda_l": 10, "mu_l": 10, "assign": 10, "templat": 10, "facilit": 10, "simplifi": [10, 12], "sprayparticlesinitinsert": 10, "parser": 10, "initsprayparticl": 10, "sprayparticleinitinsert": 10, "void": 10, "sprayparticlecontain": 10, "const": 10, "bool": 10, "init_part": 10, "probparm": 10, "prob_parm": 10, "ignore_unus": 10, "int": [10, 14], "num_jet": 10, "m_sprayjet": 10, "resiz": 10, "std": 10, "jet_nam": 10, "jet1": 10, "make_uniqu": 10, "sprayjet": 10, "geom": 10, "return": [10, 14], "center": 10, "jet_cent": 10, "injector": 10, "geometri": 10, "jet_norm": 10, "jet_vel": 10, "jet_dia": 10, "spread_angl": 10, "theta_j": 10, "spread": 10, "angl": 10, "degre": 10, "mass_flow_r": 10, "inj": 10, "hollow_sprai": 10, "hollow": 10, "cone": 10, "hollow_spread": 10, "theta_h": 10, "pm": 10, "swirl_angl": 10, "phi_": 10, "swirl": 10, "azimuth": 10, "start_tim": 10, "end_tim": 10, "dist_typ": 10, "lognorm": 10, "weibul": 10, "chisquar": 10, "phi_j": 10, "uniformli": 10, "care": 10, "desir": 10, "risk": 10, "acc": 10, "m_minparcel": 10, "m_suminjmass": 10, "m_suminjtim": 10, "minimum": 10, "event": 10, "greater": 10, "uninject": 10, "accumul": 10, "avg": 10, "reset": 10, "likelihood": 10, "potenti": 10, "grow": [10, 14], "experiment": 10, "publish": 10, "setup": 10, "peleproduct": 10, "pelemprun": 10, "single_drop_test": 10, "py": [10, 14], "testcasenam": 10, "um": 10, "ref": [10, 12], "tonini_4_33": 10, "1000": 10, "300": 10, "200": 10, "786": 10, "15": [10, 12], "daif": 10, "348": 10, "294": 10, "1334": 10, "rungehep": 10, "rungedec": 10, "rungemix": 10, "273": [10, 12], "272": 10, "500": 10, "570": 10, "octan": 10, "comparison": 10, "33": 10, "gasolin": 10, "dissert": 10, "citi": 10, "london": 10, "32": 10, "1605": 10, "1618": 10, "da\u0131": 10, "bouaziz": 10, "chesneau": 10, "ali": 10, "ch\u00e9rif": 10, "fluid": [10, 14], "sci": 10, "18": 10, "282": 10, "290": 10, "issn": 10, "0894": 10, "1777": 10, "1998": 10, "jp": 10, "rung": 10, "tesk": 10, "polymeropoulo": 10, "25": 10, "portabl": 10, "sankaran": 10, "multiph": 10, "128": 10, "2020": 10, "nasa7": 11, "nasa9": 11, "parameter": 11, "about": 11, "learn": 11, "mu": 12, "bulk": 12, "xi": 12, "lambda": 12, "d_i": 12, "ratio": [12, 14], "chi_i": 12, "thermochemistri": 12, "appropri": [12, 14], "gass": 12, "soav": [12, 15], "redlich": [12, 15], "kwong": [12, 15], "consider": 12, "attempt": 12, "static_assert": 12, "is_valid_physics_combin": 12, "srk": [12, 15], "consttransport": 12, "invalid": 12, "const_viscos": 12, "81e": 12, "const_bulk_viscos": 12, "const_conducit": 12, "623e2": 12, "const_diffus": 12, "242": 12, "const_thermal_diffusion_ratio": 12, "unspecifi": 12, "regardless": 12, "propos": 12, "1893": 12, "mu_": 12, "prandtl": 12, "capac": 12, "diffusv": 12, "runtim": [12, 14], "prandtl_numb": 12, "viscosity_mu_ref": 12, "17": 12, "16": 12, "viscosity_t_ref": 12, "viscosity_": 12, "isbas": 12, "eglib": 12, "ern": 12, "giovangigli": 12, "1995": 12, "use_soret": 12, "chung": 12, "1988": 12, "dodecane_lu": [13, 14], "arithmet": 13, "recycl": 13, "1d": 14, "turbinflow": 14, "boundari": 14, "pltfilemanag": 14, "across": 14, "freeli": 14, "propag": 14, "wrinkl": 14, "flamesheet": 14, "accomplish": 14, "pmfdata": 14, "load": 14, "bound": 14, "mole": 14, "datafil": 14, "do_cellaverag": 14, "whitespac": 14, "delimit": 14, "column": 14, "posit": 14, "cm": 14, "cm3": 14, "sampl": 14, "style": 14, "queri": 14, "midpoint": 14, "cantera_pmf_gener": 14, "unstrain": 14, "01": 14, "suitabl": 14, "command": 14, "converg": 14, "index": [14, 15], "plotpmf": 14, "placehold": 14, "synthet": 14, "spectrum": 14, "restart": 14, "class": 14, "width": 14, "grid": 14, "varieti": 14, "gaussian": 14, "sagaut": 14, "grohen": 14, "1999": 14, "num": 14, "meth": 14, "eq": 14, "27": 14, "29": 14, "awar": 14, "stencil": 14, "extend": 14, "adequ": 14, "ghost": 14, "popul": 14, "get_filter_ngrow": 14, "member": 14, "enum": 14, "filter_typ": 14, "set_name_weight": 14, "fab": 14, "nest": 14, "hpc": 14, "mileston": 14, "les_filt": 14, "les_filter_typ": 14, "les_filter_fgr": 14, "apply_filt": 14, "bxtmp": 14, "filtered_flux": 14, "num_stat": 14, "offici": 15, "project": 15, "homepag": 15, "doc": 15, "sphinx": 15, "restructur": 15, "html": 15, "gibhub": 15, "pele_physics_dir": 15, "view": 15, "web": 15, "browser": 15, "quickstart": 15, "object": 15, "Of": 15, "art": 15, "navigu": 15, "sutherland": 15, "sprai": 15, "soot": 15, "premix": 15, "inflow": 15, "filter": 15, "guidelin": 15, "search": 15}, "objects": {}, "objtypes": {}, "objnames": {}, "titleterms": {"ceptr": 0, "chemistri": [0, 1, 2, 8], "evalu": 0, "pele": 0, "through": 0, "recast": 0, "softwar": 0, "requir": [0, 2], "usag": 0, "gener": [0, 13, 14], "singl": [0, 10], "batch": 0, "convert": 0, "chemkin": 0, "file": [0, 2, 14], "qss": [0, 8, 13], "content": [1, 15], "cvode": [2, 7], "implement": 2, "pelephys": [2, 5, 8, 15], "The": [2, 6, 8], "differ": 2, "reactor": 2, "valid": [2, 8, 10], "cv": 2, "cantera": 2, "paramet": 2, "initi": [2, 14], "simul": 2, "evolut": 2, "temperatur": 2, "pressur": 2, "enthalpi": [2, 4], "comput": 2, "lidryer": 2, "mechan": [2, 13], "black": 2, "red": 2, "major": 2, "speci": [2, 4, 8], "rel": 2, "error": [2, 7], "activ": 2, "solver": 2, "option": 2, "via": [2, 8], "input": [2, 9, 10], "gnumakefil": 2, "reacteval_c": 2, "test": [2, 5, 10], "case": [2, 5], "detail": 2, "us": [2, 8], "t": 2, "result": 2, "To": 2, "go": 2, "further": 2, "klu": 2, "librari": 2, "summari": 2, "run": [2, 5], "variou": 2, "algorithm": 2, "methan": 2, "air": 2, "reactevalcvod": 2, "n": 2, "dodecan": 2, "current": 2, "limit": 2, "trick": 2, "hack": 2, "stuff": 2, "know": 2, "how": [2, 6], "doe": 2, "compar": 2, "dvode": 2, "v": 2, "integr": 2, "same": 2, "gpu": 2, "group": 2, "cell": 2, "togeth": 2, "reacteval_c_gpu": 2, "reactevalcvode_gpu": 2, "develop": [3, 14], "guidelin": 3, "c": 3, "code": 3, "python": 3, "equat": [4, 8, 9, 10], "state": [4, 6, 8], "gammalaw": 4, "fuego": 4, "soav": 4, "redlich": 4, "kwong": 4, "srk": 4, "mix": 4, "rule": 4, "thermodynam": [4, 11], "properti": 4, "specif": 4, "heat": 4, "intern": 4, "energi": 4, "speed": 4, "sound": 4, "chemic": 4, "potenti": 4, "other": 4, "primit": 4, "variabl": 4, "deriv": 4, "quickstart": 5, "obtain": 5, "depend": 5, "build": 5, "introduct": [6, 7], "object": 6, "Of": 6, "art": 6, "navigu": 6, "thi": 6, "document": [6, 15], "A": 7, "brief": 7, "numer": 7, "method": 7, "overview": 7, "linear": [7, 8], "algebra": 7, "control": 7, "step": 7, "size": 7, "order": 7, "determin": 7, "analyt": [8, 13], "reduc": 8, "quasi": 8, "steadi": 8, "assumpt": 8, "advantag": 8, "from": 8, "non": 8, "concentr": 8, "set": 8, "jacobian": [8, 13], "soot": 9, "flag": [9, 10], "sprai": 10, "inject": 10, "droplet": 10, "transport": 12, "constant": 12, "sutherland": 12, "simpl": 12, "tutori": 13, "1": 13, "nc12h26": 13, "2": 13, "without": 13, "3": 13, "skelet": 13, "util": 14, "premix": 14, "flame": 14, "pmf": 14, "turbul": 14, "inflow": 14, "plt": 14, "manag": 14, "diagnost": 14, "filter": 14, "indic": 15, "tabl": 15}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 60}, "alltitles": {"CEPTR: Chemistry Evaluation for Pele Through Recasting": [[0, "ceptr-chemistry-evaluation-for-pele-through-recasting"]], "Software requirements": [[0, "software-requirements"]], "Usage": [[0, "usage"]], "Generating for a single chemistry": [[0, "generating-for-a-single-chemistry"]], "Batched generation": [[0, "batched-generation"]], "Converting CHEMKIN files": [[0, "converting-chemkin-files"]], "Generating a QSS chemistry file": [[0, "generating-a-qss-chemistry-file"]], "Chemistry": [[1, "chemistry"]], "Chemistry contents:": [[1, null]], "CVODE implementation in PelePhysics": [[2, "cvode-implementation-in-pelephysics"]], "The different reactors": [[2, "the-different-reactors"]], "Validation of the CV reactor implementation in CVODE (with CANTERA)": [[2, "validation-of-the-cv-reactor-implementation-in-cvode-with-cantera"]], "Parameters for initializing simulation": [[2, "id14"]], "Evolution of temperature, pressure and enthalpy in a CV reactor, computed with the LiDryer mechanism. Black: CANTERA, red: PelePhysics.": [[2, "id15"]], "Evolution of major species in a CV reactor, computed with the LiDryer mechanism. Black: CANTERA, red: PelePhysics.": [[2, "id16"]], "Relative errors on the temperature, pressure, enthalpy and major species in a CV reactor, computed with the LiDryer mechanism.": [[2, "id17"]], "Activating the different CVODE solver options via the input files": [[2, "activating-the-different-cvode-solver-options-via-the-input-files"]], "The GNUmakefile": [[2, "the-gnumakefile"], [2, "id2"], [2, "id5"], [2, "id8"], [2, "id11"]], "The input file": [[2, "the-input-file"], [2, "id3"], [2, "id6"], [2, "id9"], [2, "id12"]], "The ReactEval_C test case with CVODE in details": [[2, "the-reacteval-c-test-case-with-cvode-in-details"]], "Parameters used to initialize T in the ReactEval_C test case": [[2, "id18"]], "Results": [[2, "results"], [2, "id7"]], "To go further: ReactEval_C with CVODE and the KLU library": [[2, "to-go-further-reacteval-c-with-cvode-and-the-klu-library"]], "Summary of ReactEval_C runs with various algorithms (methane/air)": [[2, "id19"]], "Summary of ReactEvalCvode runs with various algorithms (n-dodecane/air)": [[2, "id20"]], "Current Limitations": [[2, "current-limitations"], [2, "id13"]], "Tricks and hacks, stuff to know": [[2, "tricks-and-hacks-stuff-to-know"]], "How does CVODE compare with DVODE ?": [[2, "how-does-cvode-compare-with-dvode"]], "Summary of a CVODE vs a DVODE chemistry integration on the same test case": [[2, "id21"]], "CVODE implementation in PelePhysics on GPU": [[2, "cvode-implementation-in-pelephysics-on-gpu"]], "Requirements and input files": [[2, "requirements-and-input-files"]], "Grouping cells together": [[2, "grouping-cells-together"]], "The ReactEval_C_GPU test case in details": [[2, "the-reacteval-c-gpu-test-case-in-details"]], "The Results": [[2, "the-results"]], "Summary of ReactEvalCvode_GPU runs with various algorithms (methane/air)": [[2, "id22"]], "Developer Guidelines": [[3, "developer-guidelines"]], "C++ Code": [[3, "c-code"]], "Python": [[3, "python"]], "Equation of State": [[4, "equation-of-state"]], "GammaLaw": [[4, "gammalaw"]], "Fuego": [[4, "fuego"]], "Soave-Redlich-Kwong (SRK)": [[4, "soave-redlich-kwong-srk"]], "Mixing rules": [[4, "mixing-rules"]], "Thermodynamic Properties": [[4, "thermodynamic-properties"]], "Specific heat": [[4, "specific-heat"]], "Internal energy and Enthalpy": [[4, "internal-energy-and-enthalpy"]], "Speed of Sound": [[4, "speed-of-sound"]], "Species enthalpy": [[4, "species-enthalpy"]], "Chemical potential": [[4, "chemical-potential"]], "Other primitive variable derivatives": [[4, "other-primitive-variable-derivatives"]], "PelePhysics Quickstart": [[5, "pelephysics-quickstart"]], "Obtaining PelePhysics": [[5, "obtaining-pelephysics"]], "Dependencies": [[5, "dependencies"]], "Building and Running Test Cases": [[5, "building-and-running-test-cases"]], "Introduction": [[6, "introduction"]], "Objectives and State-Of-The-Art": [[6, "objectives-and-state-of-the-art"]], "How to naviguate this documentation": [[6, "how-to-naviguate-this-documentation"]], "A brief introduction to CVODE": [[7, "a-brief-introduction-to-cvode"]], "Numerical methods overview": [[7, "numerical-methods-overview"]], "Linear Algebra": [[7, "linear-algebra"]], "Error control, step-sizing, order determination": [[7, "error-control-step-sizing-order-determination"]], "Analytically reduced chemistry via quasi-steady state (QSS) assumption in PelePhysics": [[8, "analytically-reduced-chemistry-via-quasi-steady-state-qss-assumption-in-pelephysics"]], "The QSS assumption": [[8, "the-qss-assumption"]], "The advantage of the QSS assumption": [[8, "the-advantage-of-the-qss-assumption"]], "From non-QSS species to QSS species concentration": [[8, "from-non-qss-species-to-qss-species-concentration"]], "Linearizing the set of equations": [[8, "linearizing-the-set-of-equations"]], "Validation": [[8, "validation"]], "Analytical Jacobian": [[8, "analytical-jacobian"]], "Using the Analytical Jacobian": [[8, "using-the-analytical-jacobian"]], "Soot": [[9, "soot"]], "Soot Equations": [[9, "soot-equations"]], "Soot Flags and Inputs": [[9, "soot-flags-and-inputs"]], "Spray": [[10, "spray"]], "Spray Equations": [[10, "spray-equations"]], "Spray Flags and Inputs": [[10, "spray-flags-and-inputs"]], "Spray Injection": [[10, "spray-injection"]], "Spray Validation": [[10, "spray-validation"]], "Single Droplet Tests": [[10, "single-droplet-tests"]], "Thermodynamics": [[11, "thermodynamics"]], "Transport": [[12, "transport"]], "Constant": [[12, "constant"]], "Sutherland": [[12, "sutherland"]], "Simple": [[12, "simple"]], "Tutorials": [[13, "tutorials"]], "Tutorial 1 - Generating NC12H26 QSS mechanism with analytical Jacobian": [[13, "tutorial-1-generating-nc12h26-qss-mechanism-with-analytical-jacobian"]], "Tutorial 2 - Generating NC12H26 QSS mechanism without analytical Jacobian": [[13, "tutorial-2-generating-nc12h26-qss-mechanism-without-analytical-jacobian"]], "Tutorial 3 - Generating NC12H26 Skeletal mechanism": [[13, "tutorial-3-generating-nc12h26-skeletal-mechanism"]], "Utility": [[14, "utility"]], "Premixed Flame Initialization": [[14, "premixed-flame-initialization"]], "Generating a PMF file": [[14, "generating-a-pmf-file"]], "Turbulent Inflows": [[14, "turbulent-inflows"]], "Generating a turbulence file": [[14, "generating-a-turbulence-file"]], "Plt File Management": [[14, "plt-file-management"]], "Diagnostics": [[14, "diagnostics"]], "Filter": [[14, "filter"]], "Developing": [[14, "developing"]], "PelePhysics": [[15, "pelephysics"]], "Documentation contents:": [[15, null]], "Indices and tables": [[15, "indices-and-tables"]]}, "indexentries": {}}) \ No newline at end of file