Merge branch 'master' of github.com:JamesEMcClure/LBPM-WIA
This commit is contained in:
commit
0a4f7d843d
20
docs/Makefile
Normal file
20
docs/Makefile
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Minimal makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line, and also
|
||||||
|
# from the environment for the first two.
|
||||||
|
SPHINXOPTS ?=
|
||||||
|
SPHINXBUILD ?= sphinx-build
|
||||||
|
SOURCEDIR = source
|
||||||
|
BUILDDIR = $(HOME)/local/doc/build
|
||||||
|
|
||||||
|
# Put it first so that "make" without argument is like "make help".
|
||||||
|
help:
|
||||||
|
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
|
||||||
|
.PHONY: help Makefile
|
||||||
|
|
||||||
|
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||||
|
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||||
|
%: Makefile
|
||||||
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
19
docs/README.md
Normal file
19
docs/README.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Dependencies for LBPM documentation
|
||||||
|
|
||||||
|
# install sphinx
|
||||||
|
pip install Sphinx
|
||||||
|
|
||||||
|
# foamatting requires sphinx read-the-docs-theme
|
||||||
|
pip install sphinx-rtd-theme
|
||||||
|
|
||||||
|
# equation rendering requires latex and dvipng command
|
||||||
|
sudo apt-get install dvipng
|
||||||
|
sudo apt-get install texlive texstudio
|
||||||
|
sudo apt-get install texlive-latex-recommended texlive-pictures texlive-latex-extra
|
||||||
|
|
||||||
|
|
||||||
|
# To build the docs
|
||||||
|
Step 1) install dependencies listed above
|
||||||
|
Step 2) type 'make html' from the docs/ directory
|
||||||
|
Step 3) point your browser at ~/local/doc/build/html/index.html
|
||||||
|
#
|
70
docs/source/conf.py
Normal file
70
docs/source/conf.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# Configuration file for the Sphinx documentation builder.
|
||||||
|
#
|
||||||
|
# This file only contains a selection of the most common options. For a full
|
||||||
|
# list see the documentation:
|
||||||
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||||
|
|
||||||
|
# -- Path setup --------------------------------------------------------------
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
#
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
# sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
|
|
||||||
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
|
project = 'LBPM'
|
||||||
|
copyright = '2021, James E McClure'
|
||||||
|
author = 'James E McClure'
|
||||||
|
|
||||||
|
# The full version, including alpha/beta/rc tags
|
||||||
|
release = '1.0'
|
||||||
|
|
||||||
|
|
||||||
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
|
# ones.
|
||||||
|
extensions = [
|
||||||
|
'sphinx.ext.imgmath'
|
||||||
|
]
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ['_templates']
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
# This pattern also affects html_static_path and html_extra_path.
|
||||||
|
exclude_patterns = []
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
#
|
||||||
|
html_theme = 'alabaster'
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ['_static']
|
||||||
|
|
||||||
|
|
||||||
|
## Read the docs style:
|
||||||
|
if os.environ.get('READTHEDOCS') != 'True':
|
||||||
|
try:
|
||||||
|
import sphinx_rtd_theme
|
||||||
|
except ImportError:
|
||||||
|
pass # assume we have sphinx >= 1.3
|
||||||
|
else:
|
||||||
|
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||||
|
html_theme = 'sphinx_rtd_theme'
|
||||||
|
|
||||||
|
#def setup(app):
|
||||||
|
# app.add_stylesheet("fix_rtd.css")
|
20
docs/source/developerGuide/buildingModels/overview.rst
Normal file
20
docs/source/developerGuide/buildingModels/overview.rst
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
===========================
|
||||||
|
Implementing a new LB model
|
||||||
|
===========================
|
||||||
|
|
||||||
|
While LBPM includes a range of fully-functioning lattice Boltzmann models, the commonly used
|
||||||
|
Bhatnager-Gross-Krook (BGK) model has been deliberately excluded. While the physical limitations
|
||||||
|
of this model are well-known, implementing the BGK model is an excellent way to understand
|
||||||
|
how to implement new LB models within the more general framework of LBPM. In this excercise
|
||||||
|
you will
|
||||||
|
|
||||||
|
* learn "what goes where"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
* don't modify core data structures (unless you have a really good reason)
|
||||||
|
|
||||||
|
* re-use existing components whenever possible
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
|||||||
|
===============
|
||||||
|
Data Structures
|
||||||
|
===============
|
||||||
|
|
||||||
|
LBPM includes a variety of generalized data structures to facilitate the implementation
|
||||||
|
of different lattice Boltzmann models.
|
18
docs/source/developerGuide/index.rst
Normal file
18
docs/source/developerGuide/index.rst
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
###############################################################################
|
||||||
|
Developer guide
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
The LBPM developer guide provides essential information on how to add new physics
|
||||||
|
into the framework.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:glob:
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
designOverview/*
|
||||||
|
|
||||||
|
buildingModels/*
|
||||||
|
|
||||||
|
testingModels/*
|
||||||
|
|
||||||
|
|
9
docs/source/developerGuide/testingModels/unitTests.rst
Normal file
9
docs/source/developerGuide/testingModels/unitTests.rst
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
=================
|
||||||
|
Adding unit tests
|
||||||
|
=================
|
||||||
|
|
||||||
|
Unit tests in LBPM are implemented using ctest
|
||||||
|
|
||||||
|
* general overview
|
||||||
|
|
||||||
|
* launching unit tests for GPU (MPI flags etc.)
|
9
docs/source/examples/running.rst
Normal file
9
docs/source/examples/running.rst
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
============
|
||||||
|
Running LBPM
|
||||||
|
============
|
||||||
|
|
||||||
|
There are two main components to running LBPM simulators.
|
||||||
|
First is understanding how to launch MPI tasks on your system,
|
||||||
|
which depends on the particular implementation of MPI that you are using,
|
||||||
|
as well as other details of the local configuration. The second component is
|
||||||
|
understanding the LBPM input file structure.
|
25
docs/source/index.rst
Normal file
25
docs/source/index.rst
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
.. LBPM documentation master file, created by
|
||||||
|
sphinx-quickstart on Thu May 20 12:19:14 2021.
|
||||||
|
You can adapt this file completely to your liking, but it should at least
|
||||||
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
|
LBPM -- Documentation
|
||||||
|
===================================================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:glob:
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: Contents:
|
||||||
|
|
||||||
|
install
|
||||||
|
examples/*
|
||||||
|
userGuide/*
|
||||||
|
developerGuide/*
|
||||||
|
publications/*
|
||||||
|
|
||||||
|
Indices and tables
|
||||||
|
==================
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`modindex`
|
||||||
|
* :ref:`search`
|
10
docs/source/install.rst
Normal file
10
docs/source/install.rst
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
============
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
LBPM requires CMake, MPI and HDF5 as required dependencies.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
ls $LBPM_SOURCE/sample_scripts
|
||||||
|
|
13
docs/source/publications/publications.rst
Normal file
13
docs/source/publications/publications.rst
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
============
|
||||||
|
Publications
|
||||||
|
============
|
||||||
|
|
||||||
|
* James E McClure, Zhe Li, Mark Berrill, Thomas Ramstad, "The LBPM software package for simulating multiphase flow on digital images of porous rocks" Computational Geosciences (25) 871–895 (2021) https://doi.org/10.1007/s10596-020-10028-9
|
||||||
|
|
||||||
|
|
||||||
|
* James E. McClure, Zhe Li, Adrian P. Sheppard, Cass T. Miller, "An adaptive volumetric flux boundary condition for lattice Boltzmann methods" Computers & Fluids (210) (2020) https://doi.org/10.1016/j.compfluid.2020.104670
|
||||||
|
|
||||||
|
|
||||||
|
* Y.D. Wang, T. Chung, R.T. Armstrong, J. McClure, T. Ramstad, P. Mostaghimi, "Accelerated Computation of Relative Permeability by Coupled Morphological and Direct Multiphase Flow Simulation" Journal of Computational Physics (401) (2020) https://doi.org/10.1016/j.jcp.2019.108966
|
||||||
|
|
||||||
|
|
13
docs/source/userGuide/IO/fileformat.rst
Normal file
13
docs/source/userGuide/IO/fileformat.rst
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
========================
|
||||||
|
I/O conventions for LBPM
|
||||||
|
========================
|
||||||
|
|
||||||
|
There are three main kinds of output file that are supported by LBPM.
|
||||||
|
|
||||||
|
|
||||||
|
* CSV files --
|
||||||
|
|
||||||
|
* formatted binary files --
|
||||||
|
|
||||||
|
* unformatted binary files --
|
||||||
|
|
5
docs/source/userGuide/analysis/analysis.rst
Normal file
5
docs/source/userGuide/analysis/analysis.rst
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
===========================
|
||||||
|
Internal Analysis Framework
|
||||||
|
===========================
|
||||||
|
|
||||||
|
placeholder for analysis
|
17
docs/source/userGuide/index.rst
Normal file
17
docs/source/userGuide/index.rst
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
###############################################################################
|
||||||
|
User Guide
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
Welcome to the LBPM user guide.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:glob:
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
models/*
|
||||||
|
|
||||||
|
analysis/*
|
||||||
|
|
||||||
|
visualization/*
|
||||||
|
|
||||||
|
IO/*
|
@ -0,0 +1,6 @@
|
|||||||
|
=============================================
|
||||||
|
Poisson-Boltzmann model
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
The LBPM Poisson-Boltzmann solver is designed to solve the Poisson-Boltzmann equation
|
||||||
|
to solve for the electric field in an ionic fluid.
|
91
docs/source/userGuide/models/color/index.rst
Normal file
91
docs/source/userGuide/models/color/index.rst
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
###############################################################################
|
||||||
|
Color model
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
The LBPM color model is implemented by combining a multi-relaxation time D3Q19
|
||||||
|
lattice Boltzmann equation (LBE) to solve for the momentum transport with two D3Q7
|
||||||
|
LBEs for the mass transport. The color model will obey strict mass and momentum
|
||||||
|
conservation while minimizing diffusive fluxes across the interface between fluids.
|
||||||
|
The color model is a good choice for modeling dense fluids that are strongly immiscible
|
||||||
|
(e.g. water-oil systems). Due to the strong anti-diffusion in the interface region,
|
||||||
|
the color model is not suitable for modeling processes such as Ostwald ripening that
|
||||||
|
depend on diffusive fluxes between fluid phases.
|
||||||
|
|
||||||
|
A typical command to launch the LBPM color simulator is as follows
|
||||||
|
|
||||||
|
```
|
||||||
|
mpirun -np $NUMPROCS lbpm_color_simulator input.db
|
||||||
|
```
|
||||||
|
|
||||||
|
where ``$NUMPROCS`` is the number of MPI processors to be used and ``input.db`` is
|
||||||
|
the name of the input database that provides the simulation parameters.
|
||||||
|
Note that the specific syntax to launch MPI tasks may vary depending on your system.
|
||||||
|
For additional details please refer to your local system documentation.
|
||||||
|
|
||||||
|
****************************
|
||||||
|
Simulation protocols
|
||||||
|
****************************
|
||||||
|
|
||||||
|
Simulation protocols are designed to make it simpler to design and execute common
|
||||||
|
computational experiments. Protocols will automatically determine boundary conditions
|
||||||
|
needed to perform a particular simulation. LBPM will internall set default simulation paramaters
|
||||||
|
that can be over-ridden to develop customized simulations.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:glob:
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
protocols/*
|
||||||
|
|
||||||
|
|
||||||
|
***************************
|
||||||
|
Model parameters
|
||||||
|
***************************
|
||||||
|
|
||||||
|
The essential model parameters for the color model are
|
||||||
|
|
||||||
|
- :math:`\alpha` -- control the interfacial tension between fluids with key ``alpha``
|
||||||
|
- :math:`\beta` -- control the width of the interface with key ``beta``
|
||||||
|
- :math:`\tau_A` -- control the viscosity of fluid A with key ``tauA``
|
||||||
|
- :math:`\tau_B` -- control the viscosity of fluid B with key ``tauB``
|
||||||
|
|
||||||
|
****************************
|
||||||
|
Model Formulation
|
||||||
|
****************************
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
****************************
|
||||||
|
Boundary Conditions
|
||||||
|
****************************
|
||||||
|
|
||||||
|
The following external boundary conditions are supported by ``lbpm_color_simulator``
|
||||||
|
and can be set by setting the ``BC`` key values in the ``Domain`` section of the
|
||||||
|
input file database
|
||||||
|
|
||||||
|
- ``BC = 0`` -- fully periodic boundary conditions
|
||||||
|
- ``BC = 3`` -- constant pressure boundary condition
|
||||||
|
- ``BC = 4`` -- constant volumetric flux boundary condition
|
||||||
|
|
||||||
|
For ``BC = 0`` any mass that exits on one side of the domain will re-enter at the other
|
||||||
|
side. If the pore-structure for the image is tight, the mismatch between the inlet and
|
||||||
|
outlet can artificially reduce the permeability of the sample due to the blockage of
|
||||||
|
flow pathways at the boundary. LBPM includes an internal utility that will reduce the impact
|
||||||
|
of the boundary mismatch by eroding the solid labels within the inlet and outlet layers
|
||||||
|
(https://doi.org/10.1007/s10596-020-10028-9) to create a mixing layer.
|
||||||
|
The number mixing layers to use can be set using the key values in the ``Domain`` section
|
||||||
|
of the input database
|
||||||
|
|
||||||
|
- ``InletLayers = 5`` -- set the number of mixing layers to ``5`` voxels at the inlet
|
||||||
|
- ``OUtletLayers = 5`` -- set the number of mixing layers to ``5`` voxels at the outlet
|
||||||
|
|
||||||
|
For the other boundary conditions a thin reservoir of fluid (default ``3`` voxels)
|
||||||
|
is established at either side of the domain. The inlet is defined as the boundary face
|
||||||
|
where ``z = 0`` and the outlet is the boundary face where ``z = nprocz*nz``. By default a
|
||||||
|
reservoir of fluid A is established at the inlet and a reservoir of fluid B is established at
|
||||||
|
the outlet, each with a default thickness of three voxels. To over-ride the default label at
|
||||||
|
the inlet or outlet, the ``Domain`` section of the database may specify the following key values
|
||||||
|
|
||||||
|
- ``InletLayerPhase = 2`` -- establish a reservoir of component B at the inlet
|
||||||
|
- ``OutletLayerPhase = 1`` -- establish a reservoir of component A at the outlet
|
||||||
|
|
12
docs/source/userGuide/models/color/protocols/centrifuge.rst
Normal file
12
docs/source/userGuide/models/color/protocols/centrifuge.rst
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
======================================
|
||||||
|
Color model -- Centrifuge Protocol
|
||||||
|
======================================
|
||||||
|
|
||||||
|
The centrifuge protocol is designed to mimic SCAL centrifuge experiments that
|
||||||
|
are used to infer the capillary pressure. The centrifuge protocol
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
image_sequence = "image1.raw", "image2.raw"
|
||||||
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
|||||||
|
======================================
|
||||||
|
Color model -- Core Flooding
|
||||||
|
======================================
|
||||||
|
|
||||||
|
The core flooding protocol is designed to mimic SCAL experiments where one
|
||||||
|
immiscible fluid is injected into the sample at a constant rate, displacing the
|
||||||
|
other fluid. The core flooding protocol relies on a flux boundary condition
|
||||||
|
to ensure that fluid is injected into the sample at a constant rate. The flux
|
||||||
|
boundary condition implements a time-varying pressure boundary condition that
|
||||||
|
adapts to ensure a constant volumetric flux. Details for the flux boundary
|
||||||
|
condition are available
|
||||||
|
(see: https://doi.org/10.1016/j.compfluid.2020.104670)
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
protocol = "core flooding"
|
||||||
|
|
||||||
|
|
||||||
|
To match experimental conditions, it is usually important to match the capillary
|
||||||
|
number, which is
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
\mbox{Ca} = \frac{\mu u_z}{\gamma}
|
||||||
|
|
||||||
|
|
||||||
|
where :math:`\mu` is the dynamic viscosity, :math:`u_z` is the fluid
|
||||||
|
(usually water) velocity and :math:`\gamma` is the interfacial tension.
|
||||||
|
The volumetric flow rate is related to the fluid velocity based on
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
Q_z = \epsilon C_{xy} u_z
|
||||||
|
|
||||||
|
where :math:`C_{xy}` is the cross-sectional area and :math:`\epsilon`
|
||||||
|
is the porosity. Given a particular experimental system
|
||||||
|
self-similar conditions can be determined for the lattice Boltzmann
|
||||||
|
simulation by matching the non-dimensional :math:`mbox{Ca}`. It is nearly
|
||||||
|
awlays advantageous for the timestep to be as large as possible so
|
||||||
|
that time-to-solution will be more favorable. This is accomplished by
|
||||||
|
|
||||||
|
* use a high value for the numerical surface tension (e.g. ``alpha=1.0e-2``)
|
||||||
|
* use a small value for the fluid viscosity (e.g. ``tau_w = 0.7`` and ``tau_n = 0.7`` )
|
||||||
|
* determine the volumetric flow rate needed to match :math:`\mbox{Ca}`
|
||||||
|
|
||||||
|
For the color LBM the interfacial tension is
|
||||||
|
:math:`\gamma = 6 \alpha` and the dynamic viscosity is :math:`\mu = \rho(\tau-1/2)/3`,
|
||||||
|
where the units are relative to the lattice spacing, timestep and mass
|
||||||
|
density. Agreemetn between the experimental and simulated values for
|
||||||
|
:math:`\mbox{Ca}` is ensured by setting the volumetric flux
|
||||||
|
|
||||||
|
.. math::
|
||||||
|
Q_z = \frac{\epsilon C_{xy} \gamma }{\mu} \mbox{Ca}
|
||||||
|
|
||||||
|
where the LB units of the volumetric flux will be voxels per timestep.
|
||||||
|
|
||||||
|
In some situations it may also be important to match other non-dimensional numbers,
|
||||||
|
such as the viscosity ratio, density ratio, and/or Ohnesorge/Laplace number. This
|
||||||
|
can be accomplished with an analogous procedure. Enforcing additional constraints
|
||||||
|
will necessarily restrict the LB parameters that can be used, which are ultimately
|
||||||
|
manifested as a constraint on the size of a timestep.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
|||||||
|
==========================================
|
||||||
|
Color model -- Fractional Flow Protocol
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
The fractional flow protocol is designed to perform steady-state relative
|
||||||
|
permeability simulations by using an internal routine to change the fluid
|
||||||
|
saturation by adding and subtracting mass to the fluid phases. The
|
||||||
|
mass density is updated for each fluid based on the locations where
|
||||||
|
the local rate of flow is high.
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
protocol = "fractional flow"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
|||||||
|
======================================
|
||||||
|
Color model -- Image Sequence Protocol
|
||||||
|
======================================
|
||||||
|
|
||||||
|
The image sequence protocol is designed to perform a set steady-state
|
||||||
|
simulations based on a sequence of 3D (8-bit) images provided by the user.
|
||||||
|
The images might be the output of a previous LBPM simulation, a sequence of
|
||||||
|
(segmented) experimental data, or data generated from a custom routine.
|
||||||
|
The image sequence protocol will apply the same set of flow conditions
|
||||||
|
to all images in the sequence. This means
|
||||||
|
|
||||||
|
* the image labels and any associated properties are the same
|
||||||
|
* the external boundary conditions are the same
|
||||||
|
* the physical simulation parameters are the same
|
||||||
|
|
||||||
|
The image sequence protocol does not set boundary conditions by default.
|
||||||
|
It is up to the user to determine the flow condition, with the understanding
|
||||||
|
that the same set of will be applied to each image in the sequence.
|
||||||
|
|
||||||
|
To enable the image sequence protocol, the following keys should be set
|
||||||
|
within the ``Color`` section of the input database
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
protocol = "image sequence"
|
||||||
|
image_sequence = "image1.raw", "image2.raw"
|
||||||
|
|
@ -0,0 +1,18 @@
|
|||||||
|
==========================================
|
||||||
|
Color model -- Shell Aggregation Protocol
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
The shell aggregation protocol is designed to perform steady-state relative
|
||||||
|
permeability simulations by using an internal routine to change the fluid
|
||||||
|
saturation by moving the interface. The basic design for the shell aggregation
|
||||||
|
protocol is described by Wang et al. ( https://doi.org/10.1016/j.jcp.2019.108966 ).
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
|
||||||
|
protocol = "shell aggregation"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
6
docs/source/userGuide/models/freeEnergy/freeEnergy.rst
Normal file
6
docs/source/userGuide/models/freeEnergy/freeEnergy.rst
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
=============================================
|
||||||
|
Free energy model
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
The LBPM free energy model is constructed to solve the Allen-Cahn equations,
|
||||||
|
which are typically used to describe liquid-gas systems.
|
7
docs/source/userGuide/models/greyscale/greyscale.rst
Normal file
7
docs/source/userGuide/models/greyscale/greyscale.rst
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
=============================================
|
||||||
|
Greyscale model model
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
The LBPM greyscale lattice Boltzmann model is constructed to approximate the
|
||||||
|
solution of the Darcy-Brinkman equations in grey regions, coupled to a Navier-Stokes
|
||||||
|
solution in open regions.
|
23
docs/source/userGuide/models/index.rst
Normal file
23
docs/source/userGuide/models/index.rst
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
###############################################################################
|
||||||
|
LBPM model summary
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
Currently supported lattice Boltzmann models
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:glob:
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
color/*
|
||||||
|
|
||||||
|
mrt/*
|
||||||
|
|
||||||
|
nernstPlanck/*
|
||||||
|
|
||||||
|
PoissonBoltzmann/*
|
||||||
|
|
||||||
|
greyscale/*
|
||||||
|
|
||||||
|
freeEnergy/*
|
||||||
|
|
||||||
|
|
6
docs/source/userGuide/models/mrt/mrt.rst
Normal file
6
docs/source/userGuide/models/mrt/mrt.rst
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
=============================================
|
||||||
|
MRT model
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
The multi-relaxation time (MRT) lattice Boltzmann model is constructed to approximate the
|
||||||
|
solution of the Navier-Stokes equations.
|
@ -0,0 +1,6 @@
|
|||||||
|
=============================================
|
||||||
|
Nernst-Planck model
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
The Nernst-Planck model is designed to model ion transport based on the
|
||||||
|
Nernst-Planck equation.
|
5
docs/source/userGuide/visualization/visit.rst
Normal file
5
docs/source/userGuide/visualization/visit.rst
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
======================================
|
||||||
|
Visualizing simulation data with visit
|
||||||
|
======================================
|
||||||
|
|
||||||
|
placeholder for visit
|
@ -2006,179 +2006,188 @@ FlowAdaptor::~FlowAdaptor(){
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double FlowAdaptor::ImageInit(ScaLBL_ColorModel &M, std::string Filename){
|
||||||
|
int rank = M.rank;
|
||||||
|
int Nx = M.Nx; int Ny = M.Ny; int Nz = M.Nz;
|
||||||
|
if (rank==0) printf("Re-initializing fluids from file: %s \n", Filename.c_str());
|
||||||
|
M.Mask->Decomp(Filename);
|
||||||
|
for (int i=0; i<Nx*Ny*Nz; i++) M.id[i] = M.Mask->id[i]; // save what was read
|
||||||
|
for (int i=0; i<Nx*Ny*Nz; i++) M.Dm->id[i] = M.Mask->id[i]; // save what was read
|
||||||
|
|
||||||
|
double *PhaseLabel;
|
||||||
|
PhaseLabel = new double[Nx*Ny*Nz];
|
||||||
|
M.AssignComponentLabels(PhaseLabel);
|
||||||
|
|
||||||
|
double Count = 0.0;
|
||||||
|
double PoreCount = 0.0;
|
||||||
|
for (int k=1; k<Nz-1; k++){
|
||||||
|
for (int j=1; j<Ny-1; j++){
|
||||||
|
for (int i=1; i<Nx-1; i++){
|
||||||
|
if (M.id[Nx*Ny*k+Nx*j+i] == 2){
|
||||||
|
PoreCount++;
|
||||||
|
Count++;
|
||||||
|
}
|
||||||
|
else if (M.id[Nx*Ny*k+Nx*j+i] == 1){
|
||||||
|
PoreCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Count=M.Dm->Comm.sumReduce( Count);
|
||||||
|
PoreCount=M.Dm->Comm.sumReduce( PoreCount);
|
||||||
|
|
||||||
|
if (rank==0) printf(" new saturation: %f (%f / %f) \n", Count / PoreCount, Count, PoreCount);
|
||||||
|
ScaLBL_CopyToDevice(M.Phi, PhaseLabel, Nx*Ny*Nz*sizeof(double));
|
||||||
|
M.Dm->Comm.barrier();
|
||||||
|
|
||||||
|
ScaLBL_D3Q19_Init(M.fq, M.Np);
|
||||||
|
ScaLBL_PhaseField_Init(M.dvcMap, M.Phi, M.Den, M.Aq, M.Bq, 0, M.ScaLBL_Comm->LastExterior(), M.Np);
|
||||||
|
ScaLBL_PhaseField_Init(M.dvcMap, M.Phi, M.Den, M.Aq, M.Bq, M.ScaLBL_Comm->FirstInterior(), M.ScaLBL_Comm->LastInterior(), M.Np);
|
||||||
|
M.Dm->Comm.barrier();
|
||||||
|
|
||||||
|
ScaLBL_CopyToHost(M.Averages->Phi.data(),M.Phi,Nx*Ny*Nz*sizeof(double));
|
||||||
|
|
||||||
|
double saturation = Count/PoreCount;
|
||||||
|
return saturation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
double FlowAdaptor::UpdateFractionalFlow(ScaLBL_ColorModel &M){
|
double FlowAdaptor::UpdateFractionalFlow(ScaLBL_ColorModel &M){
|
||||||
|
|
||||||
double MASS_FRACTION_CHANGE = 0.0005;
|
double MASS_FRACTION_CHANGE = 0.0005;
|
||||||
if (M.db->keyExists( "FlowAdaptor" )){
|
if (M.db->keyExists( "FlowAdaptor" )){
|
||||||
auto flow_db = M.db->getDatabase( "FlowAdaptor" );
|
auto flow_db = M.db->getDatabase( "FlowAdaptor" );
|
||||||
MASS_FRACTION_CHANGE = flow_db->getWithDefault<double>( "mass_fraction_factor", 0.0005);
|
MASS_FRACTION_CHANGE = flow_db->getWithDefault<double>( "mass_fraction_factor", 0.0005);
|
||||||
}
|
}
|
||||||
int Np = M.Np;
|
int Np = M.Np;
|
||||||
double dA, dB, phi;
|
double dA, dB, phi;
|
||||||
double vx,vy,vz;
|
double vx,vy,vz;
|
||||||
double vax,vay,vaz;
|
double vax,vay,vaz;
|
||||||
double vbx,vby,vbz;
|
double vbx,vby,vbz;
|
||||||
double vax_global,vay_global,vaz_global;
|
double vax_global,vay_global,vaz_global;
|
||||||
double vbx_global,vby_global,vbz_global;
|
double vbx_global,vby_global,vbz_global;
|
||||||
|
|
||||||
double mass_a, mass_b, mass_a_global, mass_b_global;
|
double mass_a, mass_b, mass_a_global, mass_b_global;
|
||||||
|
|
||||||
double *Aq_tmp, *Bq_tmp;
|
double *Aq_tmp, *Bq_tmp;
|
||||||
double *Vel_x, *Vel_y, *Vel_z, *Phase;
|
double *Vel_x, *Vel_y, *Vel_z, *Phase;
|
||||||
|
|
||||||
Aq_tmp = new double [7*Np];
|
Aq_tmp = new double [7*Np];
|
||||||
Bq_tmp = new double [7*Np];
|
Bq_tmp = new double [7*Np];
|
||||||
Phase = new double [Np];
|
Phase = new double [Np];
|
||||||
Vel_x = new double [Np];
|
Vel_x = new double [Np];
|
||||||
Vel_y = new double [Np];
|
Vel_y = new double [Np];
|
||||||
Vel_z = new double [Np];
|
Vel_z = new double [Np];
|
||||||
|
|
||||||
ScaLBL_CopyToHost(Aq_tmp, M.Aq, 7*Np*sizeof(double));
|
ScaLBL_CopyToHost(Aq_tmp, M.Aq, 7*Np*sizeof(double));
|
||||||
ScaLBL_CopyToHost(Bq_tmp, M.Bq, 7*Np*sizeof(double));
|
ScaLBL_CopyToHost(Bq_tmp, M.Bq, 7*Np*sizeof(double));
|
||||||
ScaLBL_CopyToHost(Vel_x, &M.Velocity[0], Np*sizeof(double));
|
ScaLBL_CopyToHost(Vel_x, &M.Velocity[0], Np*sizeof(double));
|
||||||
ScaLBL_CopyToHost(Vel_y, &M.Velocity[Np], Np*sizeof(double));
|
ScaLBL_CopyToHost(Vel_y, &M.Velocity[Np], Np*sizeof(double));
|
||||||
ScaLBL_CopyToHost(Vel_z, &M.Velocity[2*Np], Np*sizeof(double));
|
ScaLBL_CopyToHost(Vel_z, &M.Velocity[2*Np], Np*sizeof(double));
|
||||||
|
|
||||||
/* DEBUG STRUCTURES */
|
/* DEBUG STRUCTURES */
|
||||||
int Nx = M.Nx; int Ny = M.Ny; int Nz = M.Nz;
|
int Nx = M.Nx; int Ny = M.Ny; int Nz = M.Nz;
|
||||||
int N = Nx*Ny*Nz;
|
//int N = Nx*Ny*Nz;
|
||||||
double * DebugMassA, *DebugMassB;
|
//double * DebugMassA, *DebugMassB;
|
||||||
DebugMassA = new double[Np];
|
//DebugMassA = new double[Np];
|
||||||
DebugMassB = new double[Np];
|
//DebugMassB = new double[Np];
|
||||||
|
|
||||||
/* compute the total momentum */
|
/* compute the total momentum */
|
||||||
vax = vay = vaz = 0.0;
|
vax = vay = vaz = 0.0;
|
||||||
vbx = vby = vbz = 0.0;
|
vbx = vby = vbz = 0.0;
|
||||||
mass_a = mass_b = 0.0;
|
mass_a = mass_b = 0.0;
|
||||||
|
double maxSpeed = 0.0;
|
||||||
|
double localMaxSpeed = 0.0;
|
||||||
|
for (int k=1; k<Nz-1; k++){
|
||||||
|
for (int j=1; j<Ny-1; j++){
|
||||||
|
for (int i=1; i<Nx-1; i++){
|
||||||
|
int n=M.Map(i,j,k);
|
||||||
|
double distance = M.Averages->SDs(i,j,k);
|
||||||
|
if (!(n<0) ){
|
||||||
|
dA = Aq_tmp[n] + Aq_tmp[n+Np] + Aq_tmp[n+2*Np] + Aq_tmp[n+3*Np] + Aq_tmp[n+4*Np] + Aq_tmp[n+5*Np] + Aq_tmp[n+6*Np];
|
||||||
|
dB = Bq_tmp[n] + Bq_tmp[n+Np] + Bq_tmp[n+2*Np] + Bq_tmp[n+3*Np] + Bq_tmp[n+4*Np] + Bq_tmp[n+5*Np] + Bq_tmp[n+6*Np];
|
||||||
|
phi = (dA - dB) / (dA + dB);
|
||||||
|
Phase[n] = phi;
|
||||||
|
mass_a += dA;
|
||||||
|
mass_b += dB;
|
||||||
|
if (phi > 0.0){
|
||||||
|
vax += Vel_x[n];
|
||||||
|
vay += Vel_y[n];
|
||||||
|
vaz += Vel_z[n];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vbx += Vel_x[n];
|
||||||
|
vby += Vel_y[n];
|
||||||
|
vbz += Vel_z[n];
|
||||||
|
}
|
||||||
|
double speed = sqrt(vax*vax + vay*vay + vaz*vaz + vbx*vbx + vby*vby + vbz*vbz);
|
||||||
|
if (distance > 3.0 && speed > localMaxSpeed){
|
||||||
|
localMaxSpeed = speed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
maxSpeed = M.Dm->Comm.maxReduce(localMaxSpeed);
|
||||||
|
mass_a_global = M.Dm->Comm.sumReduce(mass_a);
|
||||||
|
mass_b_global = M.Dm->Comm.sumReduce(mass_b);
|
||||||
|
vax_global = M.Dm->Comm.sumReduce(vax);
|
||||||
|
vay_global = M.Dm->Comm.sumReduce(vay);
|
||||||
|
vaz_global = M.Dm->Comm.sumReduce(vaz);
|
||||||
|
vbx_global = M.Dm->Comm.sumReduce(vbx);
|
||||||
|
vby_global = M.Dm->Comm.sumReduce(vby);
|
||||||
|
vbz_global = M.Dm->Comm.sumReduce(vbz);
|
||||||
|
|
||||||
double maxSpeed = 0.0;
|
double total_momentum_A = sqrt(vax_global*vax_global+vay_global*vay_global+vaz_global*vaz_global);
|
||||||
double localMaxSpeed = 0.0;
|
double total_momentum_B = sqrt(vbx_global*vbx_global+vby_global*vby_global+vbz_global*vbz_global);
|
||||||
for (int k=1; k<Nz-1; k++){
|
/* compute the total mass change */
|
||||||
for (int j=1; j<Ny-1; j++){
|
double TOTAL_MASS_CHANGE = MASS_FRACTION_CHANGE*(mass_a_global + mass_b_global);
|
||||||
for (int i=1; i<Nx-1; i++){
|
if (fabs(TOTAL_MASS_CHANGE) > 0.1*mass_a_global )
|
||||||
int n=M.Map(i,j,k);
|
TOTAL_MASS_CHANGE = 0.1*mass_a_global;
|
||||||
double distance = M.Averages->SDs(i,j,k);
|
if (fabs(TOTAL_MASS_CHANGE) > 0.1*mass_b_global )
|
||||||
if (!(n<0) ){
|
TOTAL_MASS_CHANGE = 0.1*mass_b_global;
|
||||||
dA = Aq_tmp[n] + Aq_tmp[n+Np] + Aq_tmp[n+2*Np] + Aq_tmp[n+3*Np] + Aq_tmp[n+4*Np] + Aq_tmp[n+5*Np] + Aq_tmp[n+6*Np];
|
|
||||||
dB = Bq_tmp[n] + Bq_tmp[n+Np] + Bq_tmp[n+2*Np] + Bq_tmp[n+3*Np] + Bq_tmp[n+4*Np] + Bq_tmp[n+5*Np] + Bq_tmp[n+6*Np];
|
|
||||||
phi = (dA - dB) / (dA + dB);
|
|
||||||
Phase[n] = phi;
|
|
||||||
mass_a += dA;
|
|
||||||
mass_b += dB;
|
|
||||||
if (phi > 0.0){
|
|
||||||
vax += Vel_x[n];
|
|
||||||
vay += Vel_y[n];
|
|
||||||
vaz += Vel_z[n];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
vbx += Vel_x[n];
|
|
||||||
vby += Vel_y[n];
|
|
||||||
vbz += Vel_z[n];
|
|
||||||
}
|
|
||||||
double speed = sqrt(vax*vax + vay*vay + vaz*vaz + vbx*vbx + vby*vby + vbz*vbz);
|
|
||||||
if (distance > 3.0 && speed > localMaxSpeed){
|
|
||||||
localMaxSpeed = speed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
maxSpeed = M.Dm->Comm.maxReduce(localMaxSpeed);
|
|
||||||
/* for (int n=0; n < M.ScaLBL_Comm->LastExterior(); n++){
|
|
||||||
dA = Aq_tmp[n] + Aq_tmp[n+Np] + Aq_tmp[n+2*Np] + Aq_tmp[n+3*Np] + Aq_tmp[n+4*Np] + Aq_tmp[n+5*Np] + Aq_tmp[n+6*Np];
|
|
||||||
dB = Bq_tmp[n] + Bq_tmp[n+Np] + Bq_tmp[n+2*Np] + Bq_tmp[n+3*Np] + Bq_tmp[n+4*Np] + Bq_tmp[n+5*Np] + Bq_tmp[n+6*Np];
|
|
||||||
phi = (dA - dB) / (dA + dB);
|
|
||||||
Phase[n] = phi;
|
|
||||||
mass_a += dA;
|
|
||||||
mass_b += dB;
|
|
||||||
if (phi > 0.0){
|
|
||||||
vax += Vel_x[n];
|
|
||||||
vay += Vel_y[n];
|
|
||||||
vaz += Vel_z[n];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
vbx += Vel_x[n];
|
|
||||||
vby += Vel_y[n];
|
|
||||||
vbz += Vel_z[n];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int n=M.ScaLBL_Comm->FirstInterior(); n < M.ScaLBL_Comm->LastInterior(); n++){
|
|
||||||
dA = Aq_tmp[n] + Aq_tmp[n+Np] + Aq_tmp[n+2*Np] + Aq_tmp[n+3*Np] + Aq_tmp[n+4*Np] + Aq_tmp[n+5*Np] + Aq_tmp[n+6*Np];
|
|
||||||
dB = Bq_tmp[n] + Bq_tmp[n+Np] + Bq_tmp[n+2*Np] + Bq_tmp[n+3*Np] + Bq_tmp[n+4*Np] + Bq_tmp[n+5*Np] + Bq_tmp[n+6*Np];
|
|
||||||
phi = (dA - dB) / (dA + dB);
|
|
||||||
Phase[n] = phi;
|
|
||||||
mass_a += dA;
|
|
||||||
mass_b += dB;
|
|
||||||
if (phi > 0.0){
|
|
||||||
vax += Vel_x[n];
|
|
||||||
vay += Vel_y[n];
|
|
||||||
vaz += Vel_z[n];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
vbx += Vel_x[n];
|
|
||||||
vby += Vel_y[n];
|
|
||||||
vbz += Vel_z[n];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
mass_a_global = M.Dm->Comm.sumReduce(mass_a);
|
|
||||||
mass_b_global = M.Dm->Comm.sumReduce(mass_b);
|
|
||||||
vax_global = M.Dm->Comm.sumReduce(vax);
|
|
||||||
vay_global = M.Dm->Comm.sumReduce(vay);
|
|
||||||
vaz_global = M.Dm->Comm.sumReduce(vaz);
|
|
||||||
vbx_global = M.Dm->Comm.sumReduce(vbx);
|
|
||||||
vby_global = M.Dm->Comm.sumReduce(vby);
|
|
||||||
vbz_global = M.Dm->Comm.sumReduce(vbz);
|
|
||||||
|
|
||||||
double total_momentum_A = sqrt(vax_global*vax_global+vay_global*vay_global+vaz_global*vaz_global);
|
double LOCAL_MASS_CHANGE = 0.0;
|
||||||
double total_momentum_B = sqrt(vbx_global*vbx_global+vby_global*vby_global+vbz_global*vbz_global);
|
for (int k=1; k<Nz-1; k++){
|
||||||
/* compute the total mass change */
|
for (int j=1; j<Ny-1; j++){
|
||||||
double TOTAL_MASS_CHANGE = MASS_FRACTION_CHANGE*(mass_a_global + mass_b_global);
|
for (int i=1; i<Nx-1; i++){
|
||||||
if (fabs(TOTAL_MASS_CHANGE) > 0.1*mass_a_global )
|
int n=M.Map(i,j,k);
|
||||||
TOTAL_MASS_CHANGE = 0.1*mass_a_global;
|
if (!(n<0)){
|
||||||
if (fabs(TOTAL_MASS_CHANGE) > 0.1*mass_b_global )
|
phi = Phase[n];
|
||||||
TOTAL_MASS_CHANGE = 0.1*mass_b_global;
|
vx = Vel_x[n];
|
||||||
|
vy = Vel_y[n];
|
||||||
double LOCAL_MASS_CHANGE = 0.0;
|
vz = Vel_z[n];
|
||||||
for (int k=1; k<Nz-1; k++){
|
double local_momentum = sqrt(vx*vx+vy*vy+vz*vz);
|
||||||
for (int j=1; j<Ny-1; j++){
|
/* impose ceiling for spurious currents */
|
||||||
for (int i=1; i<Nx-1; i++){
|
if (local_momentum > maxSpeed) local_momentum = maxSpeed;
|
||||||
int n=M.Map(i,j,k);
|
if (phi > 0.0){
|
||||||
if (!(n<0)){
|
LOCAL_MASS_CHANGE = TOTAL_MASS_CHANGE*local_momentum/total_momentum_A;
|
||||||
phi = Phase[n];
|
Aq_tmp[n] -= 0.3333333333333333*LOCAL_MASS_CHANGE;
|
||||||
vx = Vel_x[n];
|
Aq_tmp[n+Np] -= 0.1111111111111111*LOCAL_MASS_CHANGE;
|
||||||
vy = Vel_y[n];
|
Aq_tmp[n+2*Np] -= 0.1111111111111111*LOCAL_MASS_CHANGE;
|
||||||
vz = Vel_z[n];
|
Aq_tmp[n+3*Np] -= 0.1111111111111111*LOCAL_MASS_CHANGE;
|
||||||
double local_momentum = sqrt(vx*vx+vy*vy+vz*vz);
|
Aq_tmp[n+4*Np] -= 0.1111111111111111*LOCAL_MASS_CHANGE;
|
||||||
/* impose ceiling for spurious currents */
|
Aq_tmp[n+5*Np] -= 0.1111111111111111*LOCAL_MASS_CHANGE;
|
||||||
if (local_momentum > maxSpeed) local_momentum = maxSpeed;
|
Aq_tmp[n+6*Np] -= 0.1111111111111111*LOCAL_MASS_CHANGE;
|
||||||
if (phi > 0.0){
|
//DebugMassA[n] = (-1.0)*LOCAL_MASS_CHANGE;
|
||||||
LOCAL_MASS_CHANGE = TOTAL_MASS_CHANGE*local_momentum/total_momentum_A;
|
}
|
||||||
Aq_tmp[n] -= 0.3333333333333333*LOCAL_MASS_CHANGE;
|
else{
|
||||||
Aq_tmp[n+Np] -= 0.1111111111111111*LOCAL_MASS_CHANGE;
|
LOCAL_MASS_CHANGE = TOTAL_MASS_CHANGE*local_momentum/total_momentum_B;
|
||||||
Aq_tmp[n+2*Np] -= 0.1111111111111111*LOCAL_MASS_CHANGE;
|
Bq_tmp[n] += 0.3333333333333333*LOCAL_MASS_CHANGE;
|
||||||
Aq_tmp[n+3*Np] -= 0.1111111111111111*LOCAL_MASS_CHANGE;
|
Bq_tmp[n+Np] += 0.1111111111111111*LOCAL_MASS_CHANGE;
|
||||||
Aq_tmp[n+4*Np] -= 0.1111111111111111*LOCAL_MASS_CHANGE;
|
Bq_tmp[n+2*Np] += 0.1111111111111111*LOCAL_MASS_CHANGE;
|
||||||
Aq_tmp[n+5*Np] -= 0.1111111111111111*LOCAL_MASS_CHANGE;
|
Bq_tmp[n+3*Np] += 0.1111111111111111*LOCAL_MASS_CHANGE;
|
||||||
Aq_tmp[n+6*Np] -= 0.1111111111111111*LOCAL_MASS_CHANGE;
|
Bq_tmp[n+4*Np] += 0.1111111111111111*LOCAL_MASS_CHANGE;
|
||||||
DebugMassA[n] = (-1.0)*LOCAL_MASS_CHANGE;
|
Bq_tmp[n+5*Np] += 0.1111111111111111*LOCAL_MASS_CHANGE;
|
||||||
}
|
Bq_tmp[n+6*Np] += 0.1111111111111111*LOCAL_MASS_CHANGE;
|
||||||
else{
|
//DebugMassB[n] = LOCAL_MASS_CHANGE;
|
||||||
LOCAL_MASS_CHANGE = TOTAL_MASS_CHANGE*local_momentum/total_momentum_B;
|
}
|
||||||
Bq_tmp[n] += 0.3333333333333333*LOCAL_MASS_CHANGE;
|
}
|
||||||
Bq_tmp[n+Np] += 0.1111111111111111*LOCAL_MASS_CHANGE;
|
}
|
||||||
Bq_tmp[n+2*Np] += 0.1111111111111111*LOCAL_MASS_CHANGE;
|
}
|
||||||
Bq_tmp[n+3*Np] += 0.1111111111111111*LOCAL_MASS_CHANGE;
|
}
|
||||||
Bq_tmp[n+4*Np] += 0.1111111111111111*LOCAL_MASS_CHANGE;
|
/* for (int n=0; n < M.ScaLBL_Comm->LastExterior(); n++){
|
||||||
Bq_tmp[n+5*Np] += 0.1111111111111111*LOCAL_MASS_CHANGE;
|
|
||||||
Bq_tmp[n+6*Np] += 0.1111111111111111*LOCAL_MASS_CHANGE;
|
|
||||||
DebugMassB[n] = LOCAL_MASS_CHANGE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* for (int n=0; n < M.ScaLBL_Comm->LastExterior(); n++){
|
|
||||||
phi = Phase[n];
|
phi = Phase[n];
|
||||||
vx = Vel_x[n];
|
vx = Vel_x[n];
|
||||||
vy = Vel_y[n];
|
vy = Vel_y[n];
|
||||||
@ -2237,10 +2246,10 @@ double FlowAdaptor::UpdateFractionalFlow(ScaLBL_ColorModel &M){
|
|||||||
DebugMassB[n] = LOCAL_MASS_CHANGE;
|
DebugMassB[n] = LOCAL_MASS_CHANGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (M.rank == 0) printf("Update Fractional Flow: change mass of fluid B by %f \n",TOTAL_MASS_CHANGE/mass_b_global);
|
if (M.rank == 0) printf("Update Fractional Flow: change mass of fluid B by %f \n",TOTAL_MASS_CHANGE/mass_b_global);
|
||||||
|
|
||||||
/* Print out debugging info with mass update */
|
/* Print out debugging info with mass update
|
||||||
// initialize the array
|
// initialize the array
|
||||||
double value;
|
double value;
|
||||||
char LocalRankFilename[40];
|
char LocalRankFilename[40];
|
||||||
@ -2281,13 +2290,14 @@ double FlowAdaptor::UpdateFractionalFlow(ScaLBL_ColorModel &M){
|
|||||||
BFILE = fopen(LocalRankFilename,"wb");
|
BFILE = fopen(LocalRankFilename,"wb");
|
||||||
fwrite(regdata.data(),8,N,BFILE);
|
fwrite(regdata.data(),8,N,BFILE);
|
||||||
fclose(BFILE);
|
fclose(BFILE);
|
||||||
|
*/
|
||||||
|
|
||||||
// Need to initialize Aq, Bq, Den, Phi directly
|
// Need to initialize Aq, Bq, Den, Phi directly
|
||||||
//ScaLBL_CopyToDevice(Phi,phase.data(),7*Np*sizeof(double));
|
//ScaLBL_CopyToDevice(Phi,phase.data(),7*Np*sizeof(double));
|
||||||
ScaLBL_CopyToDevice(M.Aq, Aq_tmp, 7*Np*sizeof(double));
|
ScaLBL_CopyToDevice(M.Aq, Aq_tmp, 7*Np*sizeof(double));
|
||||||
ScaLBL_CopyToDevice(M.Bq, Bq_tmp, 7*Np*sizeof(double));
|
ScaLBL_CopyToDevice(M.Bq, Bq_tmp, 7*Np*sizeof(double));
|
||||||
|
|
||||||
return(TOTAL_MASS_CHANGE);
|
return(TOTAL_MASS_CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlowAdaptor::Flatten(ScaLBL_ColorModel &M){
|
void FlowAdaptor::Flatten(ScaLBL_ColorModel &M){
|
||||||
|
@ -89,6 +89,8 @@ public:
|
|||||||
double *Velocity;
|
double *Velocity;
|
||||||
double *Pressure;
|
double *Pressure;
|
||||||
|
|
||||||
|
void AssignComponentLabels(double *phase);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Utilities::MPI comm;
|
Utilities::MPI comm;
|
||||||
|
|
||||||
@ -101,7 +103,6 @@ private:
|
|||||||
|
|
||||||
//int rank,nprocs;
|
//int rank,nprocs;
|
||||||
void LoadParams(std::shared_ptr<Database> db0);
|
void LoadParams(std::shared_ptr<Database> db0);
|
||||||
void AssignComponentLabels(double *phase);
|
|
||||||
double ImageInit(std::string filename);
|
double ImageInit(std::string filename);
|
||||||
double MorphInit(const double beta, const double morph_delta);
|
double MorphInit(const double beta, const double morph_delta);
|
||||||
double SeedPhaseField(const double seed_water_in_oil);
|
double SeedPhaseField(const double seed_water_in_oil);
|
||||||
@ -113,6 +114,7 @@ public:
|
|||||||
FlowAdaptor(ScaLBL_ColorModel &M);
|
FlowAdaptor(ScaLBL_ColorModel &M);
|
||||||
~FlowAdaptor();
|
~FlowAdaptor();
|
||||||
double MoveInterface(ScaLBL_ColorModel &M);
|
double MoveInterface(ScaLBL_ColorModel &M);
|
||||||
|
double ImageInit(ScaLBL_ColorModel &M, std::string Filename);
|
||||||
double UpdateFractionalFlow(ScaLBL_ColorModel &M);
|
double UpdateFractionalFlow(ScaLBL_ColorModel &M);
|
||||||
void Flatten(ScaLBL_ColorModel &M);
|
void Flatten(ScaLBL_ColorModel &M);
|
||||||
DoubleArray phi;
|
DoubleArray phi;
|
||||||
|
@ -22,114 +22,138 @@
|
|||||||
int main( int argc, char **argv )
|
int main( int argc, char **argv )
|
||||||
{
|
{
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
Utilities::startup( argc, argv );
|
Utilities::startup( argc, argv );
|
||||||
|
|
||||||
{ // Limit scope so variables that contain communicators will free before MPI_Finialize
|
{ // Limit scope so variables that contain communicators will free before MPI_Finialize
|
||||||
|
|
||||||
Utilities::MPI comm( MPI_COMM_WORLD );
|
Utilities::MPI comm( MPI_COMM_WORLD );
|
||||||
int rank = comm.getRank();
|
int rank = comm.getRank();
|
||||||
int nprocs = comm.getSize();
|
int nprocs = comm.getSize();
|
||||||
std::string SimulationMode = "production";
|
std::string SimulationMode = "production";
|
||||||
// Load the input database
|
// Load the input database
|
||||||
auto db = std::make_shared<Database>( argv[1] );
|
auto db = std::make_shared<Database>( argv[1] );
|
||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
SimulationMode = "development";
|
SimulationMode = "development";
|
||||||
}
|
|
||||||
|
|
||||||
if ( rank == 0 ) {
|
|
||||||
printf( "********************************************************\n" );
|
|
||||||
printf( "Running Color LBM \n" );
|
|
||||||
printf( "********************************************************\n" );
|
|
||||||
if (SimulationMode == "development")
|
|
||||||
printf("**** DEVELOPMENT MODE ENABLED *************\n");
|
|
||||||
}
|
|
||||||
// Initialize compute device
|
|
||||||
int device = ScaLBL_SetDevice( rank );
|
|
||||||
NULL_USE( device );
|
|
||||||
ScaLBL_DeviceBarrier();
|
|
||||||
comm.barrier();
|
|
||||||
|
|
||||||
PROFILE_ENABLE( 1 );
|
|
||||||
// PROFILE_ENABLE_TRACE();
|
|
||||||
// PROFILE_ENABLE_MEMORY();
|
|
||||||
PROFILE_SYNCHRONIZE();
|
|
||||||
PROFILE_START( "Main" );
|
|
||||||
Utilities::setErrorHandlers();
|
|
||||||
|
|
||||||
auto filename = argv[1];
|
|
||||||
ScaLBL_ColorModel ColorModel( rank, nprocs, comm );
|
|
||||||
ColorModel.ReadParams( filename );
|
|
||||||
ColorModel.SetDomain();
|
|
||||||
ColorModel.ReadInput();
|
|
||||||
ColorModel.Create(); // creating the model will create data structure to match the pore
|
|
||||||
// structure and allocate variables
|
|
||||||
ColorModel.Initialize(); // initializing the model will set initial conditions for variables
|
|
||||||
|
|
||||||
if (SimulationMode == "development"){
|
|
||||||
double MLUPS=0.0;
|
|
||||||
int timestep = 0;
|
|
||||||
bool ContinueSimulation = true;
|
|
||||||
int ANALYSIS_INTERVAL = ColorModel.timestepMax;
|
|
||||||
/* flow adaptor keys to control */
|
|
||||||
int SKIP_TIMESTEPS = 0;
|
|
||||||
int MAX_STEADY_TIME = 1000000;
|
|
||||||
double ENDPOINT_THRESHOLD = 0.1;
|
|
||||||
double FRACTIONAL_FLOW_INCREMENT = 0.05;
|
|
||||||
if (ColorModel.db->keyExists( "FlowAdaptor" )){
|
|
||||||
auto flow_db = ColorModel.db->getDatabase( "FlowAdaptor" );
|
|
||||||
MAX_STEADY_TIME = flow_db->getWithDefault<int>( "max_steady_timesteps", 1000000 );
|
|
||||||
SKIP_TIMESTEPS = flow_db->getWithDefault<int>( "skip_timesteps", 100000 );
|
|
||||||
FRACTIONAL_FLOW_INCREMENT = flow_db->getWithDefault<double>( "fractional_flow_increment", 0.05);
|
|
||||||
ENDPOINT_THRESHOLD = flow_db->getWithDefault<double>( "endpoint_threshold", 0.1);
|
|
||||||
}
|
|
||||||
if (ColorModel.analysis_db->keyExists( "analysis_interval" )){
|
|
||||||
ANALYSIS_INTERVAL = ColorModel.analysis_db->getScalar<int>( "analysis_interval" );
|
|
||||||
}
|
|
||||||
/* Launch the simulation */
|
|
||||||
FlowAdaptor Adapt(ColorModel);
|
|
||||||
runAnalysis analysis(ColorModel);
|
|
||||||
while (ContinueSimulation){
|
|
||||||
/* this will run steady points */
|
|
||||||
timestep += MAX_STEADY_TIME;
|
|
||||||
MLUPS = ColorModel.Run(timestep);
|
|
||||||
if (rank==0) printf("Lattice update rate (per MPI process)= %f MLUPS \n", MLUPS);
|
|
||||||
if (ColorModel.timestep > ColorModel.timestepMax){
|
|
||||||
ContinueSimulation = false;
|
|
||||||
}
|
|
||||||
/* update the fractional flow by adding mass */
|
|
||||||
int skip_time = 0;
|
|
||||||
timestep = ColorModel.timestep;
|
|
||||||
double SaturationChange = 0.0;
|
|
||||||
double volB = ColorModel.Averages->gwb.V;
|
|
||||||
double volA = ColorModel.Averages->gnb.V;
|
|
||||||
double initialSaturation = volB/(volA + volB);
|
|
||||||
|
|
||||||
double vA_x = ColorModel.Averages->gnb.Px/ColorModel.Averages->gnb.M;
|
|
||||||
double vA_y = ColorModel.Averages->gnb.Py/ColorModel.Averages->gnb.M;
|
|
||||||
double vA_z = ColorModel.Averages->gnb.Pz/ColorModel.Averages->gnb.M;
|
|
||||||
double vB_x = ColorModel.Averages->gwb.Px/ColorModel.Averages->gwb.M;
|
|
||||||
double vB_y = ColorModel.Averages->gwb.Py/ColorModel.Averages->gwb.M;
|
|
||||||
double vB_z = ColorModel.Averages->gwb.Pz/ColorModel.Averages->gwb.M;
|
|
||||||
double speedA = sqrt(vA_x*vA_x + vA_y*vA_y + vA_z*vA_z);
|
|
||||||
double speedB = sqrt(vB_x*vB_x + vB_y*vB_y + vB_z*vB_z);
|
|
||||||
if (volA*speedA < ENDPOINT_THRESHOLD*volB*speedB) ContinueSimulation = false;
|
|
||||||
if (ContinueSimulation){
|
|
||||||
while (skip_time < SKIP_TIMESTEPS && fabs(SaturationChange) < fabs(FRACTIONAL_FLOW_INCREMENT) ){
|
|
||||||
timestep += ANALYSIS_INTERVAL;
|
|
||||||
Adapt.UpdateFractionalFlow(ColorModel);
|
|
||||||
MLUPS = ColorModel.Run(timestep);
|
|
||||||
double volB = ColorModel.Averages->gwb.V;
|
|
||||||
double volA = ColorModel.Averages->gnb.V;
|
|
||||||
SaturationChange = volB/(volA + volB) - initialSaturation;
|
|
||||||
skip_time += ANALYSIS_INTERVAL;
|
|
||||||
}
|
}
|
||||||
if (rank==0) printf(" ********************************************************************* \n");
|
|
||||||
if (rank==0) printf(" Updated fractional flow with saturation change = %f \n", SaturationChange);
|
if ( rank == 0 ) {
|
||||||
if (rank==0) printf(" ********************************************************************* \n");
|
printf( "********************************************************\n" );
|
||||||
|
printf( "Running Color LBM \n" );
|
||||||
|
printf( "********************************************************\n" );
|
||||||
|
if (SimulationMode == "development")
|
||||||
|
printf("**** DEVELOPMENT MODE ENABLED *************\n");
|
||||||
}
|
}
|
||||||
/* apply timestep skipping algorithm to accelerate steady-state */
|
// Initialize compute device
|
||||||
/* skip_time = 0;
|
int device = ScaLBL_SetDevice( rank );
|
||||||
|
NULL_USE( device );
|
||||||
|
ScaLBL_DeviceBarrier();
|
||||||
|
comm.barrier();
|
||||||
|
|
||||||
|
PROFILE_ENABLE( 1 );
|
||||||
|
// PROFILE_ENABLE_TRACE();
|
||||||
|
// PROFILE_ENABLE_MEMORY();
|
||||||
|
PROFILE_SYNCHRONIZE();
|
||||||
|
PROFILE_START( "Main" );
|
||||||
|
Utilities::setErrorHandlers();
|
||||||
|
|
||||||
|
auto filename = argv[1];
|
||||||
|
ScaLBL_ColorModel ColorModel( rank, nprocs, comm );
|
||||||
|
ColorModel.ReadParams( filename );
|
||||||
|
ColorModel.SetDomain();
|
||||||
|
ColorModel.ReadInput();
|
||||||
|
ColorModel.Create(); // creating the model will create data structure to match the pore
|
||||||
|
// structure and allocate variables
|
||||||
|
ColorModel.Initialize(); // initializing the model will set initial conditions for variables
|
||||||
|
|
||||||
|
|
||||||
|
if (SimulationMode == "development"){
|
||||||
|
double MLUPS=0.0;
|
||||||
|
int timestep = 0;
|
||||||
|
bool ContinueSimulation = true;
|
||||||
|
|
||||||
|
/* Variables for simulation protocols */
|
||||||
|
auto PROTOCOL = ColorModel.color_db->getWithDefault<std::string>( "protocol", "none" );
|
||||||
|
/* image sequence protocol */
|
||||||
|
int IMAGE_INDEX = 0;
|
||||||
|
int IMAGE_COUNT = 0;
|
||||||
|
std::vector<std::string> ImageList;
|
||||||
|
/* flow adaptor keys to control behavior */
|
||||||
|
int SKIP_TIMESTEPS = 0;
|
||||||
|
int MAX_STEADY_TIME = 1000000;
|
||||||
|
double ENDPOINT_THRESHOLD = 0.1;
|
||||||
|
double FRACTIONAL_FLOW_INCREMENT = 0.05;
|
||||||
|
if (ColorModel.db->keyExists( "FlowAdaptor" )){
|
||||||
|
auto flow_db = ColorModel.db->getDatabase( "FlowAdaptor" );
|
||||||
|
MAX_STEADY_TIME = flow_db->getWithDefault<int>( "max_steady_timesteps", 1000000 );
|
||||||
|
SKIP_TIMESTEPS = flow_db->getWithDefault<int>( "skip_timesteps", 100000 );
|
||||||
|
FRACTIONAL_FLOW_INCREMENT = flow_db->getWithDefault<double>( "fractional_flow_increment", 0.05);
|
||||||
|
ENDPOINT_THRESHOLD = flow_db->getWithDefault<double>( "endpoint_threshold", 0.1);
|
||||||
|
}
|
||||||
|
/* analysis keys*/
|
||||||
|
int ANALYSIS_INTERVAL = ColorModel.timestepMax;
|
||||||
|
if (ColorModel.analysis_db->keyExists( "analysis_interval" )){
|
||||||
|
ANALYSIS_INTERVAL = ColorModel.analysis_db->getScalar<int>( "analysis_interval" );
|
||||||
|
}
|
||||||
|
/* Launch the simulation */
|
||||||
|
FlowAdaptor Adapt(ColorModel);
|
||||||
|
runAnalysis analysis(ColorModel);
|
||||||
|
while (ContinueSimulation){
|
||||||
|
/* this will run steady points */
|
||||||
|
timestep += MAX_STEADY_TIME;
|
||||||
|
MLUPS = ColorModel.Run(timestep);
|
||||||
|
if (rank==0) printf("Lattice update rate (per MPI process)= %f MLUPS \n", MLUPS);
|
||||||
|
if (ColorModel.timestep > ColorModel.timestepMax){
|
||||||
|
ContinueSimulation = false;
|
||||||
|
}
|
||||||
|
/* update the fluid configuration with the flow adapter */
|
||||||
|
int skip_time = 0;
|
||||||
|
timestep = ColorModel.timestep;
|
||||||
|
double SaturationChange = 0.0;
|
||||||
|
double volB = ColorModel.Averages->gwb.V;
|
||||||
|
double volA = ColorModel.Averages->gnb.V;
|
||||||
|
double initialSaturation = volB/(volA + volB);
|
||||||
|
double vA_x = ColorModel.Averages->gnb.Px/ColorModel.Averages->gnb.M;
|
||||||
|
double vA_y = ColorModel.Averages->gnb.Py/ColorModel.Averages->gnb.M;
|
||||||
|
double vA_z = ColorModel.Averages->gnb.Pz/ColorModel.Averages->gnb.M;
|
||||||
|
double vB_x = ColorModel.Averages->gwb.Px/ColorModel.Averages->gwb.M;
|
||||||
|
double vB_y = ColorModel.Averages->gwb.Py/ColorModel.Averages->gwb.M;
|
||||||
|
double vB_z = ColorModel.Averages->gwb.Pz/ColorModel.Averages->gwb.M;
|
||||||
|
double speedA = sqrt(vA_x*vA_x + vA_y*vA_y + vA_z*vA_z);
|
||||||
|
double speedB = sqrt(vB_x*vB_x + vB_y*vB_y + vB_z*vB_z);
|
||||||
|
if (volA*speedA < ENDPOINT_THRESHOLD*volB*speedB) ContinueSimulation = false;
|
||||||
|
if (ContinueSimulation){
|
||||||
|
while (skip_time < SKIP_TIMESTEPS && fabs(SaturationChange) < fabs(FRACTIONAL_FLOW_INCREMENT) ){
|
||||||
|
timestep += ANALYSIS_INTERVAL;
|
||||||
|
if (PROTOCOL == "fractional flow") {
|
||||||
|
Adapt.UpdateFractionalFlow(ColorModel);
|
||||||
|
}
|
||||||
|
else if (PROTOCOL == "image sequence"){
|
||||||
|
// Use image sequence
|
||||||
|
IMAGE_INDEX++;
|
||||||
|
if (IMAGE_INDEX < IMAGE_COUNT){
|
||||||
|
std::string next_image = ImageList[IMAGE_INDEX];
|
||||||
|
if (rank==0) printf("***Loading next image in sequence (%i) ***\n",IMAGE_INDEX);
|
||||||
|
ColorModel.color_db->putScalar<int>("image_index",IMAGE_INDEX);
|
||||||
|
Adapt.ImageInit(ColorModel, next_image);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (rank==0) printf("Finished simulating image sequence \n");
|
||||||
|
ColorModel.timestep = ColorModel.timestepMax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MLUPS = ColorModel.Run(timestep);
|
||||||
|
double volB = ColorModel.Averages->gwb.V;
|
||||||
|
double volA = ColorModel.Averages->gnb.V;
|
||||||
|
SaturationChange = volB/(volA + volB) - initialSaturation;
|
||||||
|
skip_time += ANALYSIS_INTERVAL;
|
||||||
|
}
|
||||||
|
if (rank==0) printf(" ********************************************************************* \n");
|
||||||
|
if (rank==0) printf(" Updated fractional flow with saturation change = %f \n", SaturationChange);
|
||||||
|
if (rank==0) printf(" ********************************************************************* \n");
|
||||||
|
}
|
||||||
|
/* apply timestep skipping algorithm to accelerate steady-state */
|
||||||
|
/* skip_time = 0;
|
||||||
timestep = ColorModel.timestep;
|
timestep = ColorModel.timestep;
|
||||||
while (skip_time < SKIP_TIMESTEPS){
|
while (skip_time < SKIP_TIMESTEPS){
|
||||||
timestep += ANALYSIS_INTERVAL;
|
timestep += ANALYSIS_INTERVAL;
|
||||||
@ -137,24 +161,24 @@ int main( int argc, char **argv )
|
|||||||
Adapt.MoveInterface(ColorModel);
|
Adapt.MoveInterface(ColorModel);
|
||||||
skip_time += ANALYSIS_INTERVAL;
|
skip_time += ANALYSIS_INTERVAL;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
//ColorModel.WriteDebug();
|
//ColorModel.WriteDebug();
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
ColorModel.Run();
|
ColorModel.Run();
|
||||||
|
|
||||||
PROFILE_STOP( "Main" );
|
PROFILE_STOP( "Main" );
|
||||||
auto file = db->getWithDefault<std::string>( "TimerFile", "lbpm_color_simulator" );
|
auto file = db->getWithDefault<std::string>( "TimerFile", "lbpm_color_simulator" );
|
||||||
auto level = db->getWithDefault<int>( "TimerLevel", 1 );
|
auto level = db->getWithDefault<int>( "TimerLevel", 1 );
|
||||||
NULL_USE(level);
|
NULL_USE(level);
|
||||||
PROFILE_SAVE( file, level );
|
PROFILE_SAVE( file, level );
|
||||||
// ****************************************************
|
// ****************************************************
|
||||||
|
|
||||||
|
|
||||||
} // Limit scope so variables that contain communicators will free before MPI_Finialize
|
} // Limit scope so variables that contain communicators will free before MPI_Finialize
|
||||||
|
|
||||||
Utilities::shutdown();
|
Utilities::shutdown();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user