From 8e68585f8f3dcd77aeee2ae690d9acc75ca82453 Mon Sep 17 00:00:00 2001 From: JX278 Date: Fri, 11 Nov 2022 16:05:55 +0800 Subject: [PATCH 01/15] update docs --- docs/source/index.rst | 16 +--- docs/source/{quickstart => qs}/0Dcvode.jpg | Bin docs/source/{quickstart => qs}/cvode.rst | 0 docs/source/qs/examples.rst | 88 ++++++++++++++++++ docs/source/qs/input.rst | 54 +++++++++++ .../index.rst => qs/install.rst} | 67 +++++++------ docs/source/{quickstart => qs}/pytorch.png | Bin docs/source/{quickstart => qs}/pytorch.rst | 0 docs/source/quickstart/index.rst | 18 ---- docs/source/quickstart/libtorch.png | Bin 102385 -> 0 bytes docs/source/quickstart/libtorch.rst | 35 ------- 11 files changed, 177 insertions(+), 101 deletions(-) rename docs/source/{quickstart => qs}/0Dcvode.jpg (100%) rename docs/source/{quickstart => qs}/cvode.rst (100%) create mode 100644 docs/source/qs/examples.rst create mode 100644 docs/source/qs/input.rst rename docs/source/{installation/index.rst => qs/install.rst} (69%) rename docs/source/{quickstart => qs}/pytorch.png (100%) rename docs/source/{quickstart => qs}/pytorch.rst (100%) delete mode 100644 docs/source/quickstart/index.rst delete mode 100644 docs/source/quickstart/libtorch.png delete mode 100644 docs/source/quickstart/libtorch.rst diff --git a/docs/source/index.rst b/docs/source/index.rst index 88a70f03..09207a61 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -21,24 +21,14 @@ for deep learning assisted reacting flow simulations. It is also has the scope t .. toctree:: :maxdepth: 3 :numbered: - :caption: Installation - :glob: - - installation/index - -.. _quikstart: - -.. toctree:: - :maxdepth: 3 :caption: Quick Start :glob: - quickstart/index + qs/install + qs/examples + qs/input - - - .. _solvers: .. toctree:: diff --git a/docs/source/quickstart/0Dcvode.jpg b/docs/source/qs/0Dcvode.jpg similarity index 100% rename from docs/source/quickstart/0Dcvode.jpg rename to docs/source/qs/0Dcvode.jpg diff --git a/docs/source/quickstart/cvode.rst b/docs/source/qs/cvode.rst similarity index 100% rename from docs/source/quickstart/cvode.rst rename to docs/source/qs/cvode.rst diff --git a/docs/source/qs/examples.rst b/docs/source/qs/examples.rst new file mode 100644 index 00000000..b6856563 --- /dev/null +++ b/docs/source/qs/examples.rst @@ -0,0 +1,88 @@ +Two Examples +=================== + +DeepFlame with DNN +-------------------------- + +If you choose to use PyTorch as the integratgor and use the compilation flag `--use_pytorch`, you can run examples stored in `$HOME/deepflame-dev/examples/.../pytorchIntegratgor`. To run an example, you first need to source your OpenFOAM: + +.. code-block:: bash + + source $HOME/OpenFOAM/OpenFOAM-7/etc/bashrc + +Then, source your DeepFlame: + +.. code-block:: bash + + source $HOME/deepflame-dev/bashrc + +Next, you can go to the directory of any example case that you want to run. For example: + +.. code-block:: bash + + cd $HOME/deepflame-dev/examples/zeroD_cubicReactor/H2/pytorchIntegratgor + +This is an example for the zero-dimensional hydrogen combustion with PyTorch as the integrator. All files needed by DNN are stored in `pytorchDNN` folder, and the inference file is `inference.py`. Configurations regarding DNN are included in `constant/CanteraTorchProperties`. + +The case is run by simply typing: + +.. code-block:: bash + + ./Allrun + +.. Note:: Users can go to `constant/CanteraTorchProperties` and check if `torch` is switched on. Switch it `on` to run DNN cases, and switch `off` to run CVODE cases. + +If you plot PyTorch's result together with CVODE's result, the graph is expected to look like: + +.. figure:: pytorch.png + + Visualisation of 0D results from PyTorch and CVODE integrators + + + +DeepFlame without DNN +------------------------------ +CVODE Integrator is the one without the application of Deep Neural Network (DNN). Follow the steps below to run an example of CVODE. Examples are stored in the directory: +.. code-block:: bash + + $HOME/deepflame-dev/examples + +To run these examples, first source your OpenFOAM, depending on your OpenFOAM path: + +.. code-block:: bash + + source $HOME/OpenFOAM/OpenFOAM-7/etc/bashrc + +Then, source your DeepFlame: + +.. code-block:: bash + + source $HOME/deepflame-dev/bashrc + +Next, you can go to the directory of any example case that you want to run. For example: + +.. code-block:: bash + + cd $HOME/deepflame-dev/examples/zeroD_cubicReactor/H2/cvodeIntegrator + +This is an example for the zero-dimensional hydrogen combustion with CVODE integrator. + +The case is run by simply typing: + +.. code-block:: bash + + ./Allrun + +The probe used for post processing is defined in ``/system/probes``. In this case, the probe is located at the coordinates (0.0025 0.0025 0.0025) to measure temperature variation with time. +If the case is successfully run, the result can be found in ``/postProcessing/probes/0/T``, and it can be visualized by running: + +.. code-block:: bash + + gunplot + plot "/your/path/to/postProcessing/probes/0/T" + +You will get a graph: + +.. figure:: 0Dcvode.jpg + + Visualisation of the zero-dimensional hydrogen combustion result with CVODE integrator \ No newline at end of file diff --git a/docs/source/qs/input.rst b/docs/source/qs/input.rst new file mode 100644 index 00000000..47264c62 --- /dev/null +++ b/docs/source/qs/input.rst @@ -0,0 +1,54 @@ +Brief Introduction to Inputs +====================================== +The dictionary ``CanteraTorchProperties`` is the original dictionay of DeepFlame. It read in netowrk realted parameters and configurations. It typically looks like: +``` + +chemistry on; +CanteraMechanismFile "ES80_H2-7-16.yaml"; +transportModel "Mix";//"UnityLewis"; +odeCoeffs +{ + //"relTol" 1e-15; + //"absTol" 1e-24; +} +inertSpecie "N2"; + +zeroDReactor +{ + constantProperty "pressure"; +} + +torch on; +GPU on; +torchModel1 "ESH2-sub1.pt"; +torchModel2 "ESH2-sub2.pt"; +torchModel3 "ESH2-sub3.pt"; + +torchParameters1 +{ + Tact 700 ; + Qdotact 3e7; + coresPerGPU 4; +} +torchParameters2 +{ + Tact 2000; + Qdotact 3e7; +} +torchParameters3 +{ + Tact 2000; + Qdotact 7e8; +} +loadbalancing +{ + active false; + //log true; +} + +``` +In the above example, the meanings of the parameters are: +* ``CanteraMechanismFile``: the name of the reaction mechanism file +* ``odeCoeffs``: the ode torlerance. 1e-15 and 1e-24 are used for network training, so it should keep the same when comparing results with nd without DNN. +* ``torch``: the switch used to control the on and off of DNN. If users are running CVODE, this needs to be switched off. +* ``GPU``: diff --git a/docs/source/installation/index.rst b/docs/source/qs/install.rst similarity index 69% rename from docs/source/installation/index.rst rename to docs/source/qs/install.rst index eb139885..237b6f8f 100644 --- a/docs/source/installation/index.rst +++ b/docs/source/qs/install.rst @@ -1,9 +1,14 @@ +installation +====================== -Install OpenFOAM-7 (if not already installed) -==================================================== +Prerequisites +------------------------ +The installation of DeepFlame is simple and requires **OpenFOAM-7**, **LibCantera**, and **PyTorch**. .. Note:: If Ubuntu is used as the subsystem, please use `Ubuntu:20.04 `_ instead of the latest version. OpenFOAM-7 accompanied by ParaView 5.6.0 is not available for `Ubuntu-latest `_. +First install OpenFOAM-7 if it is not already installed. + .. code-block:: bash sudo sh -c "wget -O - https://dl.openfoam.org/gpg.key | apt-key add -" @@ -13,45 +18,40 @@ Install OpenFOAM-7 (if not already installed) OpenFOAM 7 and ParaView 5.6.0 will be installed in the ``/opt`` directory. -Source your OpenFOAM -====================== +**LibCantera** and **PyTorch** are installed via `conda `_. DNN version aims to support computation on CUDA. If you have compatible platform, run the following command to install DeepFlame. .. code-block:: bash - source $HOME/OpenFOAM/OpenFOAM-7/etc/bashrc - -This depends on your own path for OpenFOAM bashrc. - -Clone the DeepFlame repository -=========================================== - -.. code-block:: bash + conda create -n df-pytorch python=3.8 + conda activate df-pytorch + conda install -c cantera libcantera-devel + conda install pytorch torchvision torchaudio pytorch-cuda=11.6 -c pytorch -c nvidia + conda install pybind11 easydict - git clone https://github.com/deepmodeling/deepflame-dev.git - cd deepflame-dev +.. Note:: Please go to PyTorch's official website to check your system compatability and choose the installation command line that is suitable for your platform. -Install dependencies and DeepFlame based on your need -================================================================= -DeepFlame supports three compilation choices: no torch, LibTorch, and PyTorch. +.. Note:: Check your ``Miniconda3/envs/libcantera`` directory and make sure the install was successful (lib/ include/ etc. exist). - .. Note:: You are encouaged to try all three options, but remember to install the next version in a new terminal to clean previous environment variables. +Configure +------------------------- +You need to source your OpenFOAM-7. +.. code-block:: bash + source $HOME/OpenFOAM/OpenFOAM-7/etc/bashrc +This depends on your own path for OpenFOAM bashrc. + -PyTorch version (**RECOMMEND**) +Build and Install ------------------------------- +DeepFlame with DNN capatibility is installed through: +.. code-block:: bash -PyTorch version aims to support computation on CUDA. If you have compatible platform, run the following command to install DeepFlame. - -.. code-block:: - - conda create -n df-pytorch python=3.8 - conda activate df-pytorch - conda install -c cantera libcantera-devel - conda install pytorch torchvision torchaudio cudatoolkit=11.6 -c pytorch -c conda-forge - conda install pybind11 - . install.sh --use_pytorch + git clone https://github.com/deepmodeling/deepflame-dev.git + cd deepflame-dev + source ./bashrc + . install.sh --use_pytorch .. Note:: You may come accross an error regarding shared library ``libmkl_rt.so.2`` when libcantera is installed through cantera channel. If so, go to your conda environment and check the existance of ``libmkl_rt.so.2`` and ``libmkl_rt.so.1``, and then link ``libmkl_rt.so.2`` to ``libmkl_rt.so.1``. @@ -62,8 +62,10 @@ PyTorch version aims to support computation on CUDA. If you have compatible plat ln -s libmkl_rt.so.1 libmkl_rt.so.2 -LibTorch version + +Other Options ------------------------------- +DeepFlame also provides users with LibTorch integraotr and CVODE integrator. If you choose to use LibTorch (C++ API for Torch), first create the conda env and install `LibCantera `_: @@ -81,8 +83,6 @@ Then you can pass your own libtorch path to DeepFlame. .. Note:: Some compiling issues may happen due to system compatability. Instead of using conda installed Cantera C++ lib and the downloaded Torch C++ lib, try to compile your own Cantera and Torch C++ libraries. -No Torch version -------------------------- If your are using DeepFlame's CVODE solver without DNN model, just install LibCantera via `conda `_. @@ -92,9 +92,6 @@ If your are using DeepFlame's CVODE solver without DNN model, just install LibCa conda activate df-notorch conda install -c cantera libcantera-devel -.. Note:: Check your ``Miniconda3/envs/libcantera`` directory and make sure the install was successful (lib/ include/ etc. exist). - - If the conda env ``df-notorch`` is activated, install DeepFlame by running: .. code-block:: bash diff --git a/docs/source/quickstart/pytorch.png b/docs/source/qs/pytorch.png similarity index 100% rename from docs/source/quickstart/pytorch.png rename to docs/source/qs/pytorch.png diff --git a/docs/source/quickstart/pytorch.rst b/docs/source/qs/pytorch.rst similarity index 100% rename from docs/source/quickstart/pytorch.rst rename to docs/source/qs/pytorch.rst diff --git a/docs/source/quickstart/index.rst b/docs/source/quickstart/index.rst deleted file mode 100644 index 0e941bc8..00000000 --- a/docs/source/quickstart/index.rst +++ /dev/null @@ -1,18 +0,0 @@ -Examples for Each Chemistry Integrator -========================================= - -DeepFlame provides users with three avaiblable integrators: CVODE, LibTorch, and PyTorch. CVODE integraotr does not include any machine learning capability, while the other two use different APIs to make computation with neural neworks on different platforms possible. -To get a quick start with all three integrators, there are several examples stored in ``/deepflame-dev/examples/`` that can be run. More details regarding each integrator can be found in the following sections. - - -.. _quickstart: - -.. toctree:: - :numbered: - :glob: - - pytorch - libtorch - cvode - - \ No newline at end of file diff --git a/docs/source/quickstart/libtorch.png b/docs/source/quickstart/libtorch.png deleted file mode 100644 index 5a07c1f10c4aa4a3521b6c530f2a533fc51f8133..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102385 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

T2Q+2b;scL*I}D=WP$~09csNuXpltVzLu- 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 Date: Fri, 11 Nov 2022 17:14:56 +0800 Subject: [PATCH 02/15] Update input.rst --- docs/source/qs/input.rst | 87 +++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/docs/source/qs/input.rst b/docs/source/qs/input.rst index 47264c62..4f229d0b 100644 --- a/docs/source/qs/input.rst +++ b/docs/source/qs/input.rst @@ -1,54 +1,57 @@ Brief Introduction to Inputs ====================================== The dictionary ``CanteraTorchProperties`` is the original dictionay of DeepFlame. It read in netowrk realted parameters and configurations. It typically looks like: -``` -chemistry on; -CanteraMechanismFile "ES80_H2-7-16.yaml"; -transportModel "Mix";//"UnityLewis"; -odeCoeffs -{ - //"relTol" 1e-15; - //"absTol" 1e-24; -} -inertSpecie "N2"; +.. code-block:: + chemistry on; + CanteraMechanismFile "ES80_H2-7-16.yaml"; + transportModel "Mix";//"UnityLewis"; + odeCoeffs + { + //"relTol" 1e-15; + //"absTol" 1e-24; + } + inertSpecie "N2"; -zeroDReactor -{ - constantProperty "pressure"; -} + zeroDReactor + { + constantProperty "pressure"; + } -torch on; -GPU on; -torchModel1 "ESH2-sub1.pt"; -torchModel2 "ESH2-sub2.pt"; -torchModel3 "ESH2-sub3.pt"; + torch on; + GPU on; + torchModel1 "ESH2-sub1.pt"; + torchModel2 "ESH2-sub2.pt"; + torchModel3 "ESH2-sub3.pt"; + + torchParameters1 + { + Tact 700 ; + Qdotact 3e7; + coresPerGPU 4; + } + torchParameters2 + { + Tact 2000; + Qdotact 3e7; + } + torchParameters3 + { + Tact 2000; + Qdotact 7e8; + } + loadbalancing + { + active false; + //log true; + } -torchParameters1 -{ - Tact 700 ; - Qdotact 3e7; - coresPerGPU 4; -} -torchParameters2 -{ - Tact 2000; - Qdotact 3e7; -} -torchParameters3 -{ - Tact 2000; - Qdotact 7e8; -} -loadbalancing -{ - active false; - //log true; -} -``` In the above example, the meanings of the parameters are: * ``CanteraMechanismFile``: the name of the reaction mechanism file * ``odeCoeffs``: the ode torlerance. 1e-15 and 1e-24 are used for network training, so it should keep the same when comparing results with nd without DNN. * ``torch``: the switch used to control the on and off of DNN. If users are running CVODE, this needs to be switched off. -* ``GPU``: +* ``GPU``: the switch used to control whether GPU or CPU is used to carry out inference. +* ``torchModel``: name of network. +* ``torchParameters``: thresholds used to decide when to use network +* ``coresPerGPU``: number of CPU cores on one node From 89ed98021cec3a46d8c6d1907cfe666ec90d1274 Mon Sep 17 00:00:00 2001 From: JX278 <113102069+JX278@users.noreply.github.com> Date: Fri, 11 Nov 2022 17:17:11 +0800 Subject: [PATCH 03/15] Update input.rst --- docs/source/qs/input.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/qs/input.rst b/docs/source/qs/input.rst index 4f229d0b..26893020 100644 --- a/docs/source/qs/input.rst +++ b/docs/source/qs/input.rst @@ -2,7 +2,8 @@ Brief Introduction to Inputs ====================================== The dictionary ``CanteraTorchProperties`` is the original dictionay of DeepFlame. It read in netowrk realted parameters and configurations. It typically looks like: -.. code-block:: +.. code-block:: + chemistry on; CanteraMechanismFile "ES80_H2-7-16.yaml"; transportModel "Mix";//"UnityLewis"; From bc4812dead2588308faebd44215e14778fb7533b Mon Sep 17 00:00:00 2001 From: JX278 <113102069+JX278@users.noreply.github.com> Date: Fri, 11 Nov 2022 17:21:26 +0800 Subject: [PATCH 04/15] Delete pytorch.rst --- docs/source/qs/pytorch.rst | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 docs/source/qs/pytorch.rst diff --git a/docs/source/qs/pytorch.rst b/docs/source/qs/pytorch.rst deleted file mode 100644 index b6b8749f..00000000 --- a/docs/source/qs/pytorch.rst +++ /dev/null @@ -1,36 +0,0 @@ -PyTorch Integrator -=================== - -If you choose to use PyTorch as the integratgor and use the compilation flag `--use_pytorch`, you can run examples stored in `$HOME/deepflame-dev/examples/.../pytorchIntegratgor`. To run an example, you first need to source your OpenFOAM: - -.. code-block:: bash - - source $HOME/OpenFOAM/OpenFOAM-7/etc/bashrc - -Then, source your DeepFlame: - -.. code-block:: bash - - source $HOME/deepflame-dev/bashrc - -Next, you can go to the directory of any example case that you want to run. For example: - -.. code-block:: bash - - cd $HOME/deepflame-dev/examples/zeroD_cubicReactor/H2/pytorchIntegratgor - -This is an example for the zero-dimensional hydrogen combustion with PyTorch as the integrator. All files needed by DNN are stored in `pytorchDNN` folder, and the inference file is `inference.py`. Configurations regarding DNN are included in `constant/CanteraTorchProperties`. - -The case is run by simply typing: - -.. code-block:: bash - - ./Allrun - -.. Note:: Users can go to `constant/CanteraTorchProperties` and check if `torch` is switched on. Switch it `on` to run DNN cases, and switch `off` to run CVODE cases. - -If you plot PyTorch's result together with CVODE's result, the graph is expected to look like: - -.. figure:: pytorch.png - - Visualisation of 0D results from PyTorch and CVODE integrators \ No newline at end of file From 170c8f487695a2c85e1a2c14badff614e2059df9 Mon Sep 17 00:00:00 2001 From: JX278 <113102069+JX278@users.noreply.github.com> Date: Fri, 11 Nov 2022 17:21:37 +0800 Subject: [PATCH 05/15] Delete cvode.rst --- docs/source/qs/cvode.rst | 47 ---------------------------------------- 1 file changed, 47 deletions(-) delete mode 100644 docs/source/qs/cvode.rst diff --git a/docs/source/qs/cvode.rst b/docs/source/qs/cvode.rst deleted file mode 100644 index 9a75c85f..00000000 --- a/docs/source/qs/cvode.rst +++ /dev/null @@ -1,47 +0,0 @@ -CVODE Intergrator -=================== -CVODE Integrator is the one without the application of Deep Neural Network (DNN), and it can be used to validate PyTorch and LibTorch integrators. -Follow the steps below to run an example of CVODE. Examples are stored in the directory: -.. code-block:: bash - - $HOME/deepflame-dev/examples - -To run these examples, first source your OpenFOAM, depending on your OpenFOAM path: - -.. code-block:: bash - - source $HOME/OpenFOAM/OpenFOAM-7/etc/bashrc - -Then, source your DeepFlame: - -.. code-block:: bash - - source $HOME/deepflame-dev/bashrc - -Next, you can go to the directory of any example case that you want to run. For example: - -.. code-block:: bash - - cd $HOME/deepflame-dev/examples/zeroD_cubicReactor/H2/cvodeIntegrator - -This is an example for the zero-dimensional hydrogen combustion with CVODE integrator. - -The case is run by simply typing: - -.. code-block:: bash - - ./Allrun - -The probe used for post processing is defined in ``/system/probes``. In this case, the probe is located at the coordinates (0.0025 0.0025 0.0025) to measure temperature variation with time. -If the case is successfully run, the result can be found in ``/postProcessing/probes/0/T``, and it can be visualized by running: - -.. code-block:: bash - - gunplot - plot "/your/path/to/postProcessing/probes/0/T" - -You will get a graph: - -.. figure:: 0Dcvode.jpg - - Visualisation of the zero-dimensional hydrogen combustion result with CVODE integrator \ No newline at end of file From cadac15ad9b88db4d3eb52d9a69b6d9dc970137f Mon Sep 17 00:00:00 2001 From: JX278 <113102069+JX278@users.noreply.github.com> Date: Fri, 11 Nov 2022 17:25:20 +0800 Subject: [PATCH 06/15] Update install.rst --- docs/source/qs/install.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/qs/install.rst b/docs/source/qs/install.rst index 237b6f8f..d41ea352 100644 --- a/docs/source/qs/install.rst +++ b/docs/source/qs/install.rst @@ -1,4 +1,4 @@ -installation +Installation ====================== Prerequisites @@ -102,4 +102,4 @@ If ``df-notorch`` not activated (or you have a self-complied libcantera), specif .. code-block:: bash - . install.sh --libcantera_dir /your/path/to/libcantera/ \ No newline at end of file + . install.sh --libcantera_dir /your/path/to/libcantera/ From bc1ab5c7dc0cda363b0d6d4ab6d2f9978c55c447 Mon Sep 17 00:00:00 2001 From: JX278 <113102069+JX278@users.noreply.github.com> Date: Fri, 11 Nov 2022 17:37:02 +0800 Subject: [PATCH 07/15] Update and rename input.rst to input.md --- docs/source/qs/{input.rst => input.md} | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) rename docs/source/qs/{input.rst => input.md} (84%) diff --git a/docs/source/qs/input.rst b/docs/source/qs/input.md similarity index 84% rename from docs/source/qs/input.rst rename to docs/source/qs/input.md index 26893020..b7ef0baf 100644 --- a/docs/source/qs/input.rst +++ b/docs/source/qs/input.md @@ -2,7 +2,7 @@ Brief Introduction to Inputs ====================================== The dictionary ``CanteraTorchProperties`` is the original dictionay of DeepFlame. It read in netowrk realted parameters and configurations. It typically looks like: -.. code-block:: +``` chemistry on; CanteraMechanismFile "ES80_H2-7-16.yaml"; @@ -46,13 +46,12 @@ The dictionary ``CanteraTorchProperties`` is the original dictionay of DeepFlame active false; //log true; } +``` - -In the above example, the meanings of the parameters are: -* ``CanteraMechanismFile``: the name of the reaction mechanism file +In the above example, the meanings of the parameters are: ``CanteraMechanismFile``: the name of the reaction mechanism file * ``odeCoeffs``: the ode torlerance. 1e-15 and 1e-24 are used for network training, so it should keep the same when comparing results with nd without DNN. * ``torch``: the switch used to control the on and off of DNN. If users are running CVODE, this needs to be switched off. * ``GPU``: the switch used to control whether GPU or CPU is used to carry out inference. * ``torchModel``: name of network. -* ``torchParameters``: thresholds used to decide when to use network -* ``coresPerGPU``: number of CPU cores on one node +* ``torchParameters``: thresholds used to decide when to use network. +* ``coresPerGPU``: number of CPU cores on one node. From 650b107325ad2a15cf7f2a0a2bf091a11c476680 Mon Sep 17 00:00:00 2001 From: JX278 <113102069+JX278@users.noreply.github.com> Date: Fri, 11 Nov 2022 17:42:26 +0800 Subject: [PATCH 08/15] Update input.md --- docs/source/qs/input.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/qs/input.md b/docs/source/qs/input.md index b7ef0baf..f7551a7f 100644 --- a/docs/source/qs/input.md +++ b/docs/source/qs/input.md @@ -2,7 +2,6 @@ Brief Introduction to Inputs ====================================== The dictionary ``CanteraTorchProperties`` is the original dictionay of DeepFlame. It read in netowrk realted parameters and configurations. It typically looks like: -``` chemistry on; CanteraMechanismFile "ES80_H2-7-16.yaml"; @@ -46,7 +45,7 @@ The dictionary ``CanteraTorchProperties`` is the original dictionay of DeepFlame active false; //log true; } -``` + In the above example, the meanings of the parameters are: ``CanteraMechanismFile``: the name of the reaction mechanism file * ``odeCoeffs``: the ode torlerance. 1e-15 and 1e-24 are used for network training, so it should keep the same when comparing results with nd without DNN. From 8da359d6854940f40b742e81af82d5c46282fd5b Mon Sep 17 00:00:00 2001 From: JX278 <113102069+JX278@users.noreply.github.com> Date: Fri, 11 Nov 2022 18:00:48 +0800 Subject: [PATCH 09/15] Update input.md --- docs/source/qs/input.md | 82 ++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/docs/source/qs/input.md b/docs/source/qs/input.md index f7551a7f..ca1bf110 100644 --- a/docs/source/qs/input.md +++ b/docs/source/qs/input.md @@ -2,50 +2,50 @@ Brief Introduction to Inputs ====================================== The dictionary ``CanteraTorchProperties`` is the original dictionay of DeepFlame. It read in netowrk realted parameters and configurations. It typically looks like: +``` +chemistry on; +CanteraMechanismFile "ES80_H2-7-16.yaml"; +transportModel "Mix";//"UnityLewis"; +odeCoeffs +{ + //"relTol" 1e-15; + //"absTol" 1e-24; +} +inertSpecie "N2"; - chemistry on; - CanteraMechanismFile "ES80_H2-7-16.yaml"; - transportModel "Mix";//"UnityLewis"; - odeCoeffs - { - //"relTol" 1e-15; - //"absTol" 1e-24; - } - inertSpecie "N2"; +zeroDReactor +{ + constantProperty "pressure"; +} - zeroDReactor - { - constantProperty "pressure"; - } - - torch on; - GPU on; - torchModel1 "ESH2-sub1.pt"; - torchModel2 "ESH2-sub2.pt"; - torchModel3 "ESH2-sub3.pt"; - - torchParameters1 - { - Tact 700 ; - Qdotact 3e7; - coresPerGPU 4; - } - torchParameters2 - { - Tact 2000; - Qdotact 3e7; - } - torchParameters3 - { - Tact 2000; - Qdotact 7e8; - } - loadbalancing - { - active false; - //log true; - } +torch on; +GPU on; +torchModel1 "ESH2-sub1.pt"; +torchModel2 "ESH2-sub2.pt"; +torchModel3 "ESH2-sub3.pt"; +torchParameters1 +{ + Tact 700 ; + Qdotact 3e7; + coresPerGPU 4; +} +torchParameters2 +{ + Tact 2000; + Qdotact 3e7; +} +torchParameters3 +{ + Tact 2000; + Qdotact 7e8; +} +loadbalancing +{ + active false; + //log true; +} +``` In the above example, the meanings of the parameters are: ``CanteraMechanismFile``: the name of the reaction mechanism file * ``odeCoeffs``: the ode torlerance. 1e-15 and 1e-24 are used for network training, so it should keep the same when comparing results with nd without DNN. From 70d0dba00af64b177ec78ea90b550d5901241bd1 Mon Sep 17 00:00:00 2001 From: JX278 <113102069+JX278@users.noreply.github.com> Date: Fri, 11 Nov 2022 18:10:12 +0800 Subject: [PATCH 10/15] Update and rename input.md to input.rst --- docs/source/qs/input.md | 56 -------------------------------------- docs/source/qs/input.rst | 59 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 56 deletions(-) delete mode 100644 docs/source/qs/input.md create mode 100644 docs/source/qs/input.rst diff --git a/docs/source/qs/input.md b/docs/source/qs/input.md deleted file mode 100644 index ca1bf110..00000000 --- a/docs/source/qs/input.md +++ /dev/null @@ -1,56 +0,0 @@ -Brief Introduction to Inputs -====================================== -The dictionary ``CanteraTorchProperties`` is the original dictionay of DeepFlame. It read in netowrk realted parameters and configurations. It typically looks like: - -``` -chemistry on; -CanteraMechanismFile "ES80_H2-7-16.yaml"; -transportModel "Mix";//"UnityLewis"; -odeCoeffs -{ - //"relTol" 1e-15; - //"absTol" 1e-24; -} -inertSpecie "N2"; - -zeroDReactor -{ - constantProperty "pressure"; -} - -torch on; -GPU on; -torchModel1 "ESH2-sub1.pt"; -torchModel2 "ESH2-sub2.pt"; -torchModel3 "ESH2-sub3.pt"; - -torchParameters1 -{ - Tact 700 ; - Qdotact 3e7; - coresPerGPU 4; -} -torchParameters2 -{ - Tact 2000; - Qdotact 3e7; -} -torchParameters3 -{ - Tact 2000; - Qdotact 7e8; -} -loadbalancing -{ - active false; - //log true; -} -``` - -In the above example, the meanings of the parameters are: ``CanteraMechanismFile``: the name of the reaction mechanism file -* ``odeCoeffs``: the ode torlerance. 1e-15 and 1e-24 are used for network training, so it should keep the same when comparing results with nd without DNN. -* ``torch``: the switch used to control the on and off of DNN. If users are running CVODE, this needs to be switched off. -* ``GPU``: the switch used to control whether GPU or CPU is used to carry out inference. -* ``torchModel``: name of network. -* ``torchParameters``: thresholds used to decide when to use network. -* ``coresPerGPU``: number of CPU cores on one node. diff --git a/docs/source/qs/input.rst b/docs/source/qs/input.rst new file mode 100644 index 00000000..afcc24a9 --- /dev/null +++ b/docs/source/qs/input.rst @@ -0,0 +1,59 @@ +Brief Introduction to Inputs +====================================== +The dictionary ``CanteraTorchProperties`` is the original dictionay of DeepFlame. It read in netowrk realted parameters and configurations. It typically looks like: + +.. code-block:: + + chemistry on; + CanteraMechanismFile "ES80_H2-7-16.yaml"; + transportModel "Mix";//"UnityLewis"; + odeCoeffs + { + //"relTol" 1e-15; + //"absTol" 1e-24; + } + inertSpecie "N2"; + + zeroDReactor + { + constantProperty "pressure"; + } + + torch on; + GPU on; + torchModel1 "ESH2-sub1.pt"; + torchModel2 "ESH2-sub2.pt"; + torchModel3 "ESH2-sub3.pt"; + + torchParameters1 + { + Tact 700 ; + Qdotact 3e7; + coresPerGPU 4; + } + torchParameters2 + { + Tact 2000; + Qdotact 3e7; + } + torchParameters3 + { + Tact 2000; + Qdotact 7e8; + } + loadbalancing + { + active false; + //log true; + } + + +In the above example, the meanings of the parameters are: + +* ``CanteraMechanismFile``: the name of the reaction mechanism file +* ``odeCoeffs``: the ode torlerance. 1e-15 and 1e-24 are used for network training, so it should keep the same when comparing results with nd without DNN. +* ``torch``: the switch used to control the on and off of DNN. If users are running CVODE, this needs to be switched off. +* ``GPU``: the switch used to control whether GPU or CPU is used to carry out inference. +* ``torchModel``: name of network. +* ``torchParameters``: thresholds used to decide when to use network. +* ``coresPerGPU``: number of CPU cores on one node. From 0e29757700f05672af464dd7daaf7e1722868e5e Mon Sep 17 00:00:00 2001 From: Zhi Chen Date: Sun, 13 Nov 2022 11:22:06 +0800 Subject: [PATCH 11/15] Update install.rst --- docs/source/qs/install.rst | 70 ++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/docs/source/qs/install.rst b/docs/source/qs/install.rst index d41ea352..e4d30d90 100644 --- a/docs/source/qs/install.rst +++ b/docs/source/qs/install.rst @@ -16,14 +16,16 @@ First install OpenFOAM-7 if it is not already installed. sudo apt-get update sudo apt-get -y install openfoam7 -OpenFOAM 7 and ParaView 5.6.0 will be installed in the ``/opt`` directory. +OpenFOAM-7 and ParaView-5.6.0 will be installed in the ``/opt`` directory. -**LibCantera** and **PyTorch** are installed via `conda `_. DNN version aims to support computation on CUDA. If you have compatible platform, run the following command to install DeepFlame. +.. Note:: There is a commonly seen issue when installing OpenFOAM via ``apt-get install`` with an error message: ``could not find a distribution template for Ubuntu/focal``. To resolve this issue, you can refer to `issue#54 `_. + +**LibCantera** and **PyTorch** can be easily installed via `conda `_. If you have compatible platform, run the following command to install DeepFlame. .. code-block:: bash - conda create -n df-pytorch python=3.8 - conda activate df-pytorch + conda create -n deepflame python=3.8 + conda activate deepflame conda install -c cantera libcantera-devel conda install pytorch torchvision torchaudio pytorch-cuda=11.6 -c pytorch -c nvidia conda install pybind11 easydict @@ -31,31 +33,55 @@ OpenFOAM 7 and ParaView 5.6.0 will be installed in the ``/opt`` directory. .. Note:: Please go to PyTorch's official website to check your system compatability and choose the installation command line that is suitable for your platform. -.. Note:: Check your ``Miniconda3/envs/libcantera`` directory and make sure the install was successful (lib/ include/ etc. exist). +.. Note:: Check your ``Miniconda3/envs/deepflame`` directory and make sure the install was successful (lib/ include/ etc. exist). + Configure ------------------------- -You need to source your OpenFOAM-7. +**1. Source your OpenFOAM-7 bashrc to configure the ``$FOAM`` environment.** + +.. Note:: This depends on your own path for OpenFOAM-7 bashrc. + +If you have installed using ``apt-get install``, use + +.. code-block:: bash + + source /opt/openfoam7/etc/bashrc + +If you compiled from source following the `official guild `_ , use + .. code-block:: bash source $HOME/OpenFOAM/OpenFOAM-7/etc/bashrc -This depends on your own path for OpenFOAM bashrc. - +.. Note:: Check your environment using ``echo $FOAM_ETC`` and you should get the directory path for your OpenFOAM-7 bashrc you just used in the above step. + +**2. Clone the DeepFlame repository:** -Build and Install -------------------------------- -DeepFlame with DNN capatibility is installed through: .. code-block:: bash git clone https://github.com/deepmodeling/deepflame-dev.git + +**3. Configure the DeepFlame environment:** + +.. code-block:: bash + cd deepflame-dev + . configure.sh --use_pytorch source ./bashrc - . install.sh --use_pytorch + +.. Note:: Check your environment using ``echo $DF_ROOT`` and you should get the path for the deepflame-dev directory. + +Build and Install +------------------------------- +Finally you can build and install DeepFlame: + +.. code-block:: bash + + . install.sh .. Note:: You may come accross an error regarding shared library ``libmkl_rt.so.2`` when libcantera is installed through cantera channel. If so, go to your conda environment and check the existance of ``libmkl_rt.so.2`` and ``libmkl_rt.so.1``, and then link ``libmkl_rt.so.2`` to ``libmkl_rt.so.1``. - .. code-block:: bash cd ~/miniconda3/envs/df-pytorch/lib @@ -65,7 +91,7 @@ DeepFlame with DNN capatibility is installed through: Other Options ------------------------------- -DeepFlame also provides users with LibTorch integraotr and CVODE integrator. +DeepFlame also provides users with LibTorch and CVODE (no DNN version) options. If you choose to use LibTorch (C++ API for Torch), first create the conda env and install `LibCantera `_: @@ -76,10 +102,13 @@ If you choose to use LibTorch (C++ API for Torch), first create the conda env an conda install -c cantera libcantera-devel Then you can pass your own libtorch path to DeepFlame. -.. code-block:: bash - . install.sh --libtorch_dir /path/to/libtorch/ +.. code-block:: bash + cd deepflame-dev + . configure.sh --libtorch_dir /path/to/libtorch/ + source ./bashrc + . install.sh .. Note:: Some compiling issues may happen due to system compatability. Instead of using conda installed Cantera C++ lib and the downloaded Torch C++ lib, try to compile your own Cantera and Torch C++ libraries. @@ -96,10 +125,15 @@ If the conda env ``df-notorch`` is activated, install DeepFlame by running: .. code-block:: bash - . install.sh + cd deepflame-dev + . configure.sh + source ./bashrc + . install.sh If ``df-notorch`` not activated (or you have a self-complied libcantera), specify the path to your libcantera: .. code-block:: bash - . install.sh --libcantera_dir /your/path/to/libcantera/ + . configure.sh --libcantera_dir /your/path/to/libcantera/ + source ./bashrc + . install.sh From e2ecb3c7a19eb96f2a53aebbe9a85ff62c5be995 Mon Sep 17 00:00:00 2001 From: Zhi Chen Date: Sun, 13 Nov 2022 17:01:21 +0800 Subject: [PATCH 12/15] Update install.rst --- docs/source/qs/install.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/source/qs/install.rst b/docs/source/qs/install.rst index e4d30d90..97d37dc9 100644 --- a/docs/source/qs/install.rst +++ b/docs/source/qs/install.rst @@ -38,17 +38,17 @@ OpenFOAM-7 and ParaView-5.6.0 will be installed in the ``/opt`` directory. Configure ------------------------- -**1. Source your OpenFOAM-7 bashrc to configure the ``$FOAM`` environment.** +**1. Source your OpenFOAM-7 bashrc to configure the $FOAM environment.** .. Note:: This depends on your own path for OpenFOAM-7 bashrc. -If you have installed using ``apt-get install``, use +If you have installed using ``apt-get install``, use: .. code-block:: bash source /opt/openfoam7/etc/bashrc -If you compiled from source following the `official guild `_ , use +If you compiled from source following the `official guild `_, use: .. code-block:: bash @@ -87,13 +87,15 @@ Finally you can build and install DeepFlame: cd ~/miniconda3/envs/df-pytorch/lib ln -s libmkl_rt.so.1 libmkl_rt.so.2 +**If you have compiled DeepFlame successfully, you should see the print message in your terminal:** +.. figure:: complie_success.png Other Options ------------------------------- DeepFlame also provides users with LibTorch and CVODE (no DNN version) options. -If you choose to use LibTorch (C++ API for Torch), first create the conda env and install `LibCantera `_: +**1. If you choose to use LibTorch (C++ API for Torch), first create the conda env and install** `LibCantera `_: .. code-block:: bash @@ -113,7 +115,7 @@ Then you can pass your own libtorch path to DeepFlame. .. Note:: Some compiling issues may happen due to system compatability. Instead of using conda installed Cantera C++ lib and the downloaded Torch C++ lib, try to compile your own Cantera and Torch C++ libraries. -If your are using DeepFlame's CVODE solver without DNN model, just install LibCantera via `conda `_. +**2. If you just need DeepFlame's CVODE solver without DNN model, just install LibCantera via** `conda `_. .. code-block:: bash From 43ca8cbfe662f30cb9a6e80b2259c3ebf518fdb1 Mon Sep 17 00:00:00 2001 From: JX278 <113102069+JX278@users.noreply.github.com> Date: Sun, 13 Nov 2022 17:03:58 +0800 Subject: [PATCH 13/15] Add compile_success figure --- docs/source/qs/compile_success.png | Bin 0 -> 25454 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/source/qs/compile_success.png diff --git a/docs/source/qs/compile_success.png b/docs/source/qs/compile_success.png new file mode 100644 index 0000000000000000000000000000000000000000..0967e2aeda0ad6eff26a31034f87b1f207b004e3 GIT binary patch literal 25454 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 Date: Sun, 13 Nov 2022 17:13:21 +0800 Subject: [PATCH 14/15] Update install.rst --- docs/source/qs/install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/qs/install.rst b/docs/source/qs/install.rst index 97d37dc9..b3e88358 100644 --- a/docs/source/qs/install.rst +++ b/docs/source/qs/install.rst @@ -89,7 +89,7 @@ Finally you can build and install DeepFlame: **If you have compiled DeepFlame successfully, you should see the print message in your terminal:** -.. figure:: complie_success.png +.. figure:: compile_success.png Other Options ------------------------------- From f307c0dbc6d977751f00b1f230f54af2f62c5cc5 Mon Sep 17 00:00:00 2001 From: JX278 Date: Mon, 14 Nov 2022 13:16:50 +0800 Subject: [PATCH 15/15] fix cpu inference --- .../constant/CanteraTorchProperties | 2 +- .../H2/pytorchIntegrator/inference.py | 34 ++++++-- .../H2/pytorchIntegrator/inference.py | 85 +++++++++++++++---- .../H2/pytorchIntegrator/inference.py | 85 +++++++++++++++---- test/df0DFoam/inference.py | 34 ++++++-- .../H2/cvodeSolver/inference.py | 34 ++++++-- 6 files changed, 220 insertions(+), 54 deletions(-) diff --git a/examples/df0DFoam/zeroD_cubicReactor/H2/pytorchIntegrator/constant/CanteraTorchProperties b/examples/df0DFoam/zeroD_cubicReactor/H2/pytorchIntegrator/constant/CanteraTorchProperties index b7f3f952..13d5fc9a 100644 --- a/examples/df0DFoam/zeroD_cubicReactor/H2/pytorchIntegrator/constant/CanteraTorchProperties +++ b/examples/df0DFoam/zeroD_cubicReactor/H2/pytorchIntegrator/constant/CanteraTorchProperties @@ -32,7 +32,7 @@ zeroDReactor TorchSettings { - torch off; + torch on; GPU off; log on; torchModel1 "ESH2-sub1.pt"; diff --git a/examples/df0DFoam/zeroD_cubicReactor/H2/pytorchIntegrator/inference.py b/examples/df0DFoam/zeroD_cubicReactor/H2/pytorchIntegrator/inference.py index 6b0e5780..822624f2 100644 --- a/examples/df0DFoam/zeroD_cubicReactor/H2/pytorchIntegrator/inference.py +++ b/examples/df0DFoam/zeroD_cubicReactor/H2/pytorchIntegrator/inference.py @@ -10,6 +10,8 @@ import torch.profiler import os + + torch.set_printoptions(precision=10) @@ -91,11 +93,12 @@ def forward(self, x): setting0 = json2Parser(str("pytorchDNN/"+moduleName1+".json")) setting1 = json2Parser(str("pytorchDNN/"+moduleName2+".json")) setting2 = json2Parser(str("pytorchDNN/"+moduleName3+".json")) - + #print(str("pytorchDNN/"+moduleName1+".json")) lamda = setting0.power_transform delta_t = setting0.delta_t dim = setting0.dim layers = setting0.layers + Xmu0 = torch.tensor(setting0.Xmu).unsqueeze(0).to(device) Xstd0 = torch.tensor(setting0.Xstd).unsqueeze(0).to(device=device) @@ -116,22 +119,33 @@ def forward(self, x): model0 = Net() model1 = Net() model2 = Net() - check_point0 = torch.load(str("pytorchDNN/"+moduleName1+".pt")) - check_point1 = torch.load(str("pytorchDNN/"+moduleName2+".pt")) - check_point2 = torch.load(str("pytorchDNN/"+moduleName3+".pt")) + + if torch.cuda.is_available()==False: + check_point0 = torch.load(str("pytorchDNN/"+moduleName1+".pt"), map_location='cpu') + check_point1 = torch.load(str("pytorchDNN/"+moduleName2+".pt"), map_location='cpu') + check_point2 = torch.load(str("pytorchDNN/"+moduleName3+".pt"), map_location='cpu') + else: + check_point0 = torch.load(str("pytorchDNN/"+moduleName1+".pt")) + check_point1 = torch.load(str("pytorchDNN/"+moduleName2+".pt")) + check_point2 = torch.load(str("pytorchDNN/"+moduleName3+".pt")) + model0.load_state_dict(check_point0) model1.load_state_dict(check_point1) model2.load_state_dict(check_point2) model0.to(device=device) model1.to(device=device) model2.to(device=device) + if len(device_ids) > 1: model0 = torch.nn.DataParallel(model0, device_ids=device_ids) model1 = torch.nn.DataParallel(model1, device_ids=device_ids) model2 = torch.nn.DataParallel(model2, device_ids=device_ids) except Exception as e: print(e.args) - +# print("check_point0") +# print(check_point0) +# print("fc.0.weight") +# print(model0.state_dict()['fc.0.weight']) def inference(vec0, vec1, vec2): ''' @@ -159,7 +173,8 @@ def inference(vec0, vec1, vec2): input0_normalized = (input0_bct - Xmu0) / Xstd0 # input0_normalized[:, -1] = 0 #set Y_AR to 0 input0_normalized = input0_normalized.float() - + #print("input0_normalized") + #print(input0_normalized[0]) rho1 = input1_[:, 0].unsqueeze(1) input1_Y = input1_[:, 3:].clone() input1_bct = input1_[:, 1:] @@ -181,8 +196,13 @@ def inference(vec0, vec1, vec2): output0_normalized = model0(input0_normalized) output1_normalized = model1(input1_normalized) output2_normalized = model2(input2_normalized) + #print("output0_normalized") + #print(output0_normalized[0]) + # for name in model0.state_dict(): + # print(name) - + # print("fc.0.weight") + # print(model0.state_dict()['fc.0.weight']) # post_processing output0_bct = (output0_normalized * Ystd0 + Ymu0) * delta_t + input0_bct output0_Y = (lamda * output0_bct[:, 2:] + 1)**(1 / lamda) diff --git a/examples/dfLowMachFoam/oneD_freelyPropagation/H2/pytorchIntegrator/inference.py b/examples/dfLowMachFoam/oneD_freelyPropagation/H2/pytorchIntegrator/inference.py index 5cfc4065..822624f2 100644 --- a/examples/dfLowMachFoam/oneD_freelyPropagation/H2/pytorchIntegrator/inference.py +++ b/examples/dfLowMachFoam/oneD_freelyPropagation/H2/pytorchIntegrator/inference.py @@ -10,12 +10,10 @@ import torch.profiler import os -torch.set_printoptions(precision=10) -print('position 0 in inference.py') -device = torch.device("cuda") -device_ids = range(torch.cuda.device_count()) +torch.set_printoptions(precision=10) + class MyGELU(torch.nn.Module): def __init__(self): @@ -51,16 +49,56 @@ def forward(self, x): x = self.fc(x) return x try: + #load variables from constant/CanteraTorchProperties + path_r = r"./constant/CanteraTorchProperties" + with open(path_r, "r") as f: + data = f.read() + i = data.index('torchModel1') + a = data.index('"',i) + b = data.index('.',a+1) + moduleName1 = data[a+1:b] + + i = data.index('torchModel2') + a = data.index('"',i) + b = data.index('.',a+1) + moduleName2 = data[a+1:b] + + i = data.index('torchModel3') + a = data.index('"',i) + b = data.index('.',a+1) + moduleName3 = data[a+1:b] + + i = data.index('GPU') + a = data.index(';', i) + b = data.rfind(' ',i+1,a) + switch_GPU = data[b+1:a] + + #load OpenFOAM switch + switch_on = ["true", "True", "on", "yes", "y", "t", "any"] + switch_off = ["false", "False", "off", "no", "n", "f", "none"] + if switch_GPU in switch_on: + device = torch.device("cuda") + device_ids = range(torch.cuda.device_count()) + elif switch_GPU in switch_off: + device = torch.device("cpu") + device_ids = [0] + else: + print("invalid setting!") + os._exit(0) + + + #glbal variable will only init once when called interperter #load parameters from json - setting0 = json2Parser('pytorchDNN/settings1.json') - setting1 = json2Parser('pytorchDNN/settings2.json') - setting2 = json2Parser('pytorchDNN/settings3.json') - + setting0 = json2Parser(str("pytorchDNN/"+moduleName1+".json")) + setting1 = json2Parser(str("pytorchDNN/"+moduleName2+".json")) + setting2 = json2Parser(str("pytorchDNN/"+moduleName3+".json")) + #print(str("pytorchDNN/"+moduleName1+".json")) lamda = setting0.power_transform delta_t = setting0.delta_t dim = setting0.dim layers = setting0.layers + Xmu0 = torch.tensor(setting0.Xmu).unsqueeze(0).to(device) Xstd0 = torch.tensor(setting0.Xstd).unsqueeze(0).to(device=device) @@ -76,29 +114,38 @@ def forward(self, x): Xstd2 = torch.tensor(setting2.Xstd).unsqueeze(0).to(device=device) Ymu2 = torch.tensor(setting2.Ymu).unsqueeze(0).to(device=device) Ystd2 = torch.tensor(setting2.Ystd).unsqueeze(0).to(device=device) - print('position 1 in inference.py') #load module model0 = Net() model1 = Net() model2 = Net() - check_point0 = torch.load('pytorchDNN/ESH2-sub1.pt') - check_point1 = torch.load('pytorchDNN/ESH2-sub2.pt') - check_point2 = torch.load('pytorchDNN/ESH2-sub3.pt') + + if torch.cuda.is_available()==False: + check_point0 = torch.load(str("pytorchDNN/"+moduleName1+".pt"), map_location='cpu') + check_point1 = torch.load(str("pytorchDNN/"+moduleName2+".pt"), map_location='cpu') + check_point2 = torch.load(str("pytorchDNN/"+moduleName3+".pt"), map_location='cpu') + else: + check_point0 = torch.load(str("pytorchDNN/"+moduleName1+".pt")) + check_point1 = torch.load(str("pytorchDNN/"+moduleName2+".pt")) + check_point2 = torch.load(str("pytorchDNN/"+moduleName3+".pt")) + model0.load_state_dict(check_point0) model1.load_state_dict(check_point1) model2.load_state_dict(check_point2) model0.to(device=device) model1.to(device=device) model2.to(device=device) + if len(device_ids) > 1: model0 = torch.nn.DataParallel(model0, device_ids=device_ids) model1 = torch.nn.DataParallel(model1, device_ids=device_ids) model2 = torch.nn.DataParallel(model2, device_ids=device_ids) - print('call init') except Exception as e: print(e.args) - +# print("check_point0") +# print(check_point0) +# print("fc.0.weight") +# print(model0.state_dict()['fc.0.weight']) def inference(vec0, vec1, vec2): ''' @@ -126,7 +173,8 @@ def inference(vec0, vec1, vec2): input0_normalized = (input0_bct - Xmu0) / Xstd0 # input0_normalized[:, -1] = 0 #set Y_AR to 0 input0_normalized = input0_normalized.float() - + #print("input0_normalized") + #print(input0_normalized[0]) rho1 = input1_[:, 0].unsqueeze(1) input1_Y = input1_[:, 3:].clone() input1_bct = input1_[:, 1:] @@ -148,8 +196,13 @@ def inference(vec0, vec1, vec2): output0_normalized = model0(input0_normalized) output1_normalized = model1(input1_normalized) output2_normalized = model2(input2_normalized) + #print("output0_normalized") + #print(output0_normalized[0]) + # for name in model0.state_dict(): + # print(name) - + # print("fc.0.weight") + # print(model0.state_dict()['fc.0.weight']) # post_processing output0_bct = (output0_normalized * Ystd0 + Ymu0) * delta_t + input0_bct output0_Y = (lamda * output0_bct[:, 2:] + 1)**(1 / lamda) diff --git a/examples/dfLowMachFoam/threeD_reactingTGV/H2/pytorchIntegrator/inference.py b/examples/dfLowMachFoam/threeD_reactingTGV/H2/pytorchIntegrator/inference.py index 5cfc4065..822624f2 100644 --- a/examples/dfLowMachFoam/threeD_reactingTGV/H2/pytorchIntegrator/inference.py +++ b/examples/dfLowMachFoam/threeD_reactingTGV/H2/pytorchIntegrator/inference.py @@ -10,12 +10,10 @@ import torch.profiler import os -torch.set_printoptions(precision=10) -print('position 0 in inference.py') -device = torch.device("cuda") -device_ids = range(torch.cuda.device_count()) +torch.set_printoptions(precision=10) + class MyGELU(torch.nn.Module): def __init__(self): @@ -51,16 +49,56 @@ def forward(self, x): x = self.fc(x) return x try: + #load variables from constant/CanteraTorchProperties + path_r = r"./constant/CanteraTorchProperties" + with open(path_r, "r") as f: + data = f.read() + i = data.index('torchModel1') + a = data.index('"',i) + b = data.index('.',a+1) + moduleName1 = data[a+1:b] + + i = data.index('torchModel2') + a = data.index('"',i) + b = data.index('.',a+1) + moduleName2 = data[a+1:b] + + i = data.index('torchModel3') + a = data.index('"',i) + b = data.index('.',a+1) + moduleName3 = data[a+1:b] + + i = data.index('GPU') + a = data.index(';', i) + b = data.rfind(' ',i+1,a) + switch_GPU = data[b+1:a] + + #load OpenFOAM switch + switch_on = ["true", "True", "on", "yes", "y", "t", "any"] + switch_off = ["false", "False", "off", "no", "n", "f", "none"] + if switch_GPU in switch_on: + device = torch.device("cuda") + device_ids = range(torch.cuda.device_count()) + elif switch_GPU in switch_off: + device = torch.device("cpu") + device_ids = [0] + else: + print("invalid setting!") + os._exit(0) + + + #glbal variable will only init once when called interperter #load parameters from json - setting0 = json2Parser('pytorchDNN/settings1.json') - setting1 = json2Parser('pytorchDNN/settings2.json') - setting2 = json2Parser('pytorchDNN/settings3.json') - + setting0 = json2Parser(str("pytorchDNN/"+moduleName1+".json")) + setting1 = json2Parser(str("pytorchDNN/"+moduleName2+".json")) + setting2 = json2Parser(str("pytorchDNN/"+moduleName3+".json")) + #print(str("pytorchDNN/"+moduleName1+".json")) lamda = setting0.power_transform delta_t = setting0.delta_t dim = setting0.dim layers = setting0.layers + Xmu0 = torch.tensor(setting0.Xmu).unsqueeze(0).to(device) Xstd0 = torch.tensor(setting0.Xstd).unsqueeze(0).to(device=device) @@ -76,29 +114,38 @@ def forward(self, x): Xstd2 = torch.tensor(setting2.Xstd).unsqueeze(0).to(device=device) Ymu2 = torch.tensor(setting2.Ymu).unsqueeze(0).to(device=device) Ystd2 = torch.tensor(setting2.Ystd).unsqueeze(0).to(device=device) - print('position 1 in inference.py') #load module model0 = Net() model1 = Net() model2 = Net() - check_point0 = torch.load('pytorchDNN/ESH2-sub1.pt') - check_point1 = torch.load('pytorchDNN/ESH2-sub2.pt') - check_point2 = torch.load('pytorchDNN/ESH2-sub3.pt') + + if torch.cuda.is_available()==False: + check_point0 = torch.load(str("pytorchDNN/"+moduleName1+".pt"), map_location='cpu') + check_point1 = torch.load(str("pytorchDNN/"+moduleName2+".pt"), map_location='cpu') + check_point2 = torch.load(str("pytorchDNN/"+moduleName3+".pt"), map_location='cpu') + else: + check_point0 = torch.load(str("pytorchDNN/"+moduleName1+".pt")) + check_point1 = torch.load(str("pytorchDNN/"+moduleName2+".pt")) + check_point2 = torch.load(str("pytorchDNN/"+moduleName3+".pt")) + model0.load_state_dict(check_point0) model1.load_state_dict(check_point1) model2.load_state_dict(check_point2) model0.to(device=device) model1.to(device=device) model2.to(device=device) + if len(device_ids) > 1: model0 = torch.nn.DataParallel(model0, device_ids=device_ids) model1 = torch.nn.DataParallel(model1, device_ids=device_ids) model2 = torch.nn.DataParallel(model2, device_ids=device_ids) - print('call init') except Exception as e: print(e.args) - +# print("check_point0") +# print(check_point0) +# print("fc.0.weight") +# print(model0.state_dict()['fc.0.weight']) def inference(vec0, vec1, vec2): ''' @@ -126,7 +173,8 @@ def inference(vec0, vec1, vec2): input0_normalized = (input0_bct - Xmu0) / Xstd0 # input0_normalized[:, -1] = 0 #set Y_AR to 0 input0_normalized = input0_normalized.float() - + #print("input0_normalized") + #print(input0_normalized[0]) rho1 = input1_[:, 0].unsqueeze(1) input1_Y = input1_[:, 3:].clone() input1_bct = input1_[:, 1:] @@ -148,8 +196,13 @@ def inference(vec0, vec1, vec2): output0_normalized = model0(input0_normalized) output1_normalized = model1(input1_normalized) output2_normalized = model2(input2_normalized) + #print("output0_normalized") + #print(output0_normalized[0]) + # for name in model0.state_dict(): + # print(name) - + # print("fc.0.weight") + # print(model0.state_dict()['fc.0.weight']) # post_processing output0_bct = (output0_normalized * Ystd0 + Ymu0) * delta_t + input0_bct output0_Y = (lamda * output0_bct[:, 2:] + 1)**(1 / lamda) diff --git a/test/df0DFoam/inference.py b/test/df0DFoam/inference.py index 6b0e5780..822624f2 100644 --- a/test/df0DFoam/inference.py +++ b/test/df0DFoam/inference.py @@ -10,6 +10,8 @@ import torch.profiler import os + + torch.set_printoptions(precision=10) @@ -91,11 +93,12 @@ def forward(self, x): setting0 = json2Parser(str("pytorchDNN/"+moduleName1+".json")) setting1 = json2Parser(str("pytorchDNN/"+moduleName2+".json")) setting2 = json2Parser(str("pytorchDNN/"+moduleName3+".json")) - + #print(str("pytorchDNN/"+moduleName1+".json")) lamda = setting0.power_transform delta_t = setting0.delta_t dim = setting0.dim layers = setting0.layers + Xmu0 = torch.tensor(setting0.Xmu).unsqueeze(0).to(device) Xstd0 = torch.tensor(setting0.Xstd).unsqueeze(0).to(device=device) @@ -116,22 +119,33 @@ def forward(self, x): model0 = Net() model1 = Net() model2 = Net() - check_point0 = torch.load(str("pytorchDNN/"+moduleName1+".pt")) - check_point1 = torch.load(str("pytorchDNN/"+moduleName2+".pt")) - check_point2 = torch.load(str("pytorchDNN/"+moduleName3+".pt")) + + if torch.cuda.is_available()==False: + check_point0 = torch.load(str("pytorchDNN/"+moduleName1+".pt"), map_location='cpu') + check_point1 = torch.load(str("pytorchDNN/"+moduleName2+".pt"), map_location='cpu') + check_point2 = torch.load(str("pytorchDNN/"+moduleName3+".pt"), map_location='cpu') + else: + check_point0 = torch.load(str("pytorchDNN/"+moduleName1+".pt")) + check_point1 = torch.load(str("pytorchDNN/"+moduleName2+".pt")) + check_point2 = torch.load(str("pytorchDNN/"+moduleName3+".pt")) + model0.load_state_dict(check_point0) model1.load_state_dict(check_point1) model2.load_state_dict(check_point2) model0.to(device=device) model1.to(device=device) model2.to(device=device) + if len(device_ids) > 1: model0 = torch.nn.DataParallel(model0, device_ids=device_ids) model1 = torch.nn.DataParallel(model1, device_ids=device_ids) model2 = torch.nn.DataParallel(model2, device_ids=device_ids) except Exception as e: print(e.args) - +# print("check_point0") +# print(check_point0) +# print("fc.0.weight") +# print(model0.state_dict()['fc.0.weight']) def inference(vec0, vec1, vec2): ''' @@ -159,7 +173,8 @@ def inference(vec0, vec1, vec2): input0_normalized = (input0_bct - Xmu0) / Xstd0 # input0_normalized[:, -1] = 0 #set Y_AR to 0 input0_normalized = input0_normalized.float() - + #print("input0_normalized") + #print(input0_normalized[0]) rho1 = input1_[:, 0].unsqueeze(1) input1_Y = input1_[:, 3:].clone() input1_bct = input1_[:, 1:] @@ -181,8 +196,13 @@ def inference(vec0, vec1, vec2): output0_normalized = model0(input0_normalized) output1_normalized = model1(input1_normalized) output2_normalized = model2(input2_normalized) + #print("output0_normalized") + #print(output0_normalized[0]) + # for name in model0.state_dict(): + # print(name) - + # print("fc.0.weight") + # print(model0.state_dict()['fc.0.weight']) # post_processing output0_bct = (output0_normalized * Ystd0 + Ymu0) * delta_t + input0_bct output0_Y = (lamda * output0_bct[:, 2:] + 1)**(1 / lamda) diff --git a/test/dfLowMachFoam/twoD_reactingTGV/H2/cvodeSolver/inference.py b/test/dfLowMachFoam/twoD_reactingTGV/H2/cvodeSolver/inference.py index 6b0e5780..822624f2 100644 --- a/test/dfLowMachFoam/twoD_reactingTGV/H2/cvodeSolver/inference.py +++ b/test/dfLowMachFoam/twoD_reactingTGV/H2/cvodeSolver/inference.py @@ -10,6 +10,8 @@ import torch.profiler import os + + torch.set_printoptions(precision=10) @@ -91,11 +93,12 @@ def forward(self, x): setting0 = json2Parser(str("pytorchDNN/"+moduleName1+".json")) setting1 = json2Parser(str("pytorchDNN/"+moduleName2+".json")) setting2 = json2Parser(str("pytorchDNN/"+moduleName3+".json")) - + #print(str("pytorchDNN/"+moduleName1+".json")) lamda = setting0.power_transform delta_t = setting0.delta_t dim = setting0.dim layers = setting0.layers + Xmu0 = torch.tensor(setting0.Xmu).unsqueeze(0).to(device) Xstd0 = torch.tensor(setting0.Xstd).unsqueeze(0).to(device=device) @@ -116,22 +119,33 @@ def forward(self, x): model0 = Net() model1 = Net() model2 = Net() - check_point0 = torch.load(str("pytorchDNN/"+moduleName1+".pt")) - check_point1 = torch.load(str("pytorchDNN/"+moduleName2+".pt")) - check_point2 = torch.load(str("pytorchDNN/"+moduleName3+".pt")) + + if torch.cuda.is_available()==False: + check_point0 = torch.load(str("pytorchDNN/"+moduleName1+".pt"), map_location='cpu') + check_point1 = torch.load(str("pytorchDNN/"+moduleName2+".pt"), map_location='cpu') + check_point2 = torch.load(str("pytorchDNN/"+moduleName3+".pt"), map_location='cpu') + else: + check_point0 = torch.load(str("pytorchDNN/"+moduleName1+".pt")) + check_point1 = torch.load(str("pytorchDNN/"+moduleName2+".pt")) + check_point2 = torch.load(str("pytorchDNN/"+moduleName3+".pt")) + model0.load_state_dict(check_point0) model1.load_state_dict(check_point1) model2.load_state_dict(check_point2) model0.to(device=device) model1.to(device=device) model2.to(device=device) + if len(device_ids) > 1: model0 = torch.nn.DataParallel(model0, device_ids=device_ids) model1 = torch.nn.DataParallel(model1, device_ids=device_ids) model2 = torch.nn.DataParallel(model2, device_ids=device_ids) except Exception as e: print(e.args) - +# print("check_point0") +# print(check_point0) +# print("fc.0.weight") +# print(model0.state_dict()['fc.0.weight']) def inference(vec0, vec1, vec2): ''' @@ -159,7 +173,8 @@ def inference(vec0, vec1, vec2): input0_normalized = (input0_bct - Xmu0) / Xstd0 # input0_normalized[:, -1] = 0 #set Y_AR to 0 input0_normalized = input0_normalized.float() - + #print("input0_normalized") + #print(input0_normalized[0]) rho1 = input1_[:, 0].unsqueeze(1) input1_Y = input1_[:, 3:].clone() input1_bct = input1_[:, 1:] @@ -181,8 +196,13 @@ def inference(vec0, vec1, vec2): output0_normalized = model0(input0_normalized) output1_normalized = model1(input1_normalized) output2_normalized = model2(input2_normalized) + #print("output0_normalized") + #print(output0_normalized[0]) + # for name in model0.state_dict(): + # print(name) - + # print("fc.0.weight") + # print(model0.state_dict()['fc.0.weight']) # post_processing output0_bct = (output0_normalized * Ystd0 + Ymu0) * delta_t + input0_bct output0_Y = (lamda * output0_bct[:, 2:] + 1)**(1 / lamda)