Merge branch 'Spock' of github.com:JamesEMcClure/LBPM-WIA into Spock
This commit is contained in:
commit
af7ec72622
115
.clang-format
115
.clang-format
|
@ -1,108 +1,13 @@
|
|||
# To run clang tools:
|
||||
# cd to root directory
|
||||
# To update format only:
|
||||
# find . -name "*.cpp" -or -name "*.cc" -or -name "*.h" -or -name "*.hpp" -or -name "*.I" | xargs -I{} clang-format -i {}
|
||||
# git status -s . | sed s/^...// | grep -E "(\.cpp|\.h|\.cc|\.hpp|\.I)" | xargs -I{} clang-format -i {}
|
||||
|
||||
# To run modernize
|
||||
# export CLANG_PATH=/packages/llvm/build/llvm-60
|
||||
# export PATH=${CLANG_PATH}/bin:${CLANG_PATH}/share/clang:$PATH
|
||||
# find src -name "*.cpp" -or -name "*.cc" | xargs -I{} clang-tidy -checks=modernize* -p=/projects/AtomicModel/build/debug -fix {}
|
||||
# find src -name "*.cpp" -or -name "*.cc" -or -name "*.h" -or -name "*.hpp" -or -name "*.I" | xargs -I{} clang-format -i {}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# clang-format
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlinesLeft: true
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: true
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
#BreakBeforeBraces: Stroustrup
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
ColumnLimit: 100
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
- Regex: '^(<|"(gtest|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IndentCaseLabels: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 4
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: true
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
...
|
||||
IndentWidth: 4
|
||||
|
||||
# Our includes are not order-agnostic
|
||||
SortIncludes: false
|
||||
|
||||
# Some of our comments include insightful insight
|
||||
ReflowComments: false
|
||||
...
|
||||
|
|
13
.clang-format-2
Normal file
13
.clang-format-2
Normal file
|
@ -0,0 +1,13 @@
|
|||
# clang-format
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
IndentWidth: 4
|
||||
|
||||
# Our includes are not order-agnostic
|
||||
SortIncludes: false
|
||||
|
||||
# Some of our comments include insightful insight
|
||||
ReflowComments: false
|
||||
...
|
124
.github/workflows/c-cpp.yml
vendored
Normal file
124
.github/workflows/c-cpp.yml
vendored
Normal file
|
@ -0,0 +1,124 @@
|
|||
name: LBPM CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
LBPM_ZLIB_DIR: /home/runner/extlib/zlib
|
||||
LBPM_HDF5_DIR: /home/runner/extlib/hdf5
|
||||
LBPM_SILO_DIR: /home/runner/extlib/silo
|
||||
MPI_DIR: /home/runner/.openmpi
|
||||
|
||||
steps:
|
||||
|
||||
- name: download dependencies
|
||||
run: |
|
||||
echo $LBPM_ZLIB_DIR
|
||||
echo $LBPM_HDF5_DIR
|
||||
echo $LBPM_SILO_DIR
|
||||
echo $GITHUB_PATH
|
||||
echo $GITHUB_WORKSPACE
|
||||
|
||||
sudo apt-get update -y
|
||||
|
||||
wget https://bitbucket.org/AdvancedMultiPhysics/tpl-builder/downloads/silo-4.10.2.tar.gz
|
||||
wget https://www.zlib.net/zlib-1.2.11.tar.gz
|
||||
wget https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.8/hdf5-1.8.12/src/hdf5-1.8.12.tar.gz
|
||||
#wget https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.8/hdf5-1.8.10/src/hdf5-1.8.10.tar.gz
|
||||
|
||||
tar -xzvf zlib-1.2.11.tar.gz
|
||||
tar -xzvf hdf5-1.8.12.tar.gz
|
||||
tar -xzvf silo-4.10.2.tar.gz
|
||||
|
||||
|
||||
- name: check out commit
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: LBPM
|
||||
|
||||
|
||||
|
||||
- name: install-openmpi
|
||||
run: |
|
||||
wget https://download.open-mpi.org/release/open-mpi/v3.1/openmpi-3.1.2.tar.gz
|
||||
tar -xvf ./openmpi-3.1.2.tar.gz
|
||||
./openmpi-3.1.2/configure --prefix="$HOME/.openmpi"
|
||||
make -j
|
||||
sudo make install
|
||||
echo "$HOME/.openmpi/bin" >> $GITHUB_PATH
|
||||
|
||||
|
||||
|
||||
- name: install zlib dependencies
|
||||
run: |
|
||||
cd zlib-1.2.11
|
||||
./configure --prefix=$LBPM_ZLIB_DIR
|
||||
make
|
||||
sudo make install
|
||||
cd ..
|
||||
|
||||
|
||||
- name: install hdf5 dependencies
|
||||
run: |
|
||||
cd hdf5-1.8.12
|
||||
CC=/home/runner/.openmpi/bin/mpicc CXX=/home/runner/.openmpi/bin/mpicxx CXXFLAGS="-fPIC -O3 -std=c++14" \
|
||||
./configure --prefix=$LBPM_HDF5_DIR --enable-parallel --enable-shared --with-zlib=$LBPM_ZLIB_DIR
|
||||
make
|
||||
sudo make install
|
||||
cd ..
|
||||
|
||||
|
||||
- name: install silo dependencies
|
||||
run: |
|
||||
cd silo-4.10.2
|
||||
CC=$MPI_DIR/bin/mpicc CXX=$MPI_DIR/bin/mpicxx CXXFLAGS="-fPIC -O3 -std=c++14" \
|
||||
./configure --prefix=$LBPM_SILO_DIR -with-hdf5="$LBPM_HDF5_DIR/include,$LBPM_HDF5_DIR/lib" --enable-static
|
||||
make
|
||||
sudo make install
|
||||
cd ..
|
||||
|
||||
|
||||
- name: configure cmake
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
rm -rf CMake*
|
||||
cmake \
|
||||
-D CMAKE_BUILD_TYPE:STRING=Release \
|
||||
-D CMAKE_C_COMPILER:PATH=$MPI_DIR/bin/mpicc \
|
||||
-D CMAKE_CXX_COMPILER:PATH=$MPI_DIR/bin/mpicxx \
|
||||
-D MPI_CXX_COMPILER=$MPI_DIR/bin/mpicxx \
|
||||
-D CMAKE_C_FLAGS="-fPIC" \
|
||||
-D CMAKE_CXX_FLAGS="-fPIC" \
|
||||
-D CMAKE_CXX_STD=14 \
|
||||
-D TEST_MAX_PROCS=1 \
|
||||
-D USE_TIMER=0 \
|
||||
-D TIMER_DIRECTORY=$LBPM_TIMER_DIR \
|
||||
-D USE_NETCDF=0 \
|
||||
-D NETCDF_DIRECTORY=$LBPM_NETCDF_DIR \
|
||||
-D USE_SILO=1 \
|
||||
-D HDF5_DIRECTORY=$LBPM_HDF5_DIR \
|
||||
-D SILO_DIRECTORY=$LBPM_SILO_DIR \
|
||||
-D USE_CUDA=0 \
|
||||
$GITHUB_WORKSPACE/LBPM
|
||||
|
||||
|
||||
|
||||
- name: build and make
|
||||
run: |
|
||||
cd build
|
||||
make
|
||||
sudo make install
|
||||
cd ..
|
||||
|
||||
- name: tests
|
||||
run: |
|
||||
cd build
|
||||
ctest
|
41
.github/workflows/test_install_openmpi.yml
vendored
Normal file
41
.github/workflows/test_install_openmpi.yml
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
name: Install OpenMPI test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
install-openmpi:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: check path
|
||||
run: |
|
||||
echo $PATH
|
||||
echo $GITHUB_PATH
|
||||
cmake --version
|
||||
|
||||
- name: download-openmpi
|
||||
run: wget https://download.open-mpi.org/release/open-mpi/v4.0/openmpi-4.0.2.tar.gz
|
||||
|
||||
- name: extract-openmpi
|
||||
run: tar -xvf ./openmpi-4.0.2.tar.gz
|
||||
|
||||
- name: configure-openmpi
|
||||
run: ./openmpi-4.0.2/configure --prefix="/home/${USER}/.openmpi"
|
||||
|
||||
- name: install-openmpi
|
||||
run: |
|
||||
make -j
|
||||
sudo make install
|
||||
|
||||
- name: setting path
|
||||
run: |
|
||||
echo "/home/${USER}/.openmpi/bin" >> $GITHUB_PATH
|
||||
#echo "/home/${USER}/.openmpi/bin" >> $PATH
|
||||
- name: checking version
|
||||
run: mpirun --version
|
||||
|
|
@ -14,7 +14,6 @@ MESSAGE("====================")
|
|||
SET( PROJ LBPM ) # Set the project name for CMake
|
||||
SET( LBPM_LIB lbpm-wia ) # Set the final library name
|
||||
SET( LBPM_INC ) # Set an optional subfolder for includes (e.g. include/name/...)
|
||||
SET( TEST_MAX_PROCS 16 )
|
||||
|
||||
|
||||
# Initialize the project
|
||||
|
@ -90,7 +89,7 @@ CHECK_ENABLE_FLAG( USE_DOXYGEN 1 )
|
|||
CHECK_ENABLE_FLAG( USE_LATEX 1 )
|
||||
FILE( MAKE_DIRECTORY "${${PROJ}_INSTALL_DIR}/doc" )
|
||||
IF ( USE_DOXYGEN )
|
||||
SET( DOXYFILE_LATEX YES )
|
||||
SET( DOXYFILE_LATEX NO )
|
||||
SET( DOXYFILE_IN "${${PROJ}_SOURCE_DIR}/doxygen/Doxyfile.in" )
|
||||
SET( DOXY_HEADER_FILE "${${PROJ}_SOURCE_DIR}/doxygen/html/header.html" )
|
||||
SET( DOXY_FOOTER_FILE "${${PROJ}_SOURCE_DIR}/doxygen/html/footer.html" )
|
||||
|
@ -135,6 +134,7 @@ ENDIF()
|
|||
IF ( NOT ONLY_BUILD_DOCS )
|
||||
CONFIGURE_MPI() # MPI must be before other libraries
|
||||
CONFIGURE_MIC()
|
||||
CONFIGURE_HDF5()
|
||||
CONFIGURE_NETCDF()
|
||||
CONFIGURE_SILO()
|
||||
CONFIGURE_LBPM()
|
||||
|
|
283
IO/HDF5Writer.cpp
Normal file
283
IO/HDF5Writer.cpp
Normal file
|
@ -0,0 +1,283 @@
|
|||
#include "IO/HDF5_IO.h"
|
||||
#include "IO/IOHelpers.h"
|
||||
#include "IO/MeshDatabase.h"
|
||||
#include "IO/Writer.h"
|
||||
#include "IO/Xdmf.h"
|
||||
#include "common/MPI.h"
|
||||
#include "common/Utilities.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <sys/stat.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#ifdef USE_HDF5
|
||||
|
||||
|
||||
std::string to_string( const ArraySize &s )
|
||||
{
|
||||
std::string out = "[" + std::to_string( s[0] );
|
||||
for ( size_t i = 1; i < s.ndim(); i++ )
|
||||
out += "," + to_string( s[i] );
|
||||
out += "]";
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Xdmf::Center getXdmfType( IO::VariableType type )
|
||||
{
|
||||
if ( type == IO::VariableType::NodeVariable ) {
|
||||
return Xdmf::Center::Node;
|
||||
} else if ( type == IO::VariableType::VolumeVariable ) {
|
||||
return Xdmf::Center::Cell;
|
||||
} else {
|
||||
ERROR( "Variable type not supported" );
|
||||
}
|
||||
return Xdmf::Center::Null;
|
||||
}
|
||||
|
||||
|
||||
// Write a PointList mesh (and variables) to a file
|
||||
template<class TYPE>
|
||||
static void writeCoordinates( hid_t fid, const std::vector<Point> &points )
|
||||
{
|
||||
std::vector<TYPE> x( points.size() ), y( points.size() ), z( points.size() );
|
||||
for ( size_t i = 0; i < x.size(); i++ ) {
|
||||
x[i] = points[i].x;
|
||||
y[i] = points[i].y;
|
||||
z[i] = points[i].z;
|
||||
}
|
||||
IO::HDF5::writeHDF5( fid, "x", x );
|
||||
IO::HDF5::writeHDF5( fid, "y", y );
|
||||
IO::HDF5::writeHDF5( fid, "z", z );
|
||||
}
|
||||
static void writeHDF5PointList( hid_t fid, const std::string &filename,
|
||||
const IO::MeshDataStruct &meshData, IO::MeshDatabase database, Xdmf &xmf )
|
||||
{
|
||||
auto meshname = database.domains[0].name;
|
||||
const auto &mesh = dynamic_cast<IO::PointList &>( *meshData.mesh );
|
||||
auto gid = IO::HDF5::createGroup( fid, meshname );
|
||||
if ( meshData.precision == IO::DataType::Double ) {
|
||||
writeCoordinates<double>( gid, mesh.getPoints() );
|
||||
} else if ( meshData.precision == IO::DataType::Float ) {
|
||||
writeCoordinates<float>( gid, mesh.getPoints() );
|
||||
} else {
|
||||
ERROR( "Unsupported format" );
|
||||
}
|
||||
auto path = filename + ":/" + meshname + "/";
|
||||
auto domain = Xdmf::createPointMesh(
|
||||
meshname, 3, mesh.getPoints().size(), path + "x", path + "y", path + "z" );
|
||||
for ( size_t i = 0; i < meshData.vars.size(); i++ ) {
|
||||
auto &var = *meshData.vars[i];
|
||||
auto data = var.data;
|
||||
auto rankType = Xdmf::RankType::Null;
|
||||
if ( data.ndim() == 1 ) {
|
||||
rankType = Xdmf::RankType::Scalar;
|
||||
} else if ( data.ndim() == 2 && data.size( 1 ) == 3 ) {
|
||||
// Vector data, need to permute for visit
|
||||
rankType = Xdmf::RankType::Vector;
|
||||
data = data.permute( { 1, 0 } );
|
||||
} else {
|
||||
ERROR( "Unable to determine variable rank: " + to_string( var.data.size() ) );
|
||||
}
|
||||
if ( var.precision == IO::DataType::Double ) {
|
||||
IO::HDF5::writeHDF5( gid, var.name, data );
|
||||
} else if ( var.precision == IO::DataType::Float ) {
|
||||
IO::HDF5::writeHDF5( gid, var.name, data.cloneTo<float>() );
|
||||
} else if ( var.precision == IO::DataType::Int ) {
|
||||
IO::HDF5::writeHDF5( gid, var.name, data.cloneTo<int>() );
|
||||
} else {
|
||||
ERROR( "Unsupported format" );
|
||||
}
|
||||
domain.addVariable(
|
||||
meshname, var.name, data.size(), rankType, Xdmf::Center::Node, path + var.name );
|
||||
}
|
||||
xmf.addMesh( meshData.meshName, domain );
|
||||
}
|
||||
// Write a TriMesh mesh (and variables) to a file
|
||||
static void writeHDF5TriMesh2( hid_t fid, const std::string &filename,
|
||||
const IO::MeshDataStruct &meshData, const IO::TriMesh &mesh, IO::MeshDatabase database,
|
||||
Xdmf &xmf )
|
||||
{
|
||||
auto meshname = database.domains[0].name;
|
||||
auto gid = IO::HDF5::createGroup( fid, meshname );
|
||||
auto path = filename + ":/" + meshname + "/";
|
||||
// Write the verticies
|
||||
if ( meshData.precision == IO::DataType::Double ) {
|
||||
writeCoordinates<double>( gid, mesh.vertices->getPoints() );
|
||||
} else if ( meshData.precision == IO::DataType::Float ) {
|
||||
writeCoordinates<float>( gid, mesh.vertices->getPoints() );
|
||||
} else {
|
||||
ERROR( "Unsupported format" );
|
||||
}
|
||||
// Write the connectivity
|
||||
Array<int> tri( 3, mesh.A.size() );
|
||||
for ( size_t i = 0; i < mesh.A.size(); i++ ) {
|
||||
tri( 0, i ) = mesh.A[i];
|
||||
tri( 1, i ) = mesh.B[i];
|
||||
tri( 2, i ) = mesh.C[i];
|
||||
}
|
||||
IO::HDF5::writeHDF5( gid, "tri", tri );
|
||||
auto domain =
|
||||
Xdmf::createUnstructuredMesh( meshname, 3, Xdmf::TopologyType::Triangle, tri.size( 1 ),
|
||||
path + "tri", mesh.vertices->getPoints().size(), path + "x", path + "y", path + "z" );
|
||||
// Write the variables
|
||||
for ( size_t i = 0; i < meshData.vars.size(); i++ ) {
|
||||
auto &var = *meshData.vars[i];
|
||||
auto data = var.data;
|
||||
auto rankType = Xdmf::RankType::Null;
|
||||
if ( data.ndim() == 1 ) {
|
||||
rankType = Xdmf::RankType::Scalar;
|
||||
} else if ( data.ndim() == 2 && data.size( 1 ) == 3 ) {
|
||||
// Vector data, need to permute for visit
|
||||
rankType = Xdmf::RankType::Vector;
|
||||
data = data.permute( { 1, 0 } );
|
||||
} else {
|
||||
ERROR( "Unable to determine variable rank: " + to_string( var.data.size() ) );
|
||||
}
|
||||
if ( var.precision == IO::DataType::Double ) {
|
||||
IO::HDF5::writeHDF5( gid, var.name, data );
|
||||
} else if ( var.precision == IO::DataType::Float ) {
|
||||
IO::HDF5::writeHDF5( gid, var.name, data.cloneTo<float>() );
|
||||
} else if ( var.precision == IO::DataType::Int ) {
|
||||
IO::HDF5::writeHDF5( gid, var.name, data.cloneTo<int>() );
|
||||
} else {
|
||||
ERROR( "Unsupported format" );
|
||||
}
|
||||
domain.addVariable(
|
||||
meshname, var.name, data.size(), rankType, getXdmfType( var.type ), path + var.name );
|
||||
}
|
||||
xmf.addMesh( meshData.meshName, domain );
|
||||
}
|
||||
static void writeHDF5TriMesh( hid_t fid, const std::string &filename,
|
||||
const IO::MeshDataStruct &meshData, IO::MeshDatabase database, Xdmf &xmf )
|
||||
{
|
||||
const IO::TriMesh &mesh = dynamic_cast<IO::TriMesh &>( *meshData.mesh );
|
||||
writeHDF5TriMesh2( fid, filename, meshData, mesh, database, xmf );
|
||||
}
|
||||
static void writeHDF5TriList( hid_t fid, const std::string &filename,
|
||||
const IO::MeshDataStruct &meshData, IO::MeshDatabase database, Xdmf &xmf )
|
||||
{
|
||||
auto mesh = getTriMesh( meshData.mesh );
|
||||
writeHDF5TriMesh2( fid, filename, meshData, *mesh, database, xmf );
|
||||
}
|
||||
// Write a DomainMesh mesh (and variables) to a file
|
||||
static void writeHDF5DomainMesh( hid_t fid, const std::string &filename,
|
||||
const IO::MeshDataStruct &meshData, IO::MeshDatabase database, Xdmf &xmf )
|
||||
{
|
||||
auto &mesh = dynamic_cast<IO::DomainMesh &>( *meshData.mesh );
|
||||
auto meshname = database.domains[0].name;
|
||||
auto gid = IO::HDF5::createGroup( fid, meshname );
|
||||
auto path = filename + ":/" + meshname + "/";
|
||||
// Write the mesh
|
||||
RankInfoStruct info( mesh.rank, mesh.nprocx, mesh.nprocy, mesh.nprocz );
|
||||
std::vector<double> range = { info.ix * mesh.Lx / info.nx, ( info.ix + 1 ) * mesh.Lx / info.nx,
|
||||
info.jy * mesh.Ly / info.ny, ( info.jy + 1 ) * mesh.Ly / info.ny,
|
||||
info.kz * mesh.Lz / info.nz, ( info.kz + 1 ) * mesh.Lz / info.nz };
|
||||
std::vector<int> N = { mesh.nx, mesh.ny, mesh.nz };
|
||||
std::vector<int> rankinfo = { mesh.rank, mesh.nprocx, mesh.nprocy, mesh.nprocz };
|
||||
IO::HDF5::writeHDF5( gid, "range", range );
|
||||
IO::HDF5::writeHDF5( gid, "N", N );
|
||||
IO::HDF5::writeHDF5( gid, "rankinfo", rankinfo );
|
||||
// xmf.addUniformMesh( meshname, range, ArraySize( N[0], N[1], N[2] ) );
|
||||
// Write a curvilinear mesh due to bug with vector data on nodes loading into visit
|
||||
Array<float> x( N[0] + 1, N[1] + 1, N[2] + 1 );
|
||||
Array<float> y( N[0] + 1, N[1] + 1, N[2] + 1 );
|
||||
Array<float> z( N[0] + 1, N[1] + 1, N[2] + 1 );
|
||||
double dx = ( range[1] - range[0] ) / N[0];
|
||||
double dy = ( range[3] - range[2] ) / N[1];
|
||||
double dz = ( range[5] - range[4] ) / N[2];
|
||||
for ( int k = 0; k <= N[2]; k++ ) {
|
||||
for ( int j = 0; j <= N[1]; j++ ) {
|
||||
for ( int i = 0; i <= N[0]; i++ ) {
|
||||
x( i, j, k ) = range[0] + dx * i;
|
||||
y( i, j, k ) = range[2] + dy * j;
|
||||
z( i, j, k ) = range[4] + dz * k;
|
||||
}
|
||||
}
|
||||
}
|
||||
IO::HDF5::writeHDF5( gid, "x", x );
|
||||
IO::HDF5::writeHDF5( gid, "y", y );
|
||||
IO::HDF5::writeHDF5( gid, "z", z );
|
||||
auto domain = Xdmf::createCurvilinearMesh(
|
||||
meshname, ArraySize( N[0], N[1], N[2] ), path + "x", path + "y", path + "z" );
|
||||
// Write the variables
|
||||
for ( size_t i = 0; i < meshData.vars.size(); i++ ) {
|
||||
auto &var = *meshData.vars[i];
|
||||
auto data = var.data;
|
||||
auto rankType = Xdmf::RankType::Null;
|
||||
if ( data.ndim() == 3 ) {
|
||||
rankType = Xdmf::RankType::Scalar;
|
||||
} else if ( data.ndim() == 4 && data.size( 3 ) == 3 ) {
|
||||
// Vector data, need to permute for visit
|
||||
rankType = Xdmf::RankType::Vector;
|
||||
data = data.permute( { 3, 0, 1, 2 } );
|
||||
} else {
|
||||
ERROR( "Unable to determine variable rank: " + to_string( var.data.size() ) );
|
||||
}
|
||||
if ( var.precision == IO::DataType::Double ) {
|
||||
IO::HDF5::writeHDF5( gid, var.name, data );
|
||||
} else if ( var.precision == IO::DataType::Float ) {
|
||||
IO::HDF5::writeHDF5( gid, var.name, data.cloneTo<float>() );
|
||||
} else if ( var.precision == IO::DataType::Int ) {
|
||||
IO::HDF5::writeHDF5( gid, var.name, data.cloneTo<int>() );
|
||||
} else {
|
||||
ERROR( "Unsupported format" );
|
||||
}
|
||||
domain.addVariable(
|
||||
meshname, var.name, data.size(), rankType, getXdmfType( var.type ), path + var.name );
|
||||
}
|
||||
IO::HDF5::closeGroup( gid );
|
||||
xmf.addMesh( meshData.meshName, domain );
|
||||
}
|
||||
// Write a mesh (and variables) to a file
|
||||
static IO::MeshDatabase write_domain_hdf5( hid_t fid, const std::string &filename,
|
||||
const IO::MeshDataStruct &mesh, IO::FileFormat format, int rank, Xdmf &xmf )
|
||||
{
|
||||
// Create the MeshDatabase
|
||||
auto database = getDatabase( filename, mesh, format, rank );
|
||||
if ( database.meshClass == "PointList" ) {
|
||||
writeHDF5PointList( fid, filename, mesh, database, xmf );
|
||||
} else if ( database.meshClass == "TriMesh" ) {
|
||||
writeHDF5TriMesh( fid, filename, mesh, database, xmf );
|
||||
} else if ( database.meshClass == "TriList" ) {
|
||||
writeHDF5TriList( fid, filename, mesh, database, xmf );
|
||||
} else if ( database.meshClass == "DomainMesh" ) {
|
||||
writeHDF5DomainMesh( fid, filename, mesh, database, xmf );
|
||||
} else {
|
||||
ERROR( "Unknown mesh class" );
|
||||
}
|
||||
return database;
|
||||
}
|
||||
// Write the mesh data to hdf5
|
||||
std::vector<IO::MeshDatabase> writeMeshesHDF5( const std::vector<IO::MeshDataStruct> &meshData,
|
||||
const std::string &path, IO::FileFormat format, int rank, Xdmf &xmf )
|
||||
{
|
||||
|
||||
std::vector<IO::MeshDatabase> meshes_written;
|
||||
char filename[100], fullpath[200];
|
||||
sprintf( filename, "%05i.h5", rank );
|
||||
sprintf( fullpath, "%s/%s", path.c_str(), filename );
|
||||
auto fid = IO::HDF5::openHDF5( fullpath, "w", IO::HDF5::Compression::GZIP );
|
||||
for ( size_t i = 0; i < meshData.size(); i++ ) {
|
||||
meshes_written.push_back(
|
||||
write_domain_hdf5( fid, filename, meshData[i], format, rank, xmf ) );
|
||||
}
|
||||
IO::HDF5::closeHDF5( fid );
|
||||
return meshes_written;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
std::vector<IO::MeshDatabase> writeMeshesHDF5(
|
||||
const std::vector<IO::MeshDataStruct> &, const std::string &, IO::FileFormat, int, Xdmf & )
|
||||
{
|
||||
return std::vector<IO::MeshDatabase>();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
585
IO/HDF5_IO.cpp
Normal file
585
IO/HDF5_IO.cpp
Normal file
|
@ -0,0 +1,585 @@
|
|||
#include "IO/HDF5_IO.h"
|
||||
#include "IO/HDF5_IO.hpp"
|
||||
#include "common/Array.h"
|
||||
#include "common/Utilities.h"
|
||||
|
||||
#include <complex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace IO {
|
||||
namespace HDF5 {
|
||||
|
||||
|
||||
#ifdef USE_HDF5 // USE HDF5
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* HDF5 helper routines *
|
||||
************************************************************************/
|
||||
inline const void *H5Ptr( const void *x ) { return x == nullptr ? ( (void *) 1 ) : x; }
|
||||
bool H5Gexists( hid_t fid, const std::string &name )
|
||||
{
|
||||
H5E_auto2_t func;
|
||||
void *client;
|
||||
H5Eget_auto2( H5E_DEFAULT, &func, &client );
|
||||
H5Eset_auto2( H5E_DEFAULT, nullptr, nullptr );
|
||||
int status = H5Gget_objinfo( fid, name.data(), 0, nullptr );
|
||||
H5Eset_auto2( H5E_DEFAULT, func, client );
|
||||
return status == 0;
|
||||
}
|
||||
bool H5Dexists( hid_t fid, const std::string &name )
|
||||
{
|
||||
H5E_auto2_t func;
|
||||
void *client;
|
||||
H5Eget_auto2( H5E_DEFAULT, &func, &client );
|
||||
H5Eset_auto2( H5E_DEFAULT, nullptr, nullptr );
|
||||
hid_t dataset = H5Dopen2( fid, name.data(), H5P_DEFAULT );
|
||||
H5Eset_auto2( H5E_DEFAULT, func, client );
|
||||
bool exists = dataset > 0;
|
||||
// if ( exists )
|
||||
// H5Dclose( dataset );
|
||||
return exists;
|
||||
}
|
||||
hid_t createGroup( hid_t fid, const std::string &name )
|
||||
{
|
||||
return H5Gcreate2( fid, name.data(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT );
|
||||
}
|
||||
hid_t openGroup( hid_t fid, const std::string &name )
|
||||
{
|
||||
INSIST( H5Gexists( fid, name ), "Group " + name + " does not exist" );
|
||||
return H5Gopen2( fid, name.data(), H5P_DEFAULT );
|
||||
}
|
||||
void closeGroup( hid_t gid ) { H5Gclose( gid ); }
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Complex struct that is compatible with HDF5 *
|
||||
************************************************************************/
|
||||
typedef struct {
|
||||
double re;
|
||||
double im;
|
||||
} complex_t;
|
||||
inline void convert( size_t N, const std::complex<double> *x, complex_t *y )
|
||||
{
|
||||
for ( size_t i = 0; i < N; i++ ) {
|
||||
y[i].re = x[i].real();
|
||||
y[i].im = x[i].imag();
|
||||
}
|
||||
}
|
||||
inline void convert( size_t N, const complex_t *x, std::complex<double> *y )
|
||||
{
|
||||
for ( size_t i = 0; i < N; i++ ) {
|
||||
y[i] = std::complex<double>( x[i].re, x[i].im );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Get the HDF5 data type *
|
||||
************************************************************************/
|
||||
template<>
|
||||
hid_t getHDF5datatype<bool>()
|
||||
{
|
||||
return H5Tcopy( H5T_NATIVE_UCHAR );
|
||||
}
|
||||
template<>
|
||||
hid_t getHDF5datatype<char>()
|
||||
{
|
||||
return H5Tcopy( H5T_NATIVE_CHAR );
|
||||
}
|
||||
template<>
|
||||
hid_t getHDF5datatype<uint8_t>()
|
||||
{
|
||||
return H5Tcopy( H5T_NATIVE_UINT8 );
|
||||
}
|
||||
template<>
|
||||
hid_t getHDF5datatype<int8_t>()
|
||||
{
|
||||
return H5Tcopy( H5T_NATIVE_INT8 );
|
||||
}
|
||||
template<>
|
||||
hid_t getHDF5datatype<uint16_t>()
|
||||
{
|
||||
return H5Tcopy( H5T_NATIVE_UINT16 );
|
||||
}
|
||||
template<>
|
||||
hid_t getHDF5datatype<int16_t>()
|
||||
{
|
||||
return H5Tcopy( H5T_NATIVE_INT16 );
|
||||
}
|
||||
template<>
|
||||
hid_t getHDF5datatype<int>()
|
||||
{
|
||||
return H5Tcopy( H5T_NATIVE_INT );
|
||||
}
|
||||
template<>
|
||||
hid_t getHDF5datatype<unsigned int>()
|
||||
{
|
||||
return H5Tcopy( H5T_NATIVE_UINT );
|
||||
}
|
||||
template<>
|
||||
hid_t getHDF5datatype<long int>()
|
||||
{
|
||||
return H5Tcopy( H5T_NATIVE_LONG );
|
||||
}
|
||||
template<>
|
||||
hid_t getHDF5datatype<unsigned long int>()
|
||||
{
|
||||
return H5Tcopy( H5T_NATIVE_ULONG );
|
||||
}
|
||||
template<>
|
||||
hid_t getHDF5datatype<float>()
|
||||
{
|
||||
return H5Tcopy( H5T_NATIVE_FLOAT );
|
||||
}
|
||||
template<>
|
||||
hid_t getHDF5datatype<double>()
|
||||
{
|
||||
return H5Tcopy( H5T_NATIVE_DOUBLE );
|
||||
}
|
||||
template<>
|
||||
hid_t getHDF5datatype<std::complex<double>>()
|
||||
{
|
||||
hid_t datatype = H5Tcreate( H5T_COMPOUND, sizeof( complex_t ) );
|
||||
H5Tinsert( datatype, "real", HOFFSET( complex_t, re ), H5T_NATIVE_DOUBLE );
|
||||
H5Tinsert( datatype, "imag", HOFFSET( complex_t, im ), H5T_NATIVE_DOUBLE );
|
||||
return datatype;
|
||||
}
|
||||
template<>
|
||||
hid_t getHDF5datatype<char *>()
|
||||
{
|
||||
hid_t datatype = H5Tcopy( H5T_C_S1 );
|
||||
H5Tset_size( datatype, H5T_VARIABLE );
|
||||
return datatype;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Read/write Array types *
|
||||
************************************************************************/
|
||||
template<>
|
||||
void readHDF5<Array<std::string>>( hid_t fid, const std::string &name, Array<std::string> &data )
|
||||
{
|
||||
if ( !H5Dexists( fid, name ) ) {
|
||||
// Dataset does not exist
|
||||
data.resize( 0 );
|
||||
return;
|
||||
}
|
||||
hid_t dataset = H5Dopen2( fid, name.data(), H5P_DEFAULT );
|
||||
hid_t datatype = H5Dget_type( dataset );
|
||||
hid_t dataspace = H5Dget_space( dataset );
|
||||
hsize_t dims0[10];
|
||||
int ndim = H5Sget_simple_extent_dims( dataspace, dims0, nullptr );
|
||||
auto dims = convertSize( ndim, dims0 );
|
||||
data.resize( dims );
|
||||
hid_t datatype2 = getHDF5datatype<char *>();
|
||||
if ( data.empty() ) {
|
||||
// The data is empty
|
||||
} else if ( H5Tequal( datatype, datatype2 ) ) {
|
||||
// The type of Array and the data in HDF5 match
|
||||
auto **tmp = new char *[data.length() * sizeof( char * )];
|
||||
memset( tmp, 0, data.length() * sizeof( char * ) );
|
||||
H5Dread( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, tmp );
|
||||
for ( size_t i = 0; i < data.length(); i++ )
|
||||
data( i ) = std::string( tmp[i] );
|
||||
H5Dvlen_reclaim( datatype, dataspace, H5P_DEFAULT, tmp );
|
||||
delete[] tmp;
|
||||
} else {
|
||||
ERROR( "Unknown format for std::string" );
|
||||
}
|
||||
H5Dclose( dataset );
|
||||
H5Tclose( datatype );
|
||||
H5Tclose( datatype2 );
|
||||
H5Sclose( dataspace );
|
||||
}
|
||||
template<>
|
||||
void readHDF5<Array<std::complex<double>>>(
|
||||
hid_t fid, const std::string &name, Array<std::complex<double>> &data )
|
||||
{
|
||||
if ( !H5Dexists( fid, name ) ) {
|
||||
// Dataset does not exist
|
||||
data.resize( 0 );
|
||||
return;
|
||||
}
|
||||
hid_t dataset = H5Dopen2( fid, name.data(), H5P_DEFAULT );
|
||||
hid_t datatype = H5Dget_type( dataset );
|
||||
hid_t dataspace = H5Dget_space( dataset );
|
||||
hsize_t dims0[10];
|
||||
int ndim = H5Sget_simple_extent_dims( dataspace, dims0, nullptr );
|
||||
auto dims = convertSize( ndim, dims0 );
|
||||
data.resize( dims );
|
||||
hid_t datatype2 = getHDF5datatype<std::complex<double>>();
|
||||
if ( data.empty() ) {
|
||||
// The data is empty
|
||||
} else if ( H5Tequal( datatype, datatype2 ) ) {
|
||||
// The type of Array and the data in HDF5 match
|
||||
H5Dread( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data.data() );
|
||||
} else {
|
||||
ERROR( "We need to convert data formats" );
|
||||
}
|
||||
H5Dclose( dataset );
|
||||
H5Tclose( datatype );
|
||||
H5Tclose( datatype2 );
|
||||
H5Sclose( dataspace );
|
||||
}
|
||||
// clang-format off
|
||||
#define readWriteHDF5Array( TYPE ) \
|
||||
template<> \
|
||||
void writeHDF5<Array<TYPE>>( hid_t fid, const std::string &name, const Array<TYPE> &data ) \
|
||||
{ \
|
||||
writeHDF5ArrayDefault<TYPE>( fid, name, data ); \
|
||||
} \
|
||||
template<> \
|
||||
void readHDF5<Array<TYPE>>( hid_t fid, const std::string &name, Array<TYPE> &data ) \
|
||||
{ \
|
||||
readHDF5ArrayDefault<TYPE>( fid, name, data ); \
|
||||
}
|
||||
readWriteHDF5Array( bool )
|
||||
readWriteHDF5Array( char )
|
||||
readWriteHDF5Array( int8_t )
|
||||
readWriteHDF5Array( int16_t )
|
||||
readWriteHDF5Array( int32_t )
|
||||
readWriteHDF5Array( int64_t )
|
||||
readWriteHDF5Array( uint8_t )
|
||||
readWriteHDF5Array( uint16_t )
|
||||
readWriteHDF5Array( uint32_t )
|
||||
readWriteHDF5Array( uint64_t )
|
||||
readWriteHDF5Array( float )
|
||||
readWriteHDF5Array( double )
|
||||
// clang-format on
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Read/write scalar types *
|
||||
************************************************************************/
|
||||
template<>
|
||||
void readHDF5<std::string>( hid_t fid, const std::string &name, std::string &data )
|
||||
{
|
||||
hid_t dataset = H5Dopen2( fid, name.data(), H5P_DEFAULT );
|
||||
hid_t datatype = H5Dget_type( dataset );
|
||||
hid_t datatype0 = getHDF5datatype<char *>();
|
||||
if ( H5Tequal( datatype, datatype0 ) ) {
|
||||
hid_t dataspace = H5Dget_space( dataset );
|
||||
char *tmp[1] = { nullptr };
|
||||
H5Dread( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, tmp );
|
||||
data = std::string( tmp[0] );
|
||||
H5Dvlen_reclaim( datatype, dataspace, H5P_DEFAULT, tmp );
|
||||
H5Sclose( dataspace );
|
||||
} else {
|
||||
Array<char> tmp;
|
||||
readHDF5( fid, name, tmp );
|
||||
data = std::string( tmp.data(), tmp.length() );
|
||||
}
|
||||
H5Dclose( dataset );
|
||||
H5Tclose( datatype );
|
||||
H5Tclose( datatype0 );
|
||||
}
|
||||
template<>
|
||||
void writeHDF5<std::string>( hid_t fid, const std::string &name, const std::string &data )
|
||||
{
|
||||
Array<char> tmp;
|
||||
tmp.viewRaw( { data.length() }, (char *) data.data() );
|
||||
writeHDF5( fid, name, tmp );
|
||||
}
|
||||
// clang-format off
|
||||
#define readWriteHDF5Scalar( TYPE ) \
|
||||
template<> \
|
||||
void writeHDF5<TYPE>( hid_t fid, const std::string &name, const TYPE &data ) \
|
||||
{ \
|
||||
hid_t dataspace = H5Screate( H5S_SCALAR ); \
|
||||
hid_t datatype = getHDF5datatype<TYPE>(); \
|
||||
hid_t dataset = H5Dcreate2( \
|
||||
fid, name.data(), datatype, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT ); \
|
||||
H5Dwrite( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, H5Ptr( &data ) ); \
|
||||
H5Dclose( dataset ); \
|
||||
H5Tclose( datatype ); \
|
||||
H5Sclose( dataspace ); \
|
||||
} \
|
||||
template<> \
|
||||
void readHDF5<TYPE>( hid_t fid, const std::string &name, TYPE &data ) \
|
||||
{ \
|
||||
Array<TYPE> tmp; \
|
||||
readHDF5( fid, name, tmp ); \
|
||||
INSIST( tmp.ndim() == 1 && tmp.length() == 1, "Error loading " + std::string( name ) ); \
|
||||
data = tmp( 0 ); \
|
||||
}
|
||||
readWriteHDF5Scalar( bool )
|
||||
readWriteHDF5Scalar( char )
|
||||
readWriteHDF5Scalar( int8_t )
|
||||
readWriteHDF5Scalar( int16_t )
|
||||
readWriteHDF5Scalar( int32_t )
|
||||
readWriteHDF5Scalar( int64_t )
|
||||
readWriteHDF5Scalar( uint8_t )
|
||||
readWriteHDF5Scalar( uint16_t )
|
||||
readWriteHDF5Scalar( uint32_t )
|
||||
readWriteHDF5Scalar( uint64_t )
|
||||
readWriteHDF5Scalar( float )
|
||||
readWriteHDF5Scalar( double )
|
||||
readWriteHDF5Scalar( std::complex<double> )
|
||||
// clang-format on
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Create custom error handler *
|
||||
******************************************************************/
|
||||
herr_t hdf5_error_handler( hid_t err_stack, void * )
|
||||
{
|
||||
FILE *fid = tmpfile();
|
||||
H5Eprint2( err_stack, fid );
|
||||
H5Eclear2( err_stack );
|
||||
rewind( fid );
|
||||
char msg[1024];
|
||||
size_t N = fread( msg, 1, sizeof( msg ) - 1, fid );
|
||||
fclose( fid );
|
||||
msg[N] = 0;
|
||||
std::string msg2 = "Error calling HDF5 routine:\n";
|
||||
ERROR( msg2 + msg );
|
||||
return 0;
|
||||
}
|
||||
bool set_hdf5_error_handler()
|
||||
{
|
||||
hid_t error_stack = 0;
|
||||
H5E_auto2_t fun = hdf5_error_handler;
|
||||
H5Eset_auto2( error_stack, fun, nullptr );
|
||||
return true;
|
||||
}
|
||||
bool global_is_hdf5_error_handler_set = set_hdf5_error_handler();
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Open/close HDF5 files *
|
||||
******************************************************************/
|
||||
hid_t openHDF5( const std::string &filename, const char *mode, Compression compress )
|
||||
{
|
||||
// Set cache size to 3MBs and instruct the cache to discard the fully read chunk
|
||||
auto pid = H5P_DEFAULT;
|
||||
/*auto pid = H5Pcreate( H5P_FILE_ACCESS );
|
||||
int nelemts;
|
||||
size_t nslots, nbytes;
|
||||
double w0;
|
||||
H5Pget_cache(pid,& nelemts,& nslots,& nbytes,& w0);
|
||||
H5Pset_cache(pid, nelemts, 1999, 3*1024*1024, 1.0); */
|
||||
// Open the file
|
||||
hid_t fid = 0;
|
||||
if ( strcmp( mode, "r" ) == 0 ) {
|
||||
fid = H5Fopen( filename.data(), H5F_ACC_RDONLY, pid );
|
||||
} else if ( strcmp( mode, "w" ) == 0 ) {
|
||||
fid = H5Fcreate( filename.data(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT );
|
||||
} else if ( strcmp( mode, "rw" ) == 0 ) {
|
||||
fid = H5Fopen( filename.data(), H5F_ACC_RDWR, H5P_DEFAULT );
|
||||
} else {
|
||||
ERROR( "Invalid mode for opening HDF5 file" );
|
||||
}
|
||||
if ( strcmp( mode, "w" ) == 0 ) {
|
||||
if ( compress == Compression::None ) {
|
||||
writeHDF5<int>( fid, "DefaultCompression", 0 );
|
||||
} else if ( compress == Compression::GZIP ) {
|
||||
writeHDF5<int>( fid, "DefaultCompression", 1 );
|
||||
} else if ( compress == Compression::SZIP ) {
|
||||
writeHDF5<int>( fid, "DefaultCompression", 2 );
|
||||
} else {
|
||||
ERROR( "Internal error" );
|
||||
}
|
||||
}
|
||||
// H5Pclose( pid );
|
||||
return fid;
|
||||
}
|
||||
void closeHDF5( hid_t fid )
|
||||
{
|
||||
// Try to close any remaining objects (needed to ensure we can reopen the data if desired)
|
||||
hid_t file[1000], set[1000], group[1000], type[1000], attr[1000];
|
||||
size_t N_file = H5Fget_obj_ids( fid, H5F_OBJ_FILE, 1000, file );
|
||||
size_t N_set = H5Fget_obj_ids( fid, H5F_OBJ_DATASET, 1000, set );
|
||||
size_t N_group = H5Fget_obj_ids( fid, H5F_OBJ_GROUP, 1000, group );
|
||||
size_t N_type = H5Fget_obj_ids( fid, H5F_OBJ_DATATYPE, 1000, type );
|
||||
size_t N_attr = H5Fget_obj_ids( fid, H5F_OBJ_ATTR, 1000, attr );
|
||||
for ( size_t i = 0; i < N_file; i++ ) {
|
||||
if ( file[i] != fid )
|
||||
H5Fclose( file[i] );
|
||||
}
|
||||
for ( size_t i = 0; i < N_set; i++ )
|
||||
H5Dclose( set[i] );
|
||||
for ( size_t i = 0; i < N_group; i++ )
|
||||
H5Gclose( group[i] );
|
||||
for ( size_t i = 0; i < N_type; i++ )
|
||||
H5Tclose( type[i] );
|
||||
for ( size_t i = 0; i < N_attr; i++ )
|
||||
H5Aclose( attr[i] );
|
||||
// Flush the data (needed to ensure we can reopen the data if desired)
|
||||
unsigned intent;
|
||||
H5Fget_intent( fid, &intent );
|
||||
if ( intent == H5F_ACC_RDWR || intent == H5F_ACC_TRUNC )
|
||||
H5Fflush( fid, H5F_SCOPE_GLOBAL );
|
||||
// Close the file
|
||||
H5Fclose( fid );
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Check if we support compression *
|
||||
************************************************************************/
|
||||
Compression defaultCompression( hid_t fid )
|
||||
{
|
||||
hid_t root = H5Gopen2( fid, "/", H5P_DEFAULT );
|
||||
if ( !H5Dexists( root, "DefaultCompression" ) )
|
||||
return Compression::None;
|
||||
int tmp;
|
||||
readHDF5( root, "DefaultCompression", tmp );
|
||||
Compression compress = Compression::None;
|
||||
if ( tmp == 0 ) {
|
||||
compress = Compression::None;
|
||||
} else if ( tmp == 1 ) {
|
||||
compress = Compression::GZIP;
|
||||
} else if ( tmp == 2 ) {
|
||||
compress = Compression::SZIP;
|
||||
} else {
|
||||
ERROR( "Internal error" );
|
||||
}
|
||||
return compress;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Create a default chunk size *
|
||||
************************************************************************/
|
||||
hid_t createChunk( const std::vector<hsize_t> &dims, Compression compress )
|
||||
{
|
||||
if ( compress == Compression::None || dims.empty() )
|
||||
return H5P_DEFAULT;
|
||||
hsize_t length = 1;
|
||||
for ( auto d : dims )
|
||||
length *= d;
|
||||
if ( length < 512 )
|
||||
return H5P_DEFAULT;
|
||||
hid_t plist = H5Pcreate( H5P_DATASET_CREATE );
|
||||
auto status = H5Pset_chunk( plist, dims.size(), dims.data() );
|
||||
ASSERT( status == 0 );
|
||||
if ( compress == Compression::GZIP ) {
|
||||
status = H5Pset_deflate( plist, 7 );
|
||||
ASSERT( status == 0 );
|
||||
} else if ( compress == Compression::SZIP ) {
|
||||
status = H5Pset_szip( plist, H5_SZIP_NN_OPTION_MASK, 16 );
|
||||
ASSERT( status == 0 );
|
||||
}
|
||||
return plist;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Write Array *
|
||||
************************************************************************/
|
||||
template<>
|
||||
void writeHDF5<Array<std::complex<double>>>(
|
||||
hid_t fid, const std::string &name, const Array<std::complex<double>> &data )
|
||||
{
|
||||
hid_t datatype = getHDF5datatype<std::complex<double>>();
|
||||
// Copy the data
|
||||
size_t N = data.length();
|
||||
auto *y = new complex_t[N];
|
||||
convert( N, data.data(), y );
|
||||
// Save the array
|
||||
auto dim = arraySize( data );
|
||||
hid_t dataspace = H5Screate_simple( dim.size(), dim.data(), nullptr );
|
||||
hid_t dataset =
|
||||
H5Dcreate2( fid, name.data(), datatype, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT );
|
||||
H5Dwrite( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, H5Ptr( y ) );
|
||||
H5Dclose( dataset );
|
||||
H5Tclose( datatype );
|
||||
H5Sclose( dataspace );
|
||||
delete[] y;
|
||||
}
|
||||
template<>
|
||||
void writeHDF5<Array<std::string>>(
|
||||
hid_t fid, const std::string &name, const Array<std::string> &data )
|
||||
{
|
||||
auto dim = arraySize( data );
|
||||
hid_t dataspace = H5Screate_simple( dim.size(), dim.data(), nullptr );
|
||||
auto **tmp = new char *[data.length() + 1];
|
||||
memset( tmp, 0, ( data.length() + 1 ) * sizeof( char * ) );
|
||||
for ( size_t i = 0; i < data.length(); i++ ) {
|
||||
tmp[i] = const_cast<char *>( data( i ).data() );
|
||||
}
|
||||
hid_t datatype = getHDF5datatype<char *>();
|
||||
hid_t props = H5Pcreate( H5P_DATASET_CREATE );
|
||||
hid_t dataset = H5Dcreate1( fid, name.data(), datatype, dataspace, props );
|
||||
H5Dwrite( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, tmp );
|
||||
H5Pclose( props );
|
||||
H5Dclose( dataset );
|
||||
H5Tclose( datatype );
|
||||
H5Sclose( dataspace );
|
||||
delete[] tmp;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Specializations for std::vector *
|
||||
************************************************************************/
|
||||
template<>
|
||||
void readHDF5<std::vector<bool>>( hid_t fid, const std::string &name, std::vector<bool> &data )
|
||||
{
|
||||
Array<bool> tmp;
|
||||
readHDF5( fid, name, tmp );
|
||||
data.resize( tmp.length() );
|
||||
for ( size_t i = 0; i < data.size(); i++ )
|
||||
data[i] = tmp( i );
|
||||
}
|
||||
template<>
|
||||
void writeHDF5<std::vector<bool>>( hid_t fid, const std::string &name, const std::vector<bool> &x )
|
||||
{
|
||||
Array<bool> y( x.size() );
|
||||
for ( size_t i = 0; i < x.size(); i++ )
|
||||
y( i ) = x[i];
|
||||
writeHDF5( fid, name, y );
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Explicit instantiations for std::vector *
|
||||
***********************************************************************/
|
||||
// clang-format off
|
||||
#define INSTANTIATE_STD_VECTOR( TYPE ) \
|
||||
template<> void readHDF5<std::vector<TYPE>>( hid_t fid, const std::string &name, std::vector<TYPE> &x ) \
|
||||
{ \
|
||||
Array<TYPE> y; \
|
||||
readHDF5( fid, name, y ); \
|
||||
x.resize( y.length() ); \
|
||||
for ( size_t i = 0; i < x.size(); i++ ) \
|
||||
x[i] = y( i ); \
|
||||
} \
|
||||
template<> void writeHDF5<std::vector<TYPE>>( hid_t fid, const std::string &name, const std::vector<TYPE> &x ) \
|
||||
{ \
|
||||
Array<TYPE> y; \
|
||||
y.viewRaw( { x.size() }, const_cast<TYPE*>( x.data() ) ); \
|
||||
writeHDF5( fid, name, y ); \
|
||||
}
|
||||
INSTANTIATE_STD_VECTOR( char )
|
||||
INSTANTIATE_STD_VECTOR( unsigned char )
|
||||
INSTANTIATE_STD_VECTOR( int )
|
||||
INSTANTIATE_STD_VECTOR( unsigned int )
|
||||
INSTANTIATE_STD_VECTOR( int16_t )
|
||||
INSTANTIATE_STD_VECTOR( uint16_t )
|
||||
INSTANTIATE_STD_VECTOR( int64_t )
|
||||
INSTANTIATE_STD_VECTOR( uint64_t )
|
||||
INSTANTIATE_STD_VECTOR( float )
|
||||
INSTANTIATE_STD_VECTOR( double )
|
||||
INSTANTIATE_STD_VECTOR( std::string )
|
||||
// clang-format on
|
||||
|
||||
|
||||
#else // No HDF5
|
||||
// Dummy implimentations for no HDF5
|
||||
hid_t openHDF5( const std::string &, const char *, Compression ) { return 0; }
|
||||
void closeHDF5( hid_t ) {}
|
||||
bool H5Gexists( hid_t, const std::string & ) { return false; }
|
||||
bool H5Dexists( hid_t, const std::string & ) { return false; }
|
||||
hid_t createGroup( hid_t, const std::string & ) { return 0; }
|
||||
hid_t openGroup( hid_t, const std::string & ) { return 0; }
|
||||
void closeGroup( hid_t ) {}
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace HDF5
|
||||
} // namespace IO
|
169
IO/HDF5_IO.h
Normal file
169
IO/HDF5_IO.h
Normal file
|
@ -0,0 +1,169 @@
|
|||
// This file contains helper functions and interfaces for reading/writing HDF5
|
||||
#ifndef included_HDF5_h
|
||||
#define included_HDF5_h
|
||||
|
||||
#include "common/ArraySize.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
|
||||
// Include the headers and define some basic types
|
||||
#ifdef USE_HDF5
|
||||
// Using HDF5
|
||||
#include "hdf5.h"
|
||||
#else
|
||||
// Not using HDF5
|
||||
typedef int hid_t;
|
||||
typedef size_t hsize_t;
|
||||
#endif
|
||||
|
||||
|
||||
namespace IO {
|
||||
namespace HDF5 {
|
||||
|
||||
|
||||
enum class Compression : uint8_t { None, GZIP, SZIP };
|
||||
|
||||
|
||||
/**
|
||||
* \brief Open an HDF5 file
|
||||
* \details This function opens and HDF5 file for reading/writing.
|
||||
* Once complete, we must close the file using closeHDF5
|
||||
* @param[in] filename File to open
|
||||
* @param[in] mode C string containing a file access mode. It can be:
|
||||
* "r" read: Open file for input operations. The file must exist.
|
||||
* "w" write: Create an empty file for output operations.
|
||||
* If a file with the same name already exists, its contents
|
||||
* are discarded and the file is treated as a new empty file.
|
||||
* "rw" read+write: Open file for reading and writing. The file must exist.
|
||||
* @param[in] compress Default compression
|
||||
* @return Return a handle to the file.
|
||||
*/
|
||||
hid_t openHDF5(
|
||||
const std::string &filename, const char *mode, Compression compress = Compression::None );
|
||||
|
||||
|
||||
/**
|
||||
* \brief Open an HDF5 file
|
||||
* \details This function opens and HDF5 file for reading/writing
|
||||
* @param[in] fid File to open
|
||||
*/
|
||||
void closeHDF5( hid_t fid );
|
||||
|
||||
|
||||
/**
|
||||
* \brief Retrun the the default compression
|
||||
* \details This function returns the default compression used when the file was created
|
||||
* @param[in] fid File/Group id
|
||||
*/
|
||||
Compression defaultCompression( hid_t fid );
|
||||
|
||||
|
||||
/**
|
||||
* \brief Open an HDF5 file
|
||||
* \details This function create a chunk for HDF5
|
||||
* @param[in] dims Chunk size
|
||||
* @param[in] compress Compression to use
|
||||
* @return Return a handle to the file.
|
||||
*/
|
||||
hid_t createChunk( const std::vector<hsize_t> &dims, Compression compress );
|
||||
|
||||
|
||||
/**
|
||||
* \brief Write a structure to HDF5
|
||||
* \details This function writes a C++ class/struct to HDF5.
|
||||
* This is a templated function and users can impliment their own data
|
||||
* types by creating explicit instantiations for a given type.
|
||||
* There is no default instantiation except when compiled without HDF5 which is a no-op.
|
||||
* @param[in] fid File or group to write to
|
||||
* @param[in] name The name of the variable
|
||||
* @param[in] data The structure to write
|
||||
*/
|
||||
template<class T>
|
||||
void writeHDF5( hid_t fid, const std::string &name, const T &data );
|
||||
|
||||
|
||||
/**
|
||||
* \brief Read a structure from HDF5
|
||||
* \details This function reads a C++ class/struct from HDF5.
|
||||
* This is a templated function and users can impliment their own data
|
||||
* types by creating explicit instantiations for a given type.
|
||||
* There is no default instantiation except when compiled without HDF5 which is a no-op.
|
||||
* @param[in] fid File or group to read from
|
||||
* @param[in] name The name of the variable
|
||||
* @param[out] data The structure to read
|
||||
*/
|
||||
template<class T>
|
||||
void readHDF5( hid_t fid, const std::string &name, T &data );
|
||||
|
||||
|
||||
/**
|
||||
* \brief Check if group exists
|
||||
* \details This function checks if an HDF5 group exists in the file
|
||||
* @param[in] fid ID of group or database to read
|
||||
* @param[in] name The name of the group
|
||||
*/
|
||||
bool H5Gexists( hid_t fid, const std::string &name );
|
||||
|
||||
|
||||
/**
|
||||
* \brief Check if dataset exists
|
||||
* \details This function checks if an HDF5 dataset exists in the file
|
||||
* @param[in] fid File to open
|
||||
* @param[in] name The name of the dataset
|
||||
*/
|
||||
bool H5Dexists( hid_t fid, const std::string &name );
|
||||
|
||||
|
||||
/**
|
||||
* \brief Create a group
|
||||
* \details This function creates a new HDF5 group
|
||||
* @param[in] fid File or group to write to
|
||||
* @param[in] name The name of the group
|
||||
*/
|
||||
hid_t createGroup( hid_t fid, const std::string &name );
|
||||
|
||||
|
||||
/**
|
||||
* \brief Open a group
|
||||
* \details This function opens an HDF5 group
|
||||
* @param[in] fid File or group to write to
|
||||
* @param[in] name The name of the group
|
||||
*/
|
||||
hid_t openGroup( hid_t fid, const std::string &name );
|
||||
|
||||
|
||||
/**
|
||||
* \brief Close a group
|
||||
* \details This function closes an HDF5 group
|
||||
* @param[in] fid Group to close
|
||||
*/
|
||||
void closeGroup( hid_t fid );
|
||||
|
||||
|
||||
/**
|
||||
* \brief Get HDF5 data type
|
||||
* \details This function returns the id of the data type
|
||||
*/
|
||||
template<class T>
|
||||
hid_t getHDF5datatype();
|
||||
|
||||
|
||||
// Default no-op implimentations for use without HDF5
|
||||
// clang-format off
|
||||
#ifndef USE_HDF5
|
||||
template<class T> void readHDF5( hid_t, const std::string&, T& ) {}
|
||||
template<class T> void writeHDF5( hid_t, const std::string&, const T& ) {}
|
||||
template<class T> void readHDF5Array( hid_t, const std::string&, Array<T>& ) {}
|
||||
template<class T> void writeHDF5Array( hid_t, const std::string&, const Array<T>& ) {}
|
||||
template<class T> hid_t getHDF5datatype() { return 0; }
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
|
||||
} // namespace HDF5
|
||||
} // namespace IO
|
||||
|
||||
|
||||
#endif
|
348
IO/HDF5_IO.hpp
Normal file
348
IO/HDF5_IO.hpp
Normal file
|
@ -0,0 +1,348 @@
|
|||
// This file contains helper functions and interfaces for reading/writing HDF5
|
||||
#ifndef included_HDF5_hpp
|
||||
#define included_HDF5_hpp
|
||||
#ifdef USE_HDF5
|
||||
|
||||
#include "IO/HDF5_IO.h"
|
||||
#include "common/Array.h"
|
||||
#include "common/Array.hpp"
|
||||
#include "common/Utilities.h"
|
||||
|
||||
#include <array>
|
||||
#include <complex>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace IO {
|
||||
namespace HDF5 {
|
||||
|
||||
|
||||
/********************************************************
|
||||
* External instantiations (scalar) *
|
||||
********************************************************/
|
||||
// clang-format off
|
||||
template<> void writeHDF5<char>( hid_t, const std::string &, const char & );
|
||||
template<> void readHDF5<char>( hid_t, const std::string &, char & );
|
||||
template<> void writeHDF5<bool>( hid_t, const std::string &, const bool & );
|
||||
template<> void readHDF5<bool>( hid_t, const std::string &, bool & );
|
||||
template<> void writeHDF5<int>( hid_t, const std::string &, const int & );
|
||||
template<> void readHDF5<int>( hid_t, const std::string &, int & );
|
||||
template<> void writeHDF5<long>( hid_t, const std::string &, const long & );
|
||||
template<> void readHDF5<long>( hid_t, const std::string &, long & );
|
||||
template<> void writeHDF5<float>( hid_t, const std::string &, const float & );
|
||||
template<> void readHDF5<float>( hid_t, const std::string &, float & );
|
||||
template<> void writeHDF5<double>( hid_t, const std::string &, const double & );
|
||||
template<> void readHDF5<double>( hid_t, const std::string &, double & );
|
||||
template<> void writeHDF5<unsigned char>( hid_t, const std::string &, const unsigned char & );
|
||||
template<> void readHDF5<unsigned char>( hid_t, const std::string &, unsigned char & );
|
||||
template<> void writeHDF5<unsigned int>( hid_t, const std::string &, const unsigned int & );
|
||||
template<> void readHDF5<unsigned int>( hid_t, const std::string &, unsigned int & );
|
||||
template<> void writeHDF5<unsigned long>( hid_t, const std::string &, const unsigned long & );
|
||||
template<> void readHDF5<unsigned long>( hid_t, const std::string &, unsigned long & );
|
||||
template<> void writeHDF5<std::string>( hid_t, const std::string &, const std::string & );
|
||||
template<> void readHDF5<std::string>( hid_t, const std::string &, std::string & );
|
||||
template<> void writeHDF5<std::complex<double>>( hid_t, const std::string &, const std::complex<double> & );
|
||||
template<> void readHDF5<std::complex<double>>( hid_t, const std::string &, std::complex<double> & );
|
||||
template<> void writeHDF5<std::complex<float>>( hid_t, const std::string &, const std::complex<float> & );
|
||||
template<> void readHDF5<std::complex<float>>( hid_t, const std::string &, std::complex<float> & );
|
||||
// clang-format on
|
||||
|
||||
|
||||
/********************************************************
|
||||
* External instantiations (Array) *
|
||||
********************************************************/
|
||||
// clang-format off
|
||||
template<> void writeHDF5<Array<char>>( hid_t, const std::string &, const Array<char> & );
|
||||
template<> void readHDF5<Array<char>>( hid_t, const std::string &, Array<char> & );
|
||||
template<> void writeHDF5<Array<bool>>( hid_t, const std::string &, const Array<bool> & );
|
||||
template<> void readHDF5<Array<bool>>( hid_t, const std::string &, Array<bool> & );
|
||||
template<> void writeHDF5<Array<int>>( hid_t, const std::string &, const Array<int> & );
|
||||
template<> void readHDF5<Array<int>>( hid_t, const std::string &, Array<int> & );
|
||||
template<> void writeHDF5<Array<long>>( hid_t, const std::string &, const Array<long> & );
|
||||
template<> void readHDF5<Array<long>>( hid_t, const std::string &, Array<long> & );
|
||||
template<> void writeHDF5<Array<float>>( hid_t, const std::string &, const Array<float> & );
|
||||
template<> void readHDF5<Array<float>>( hid_t, const std::string &, Array<float> & );
|
||||
template<> void writeHDF5<Array<double>>( hid_t, const std::string &, const Array<double> & );
|
||||
template<> void readHDF5<Array<double>>( hid_t, const std::string &, Array<double> & );
|
||||
template<> void writeHDF5<Array<unsigned char>>( hid_t, const std::string &, const Array<unsigned char> & );
|
||||
template<> void readHDF5<Array<unsigned char>>( hid_t, const std::string &, Array<unsigned char> & );
|
||||
template<> void writeHDF5<Array<unsigned int>>( hid_t, const std::string &, const Array<unsigned int> & );
|
||||
template<> void readHDF5<Array<unsigned int>>( hid_t, const std::string &, Array<unsigned int> & );
|
||||
template<> void writeHDF5<Array<unsigned long>>( hid_t, const std::string &, const Array<unsigned long> & );
|
||||
template<> void readHDF5<Array<unsigned long>>( hid_t, const std::string &, Array<unsigned long> & );
|
||||
template<> void writeHDF5<Array<std::string>>( hid_t, const std::string &, const Array<std::string> & );
|
||||
template<> void readHDF5<Array<std::string>>( hid_t, const std::string &, Array<std::string> & );
|
||||
template<> void writeHDF5<Array<std::string>>( hid_t, const std::string &, const Array<std::string> & );
|
||||
template<> void readHDF5<Array<std::string>>( hid_t, const std::string &, Array<std::string> & );
|
||||
template<> void writeHDF5<Array<std::complex<double>>>( hid_t, const std::string &, const Array<std::complex<double>> & );
|
||||
template<> void readHDF5<Array<std::complex<double>>>( hid_t, const std::string &, Array<std::complex<double>> & );
|
||||
template<> void writeHDF5<Array<std::complex<float>>>( hid_t, const std::string &, const Array<std::complex<float>> & );
|
||||
template<> void readHDF5<Array<std::complex<float>>>( hid_t, const std::string &, Array<std::complex<float>> & );
|
||||
// clang-format on
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Default implimentation *
|
||||
******************************************************************/
|
||||
/*template<class TYPE>
|
||||
void writeHDF5( hid_t fid, const std::string &name, const TYPE &x )
|
||||
{
|
||||
NULL_USE( fid );
|
||||
if constexpr ( is_shared_ptr<TYPE>::value ) {
|
||||
// We are dealing with a std::shared_ptr
|
||||
writeHDF5( fid, name, *x );
|
||||
} else if constexpr ( is_vector<TYPE>::value ) {
|
||||
// We are dealing with a std::vector
|
||||
typedef decltype( *x.begin() ) TYPE2;
|
||||
typedef typename std::remove_reference<TYPE2>::type TYPE3;
|
||||
typedef typename std::remove_cv<TYPE3>::type TYPE4;
|
||||
Array<TYPE4> y;
|
||||
y.viewRaw( { x.size() }, const_cast<TYPE4 *>( x.data() ) );
|
||||
writeHDF5( fid, name, y );
|
||||
} else if constexpr ( std::is_array<TYPE>::value ) {
|
||||
// We are dealing with a std::array
|
||||
typedef decltype( *x.begin() ) TYPE2;
|
||||
typedef typename std::remove_reference<TYPE2>::type TYPE3;
|
||||
typedef typename std::remove_cv<TYPE3>::type TYPE4;
|
||||
Array<TYPE4> y;
|
||||
y.viewRaw( { x.size() }, const_cast<TYPE4 *>( x.data() ) );
|
||||
writeHDF5( fid, name, y );
|
||||
} else if constexpr ( is_Array<TYPE>::value ) {
|
||||
// We are dealing with an Array
|
||||
std::string typeName = Utilities::demangle( typeid( TYPE ).name() );
|
||||
throw std::logic_error( "Unsupported type writeHDF5<Array<" + typeName + ">>" );
|
||||
} else if constexpr ( std::is_same<TYPE, std::string>::value ) {
|
||||
// We are dealing with a std::string (should be handled through specialization)
|
||||
throw std::logic_error( "Internal error" );
|
||||
} else if constexpr ( std::is_same<TYPE, std::string>::value ||
|
||||
std::is_same<TYPE, char *>::value ||
|
||||
std::is_same<TYPE, const char *>::value ) {
|
||||
// We are dealing with a string or char array
|
||||
writeHDF5( fid, name, std::string( x ) );
|
||||
} else if constexpr ( has_size<TYPE>::value ) {
|
||||
// We are dealing with a container
|
||||
typedef decltype( *x.begin() ) TYPE2;
|
||||
typedef typename std::remove_reference<TYPE2>::type TYPE3;
|
||||
typedef typename std::remove_cv<TYPE3>::type TYPE4;
|
||||
std::vector<TYPE4> x2( x.begin(), x.end() );
|
||||
writeHDF5<std::vector<TYPE4>>( fid, name, x2 );
|
||||
} else {
|
||||
throw std::logic_error( "Unsupported type" );
|
||||
}
|
||||
}
|
||||
template<class TYPE>
|
||||
void readHDF5( hid_t fid, const std::string &name, TYPE &x )
|
||||
{
|
||||
NULL_USE( fid );
|
||||
if constexpr ( is_shared_ptr<TYPE>::value ) {
|
||||
// We are dealing with a std::shared_ptr
|
||||
readHDF5( fid, name, *x );
|
||||
} else if constexpr ( is_vector<TYPE>::value ) {
|
||||
// We are dealing with a std::vector
|
||||
typedef typename std::remove_reference<decltype( *x.begin() )>::type TYPE2;
|
||||
Array<TYPE2> y;
|
||||
readHDF5( fid, name, y );
|
||||
x.resize( y.length() );
|
||||
// Swap the elements in the arrays to use the move operator
|
||||
for ( size_t i = 0; i < x.size(); i++ )
|
||||
std::swap( x[i], y( i ) );
|
||||
} else if constexpr ( std::is_array<TYPE>::value ) {
|
||||
// We are dealing with a std::array
|
||||
typedef typename std::remove_reference<decltype( *x.begin() )>::type TYPE2;
|
||||
Array<TYPE2> y;
|
||||
readHDF5( fid, name, y );
|
||||
ASSERT( y.length() == x.size() );
|
||||
// Swap the elements in the arrays to use the move operator
|
||||
for ( size_t i = 0; i < x.size(); i++ )
|
||||
std::swap( x[i], y( i ) );
|
||||
} else if constexpr ( is_Array<TYPE>::value ) {
|
||||
// We are dealing with an Array
|
||||
std::string typeName = Utilities::demangle( typeid( TYPE ).name() );
|
||||
throw std::logic_error( "Unsupported type readHDF5<Array<" + typeName + ">>" );
|
||||
} else if constexpr ( std::is_same<TYPE, std::string>::value ) {
|
||||
// We are dealing with a std::string (should be handled through specialization)
|
||||
throw std::logic_error( "Internal error" );
|
||||
} else if constexpr ( std::is_same<TYPE, std::string>::value ||
|
||||
std::is_same<TYPE, char *>::value ||
|
||||
std::is_same<TYPE, const char *>::value ) {
|
||||
// We are dealing with a string or char array
|
||||
throw std::logic_error(
|
||||
"Reading data into a string, char*, const char* is not supported" );
|
||||
} else if constexpr ( has_size<TYPE>::value ) {
|
||||
// We are dealing with a container
|
||||
typedef typename std::remove_reference<decltype( *x.begin() )>::type TYPE2;
|
||||
Array<TYPE2> y;
|
||||
readHDF5( fid, name, y );
|
||||
if ( x.size() == y.length() ) {
|
||||
auto it = x.begin();
|
||||
for ( size_t i = 0; i < y.length(); i++, ++it )
|
||||
*it = y( i );
|
||||
} else {
|
||||
throw std::logic_error( "Reading data into an arbitrary container is not finished" );
|
||||
}
|
||||
} else {
|
||||
throw std::logic_error( "Unsupported type" );
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Helper function to get the size of an Array *
|
||||
* Note that HDF5 uses C ordered arrays so we need to flip the dimensions*
|
||||
************************************************************************/
|
||||
template<class T>
|
||||
inline std::vector<hsize_t> arraySize( const Array<T> &x )
|
||||
{
|
||||
int N = x.ndim();
|
||||
auto s1 = x.size();
|
||||
std::vector<hsize_t> s2( std::max( N, 1 ), 0 );
|
||||
for ( int i = 0; i < N; i++ )
|
||||
s2[N - i - 1] = static_cast<hsize_t>( s1[i] );
|
||||
return s2;
|
||||
}
|
||||
inline std::vector<size_t> convertSize( int N, const hsize_t *dims )
|
||||
{
|
||||
if ( N == 0 )
|
||||
return std::vector<size_t>( 1, 1 );
|
||||
std::vector<size_t> size( N, 0 );
|
||||
for ( int i = 0; i < N; i++ )
|
||||
size[N - i - 1] = static_cast<size_t>( dims[i] );
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* readAndConvertHDF5Data *
|
||||
************************************************************************/
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_integral<T>::value || std::is_floating_point<T>::value, void>::type
|
||||
readAndConvertHDF5Data( hid_t dataset, hid_t datatype, Array<T> &data )
|
||||
{
|
||||
if ( H5Tequal( datatype, H5T_NATIVE_CHAR ) ) {
|
||||
Array<char> data2( data.size() );
|
||||
H5Dread( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data2.data() );
|
||||
data.copy( data2 );
|
||||
} else if ( H5Tequal( datatype, H5T_NATIVE_UCHAR ) ) {
|
||||
Array<unsigned char> data2( data.size() );
|
||||
H5Dread( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data2.data() );
|
||||
data.copy( data2 );
|
||||
} else if ( H5Tequal( datatype, H5T_NATIVE_INT8 ) ) {
|
||||
Array<int8_t> data2( data.size() );
|
||||
H5Dread( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data2.data() );
|
||||
data.copy( data2 );
|
||||
} else if ( H5Tequal( datatype, H5T_NATIVE_UINT8 ) ) {
|
||||
Array<uint8_t> data2( data.size() );
|
||||
H5Dread( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data2.data() );
|
||||
data.copy( data2 );
|
||||
} else if ( H5Tequal( datatype, H5T_NATIVE_INT ) ) {
|
||||
Array<int> data2( data.size() );
|
||||
H5Dread( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data2.data() );
|
||||
data.copy( data2 );
|
||||
} else if ( H5Tequal( datatype, H5T_NATIVE_UINT ) ) {
|
||||
Array<unsigned int> data2( data.size() );
|
||||
H5Dread( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data2.data() );
|
||||
data.copy( data2 );
|
||||
} else if ( H5Tequal( datatype, H5T_NATIVE_LONG ) ) {
|
||||
Array<long int> data2( data.size() );
|
||||
H5Dread( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data2.data() );
|
||||
data.copy( data2 );
|
||||
} else if ( H5Tequal( datatype, H5T_NATIVE_ULONG ) ) {
|
||||
Array<unsigned long int> data2( data.size() );
|
||||
H5Dread( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data2.data() );
|
||||
data.copy( data2 );
|
||||
} else if ( H5Tequal( datatype, H5T_NATIVE_FLOAT ) ) {
|
||||
Array<float> data2( data.size() );
|
||||
H5Dread( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data2.data() );
|
||||
data.copy( data2 );
|
||||
} else if ( H5Tequal( datatype, H5T_NATIVE_DOUBLE ) ) {
|
||||
Array<double> data2( data.size() );
|
||||
H5Dread( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data2.data() );
|
||||
data.copy( data2 );
|
||||
} else {
|
||||
ERROR( "We need to convert unknown data format" );
|
||||
}
|
||||
}
|
||||
template<class T>
|
||||
typename std::enable_if<!std::is_integral<T>::value && !std::is_floating_point<T>::value,
|
||||
void>::type
|
||||
readAndConvertHDF5Data( hid_t, hid_t, Array<T> & )
|
||||
{
|
||||
ERROR( "Unable to convert data" );
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Default writeHDF5Array *
|
||||
************************************************************************/
|
||||
template<class T>
|
||||
void writeHDF5ArrayDefault( hid_t fid, const std::string &name, const Array<T> &data )
|
||||
{
|
||||
size_t N_bytes = data.length() * sizeof( T );
|
||||
auto dim = arraySize( data );
|
||||
hid_t plist = H5P_DEFAULT;
|
||||
if ( N_bytes < 0x7500 ) {
|
||||
// Use compact storage (limited to < 30K)
|
||||
plist = H5Pcreate( H5P_DATASET_CREATE );
|
||||
auto status = H5Pset_layout( plist, H5D_COMPACT );
|
||||
ASSERT( status == 0 );
|
||||
} else if ( std::is_same<T, double>::value || std::is_same<T, float>::value ) {
|
||||
// Use compression if availible
|
||||
plist = createChunk( dim, defaultCompression( fid ) );
|
||||
}
|
||||
hid_t dataspace = H5Screate_simple( dim.size(), dim.data(), NULL );
|
||||
hid_t datatype = getHDF5datatype<T>();
|
||||
hid_t dataset =
|
||||
H5Dcreate2( fid, name.data(), datatype, dataspace, H5P_DEFAULT, plist, H5P_DEFAULT );
|
||||
const void *ptr = data.data() == NULL ? ( (void *) 1 ) : data.data();
|
||||
H5Dwrite( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, ptr );
|
||||
H5Dclose( dataset );
|
||||
H5Tclose( datatype );
|
||||
H5Sclose( dataspace );
|
||||
if ( plist != H5P_DEFAULT )
|
||||
H5Pclose( plist );
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Default readHDF5Array *
|
||||
************************************************************************/
|
||||
template<class T>
|
||||
void readHDF5ArrayDefault( hid_t fid, const std::string &name, Array<T> &data )
|
||||
{
|
||||
if ( !H5Dexists( fid, name ) ) {
|
||||
// Dataset does not exist
|
||||
data.resize( 0 );
|
||||
return;
|
||||
}
|
||||
hid_t dataset = H5Dopen2( fid, name.data(), H5P_DEFAULT );
|
||||
hid_t datatype = H5Dget_type( dataset );
|
||||
hid_t dataspace = H5Dget_space( dataset );
|
||||
hsize_t dims0[10];
|
||||
int ndim = H5Sget_simple_extent_dims( dataspace, dims0, NULL );
|
||||
auto dims = convertSize( ndim, dims0 );
|
||||
data.resize( dims );
|
||||
hid_t datatype2 = getHDF5datatype<T>();
|
||||
if ( data.empty() ) {
|
||||
// The data is empty
|
||||
} else if ( H5Tequal( datatype, datatype2 ) ) {
|
||||
// The type of Array and the data in HDF5 match
|
||||
H5Dread( dataset, datatype, H5S_ALL, H5S_ALL, H5P_DEFAULT, data.data() );
|
||||
} else {
|
||||
// Try to convert the data
|
||||
readAndConvertHDF5Data( dataset, datatype, data );
|
||||
}
|
||||
H5Dclose( dataset );
|
||||
H5Tclose( datatype );
|
||||
H5Tclose( datatype2 );
|
||||
H5Sclose( dataspace );
|
||||
}
|
||||
|
||||
|
||||
} // namespace HDF5
|
||||
} // namespace IO
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef IO_HELPERS_INC
|
||||
#define IO_HELPERS_INC
|
||||
|
||||
|
|
36
IO/Mesh.cpp
36
IO/Mesh.cpp
|
@ -1,3 +1,33 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "Mesh.h"
|
||||
#include "IO/IOHelpers.h"
|
||||
#include "common/Utilities.h"
|
||||
|
@ -133,7 +163,7 @@ size_t PointList::numberPointsVar( VariableType type ) const
|
|||
}
|
||||
std::pair<size_t, void *> PointList::pack( int level ) const
|
||||
{
|
||||
std::pair<size_t, void *> data_out( 0, NULL );
|
||||
std::pair<size_t, void *> data_out( 0, nullptr );
|
||||
if ( level == 0 ) {
|
||||
data_out.first = ( 2 + 3 * points.size() ) * sizeof( double );
|
||||
double *data_ptr = new double[2 + 3 * points.size()];
|
||||
|
@ -596,6 +626,8 @@ std::string getString( FileFormat type )
|
|||
return "new(single)";
|
||||
else if ( type == FileFormat::SILO )
|
||||
return "silo";
|
||||
else if ( type == FileFormat::HDF5 )
|
||||
return "hdf5";
|
||||
else
|
||||
ERROR( "Invalid type" );
|
||||
return "";
|
||||
|
@ -611,6 +643,8 @@ FileFormat getFileFormat( const std::string &type_in )
|
|||
return FileFormat::NEW_SINGLE;
|
||||
else if ( type == "silo" || type == "4" )
|
||||
return FileFormat::SILO;
|
||||
else if ( type == "hdf5" || type == "5" )
|
||||
return FileFormat::HDF5;
|
||||
else
|
||||
ERROR( "Invalid type: " + type );
|
||||
return FileFormat::SILO;
|
||||
|
|
17
IO/Mesh.h
17
IO/Mesh.h
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef MESH_INC
|
||||
#define MESH_INC
|
||||
|
||||
|
@ -24,7 +39,7 @@ enum class VariableType {
|
|||
};
|
||||
enum class DataType { Double, Float, Int, Null };
|
||||
enum class MeshType { PointMesh, SurfaceMesh, VolumeMesh, Unknown };
|
||||
enum class FileFormat { OLD, NEW, NEW_SINGLE, SILO };
|
||||
enum class FileFormat { OLD, NEW, NEW_SINGLE, SILO, HDF5 };
|
||||
|
||||
|
||||
//! Convert enums to/from strings (more future-proof than static_cast<int>)
|
||||
|
|
|
@ -1,3 +1,33 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "IO/MeshDatabase.h"
|
||||
#include "IO/IOHelpers.h"
|
||||
#include "IO/Mesh.h"
|
||||
|
@ -366,7 +396,7 @@ std::vector<MeshDatabase> read( const std::string &filename )
|
|||
PROFILE_START( "read" );
|
||||
FILE *fid = fopen( filename.c_str(), "rb" );
|
||||
if ( fid == NULL )
|
||||
ERROR( "Error opening file" );
|
||||
ERROR( "Error opening file: " + filename );
|
||||
char *line = new char[10000];
|
||||
while ( std::fgets( line, 1000, fid ) != NULL ) {
|
||||
if ( line[0] < 32 ) {
|
||||
|
|
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef MeshDatabase_INC
|
||||
#define MeshDatabase_INC
|
||||
|
||||
|
|
15
IO/PIO.cpp
15
IO/PIO.cpp
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "IO/PIO.h"
|
||||
#include "common/MPI.h"
|
||||
#include "common/Utilities.h"
|
||||
|
|
15
IO/PIO.h
15
IO/PIO.h
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef included_PIO
|
||||
#define included_PIO
|
||||
|
||||
|
|
30
IO/PIO.hpp
30
IO/PIO.hpp
|
@ -1,3 +1,33 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef included_PIO_hpp
|
||||
#define included_PIO_hpp
|
||||
|
||||
|
|
157
IO/Reader.cpp
157
IO/Reader.cpp
|
@ -1,13 +1,25 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "IO/Reader.h"
|
||||
#include "IO/HDF5_IO.h"
|
||||
#include "IO/IOHelpers.h"
|
||||
#include "IO/Mesh.h"
|
||||
#include "IO/MeshDatabase.h"
|
||||
#include "common/Utilities.h"
|
||||
|
||||
#ifdef USE_SILO
|
||||
#include "IO/silo.h"
|
||||
#endif
|
||||
|
||||
#include "common/Utilities.h"
|
||||
|
||||
#include <ProfilerApp.h>
|
||||
#include <cstdio>
|
||||
|
@ -62,14 +74,16 @@ std::vector<std::string> IO::readTimesteps( const std::string &path, const std::
|
|||
filename += "summary.LBM";
|
||||
} else if ( format == "silo" ) {
|
||||
filename += "LBM.visit";
|
||||
} else if ( format == "hdf5" ) {
|
||||
filename += "LBM.visit";
|
||||
} else if ( format == "auto" ) {
|
||||
bool test_old = fileExists( path + "/summary.LBM" );
|
||||
bool test_silo = fileExists( path + "/LBM.visit" );
|
||||
if ( test_old && test_silo ) {
|
||||
bool test_old = fileExists( path + "/summary.LBM" );
|
||||
bool test_new = fileExists( path + "/LBM.visit" );
|
||||
if ( test_old && test_new ) {
|
||||
ERROR( "Unable to determine format (both summary.LBM and LBM.visit exist)" );
|
||||
} else if ( test_old ) {
|
||||
filename += "summary.LBM";
|
||||
} else if ( test_silo ) {
|
||||
} else if ( test_new ) {
|
||||
filename += "LBM.visit";
|
||||
} else {
|
||||
ERROR( "Unable to determine format (neither summary.LBM or LBM.visit exist)" );
|
||||
|
@ -88,6 +102,9 @@ std::vector<std::string> IO::readTimesteps( const std::string &path, const std::
|
|||
std::string line( buf );
|
||||
line.resize( line.size() - 1 );
|
||||
auto pos = line.find( "summary.silo" );
|
||||
if ( pos != std::string::npos )
|
||||
line.resize( pos );
|
||||
pos = line.find( "summary.xmf" );
|
||||
if ( pos != std::string::npos )
|
||||
line.resize( pos );
|
||||
if ( line.empty() )
|
||||
|
@ -170,8 +187,8 @@ std::shared_ptr<IO::Mesh> IO::getMesh( const std::string &path, const std::strin
|
|||
if ( count % 3 != 0 )
|
||||
ERROR( "Error reading file" );
|
||||
if ( meshDatabase.type == IO::MeshType::PointMesh ) {
|
||||
size_t N = count / 3;
|
||||
std::shared_ptr<PointList> pointlist( new PointList( N ) );
|
||||
size_t N = count / 3;
|
||||
auto pointlist = std::make_shared<PointList>( N );
|
||||
std::vector<Point> &P = pointlist->points;
|
||||
for ( size_t i = 0; i < N; i++ ) {
|
||||
P[i].x = data[3 * i + 0];
|
||||
|
@ -182,8 +199,8 @@ std::shared_ptr<IO::Mesh> IO::getMesh( const std::string &path, const std::strin
|
|||
} else if ( meshDatabase.type == IO::MeshType::SurfaceMesh ) {
|
||||
if ( count % 9 != 0 )
|
||||
ERROR( "Error reading file (2)" );
|
||||
size_t N_tri = count / 9;
|
||||
std::shared_ptr<TriList> trilist( new TriList( N_tri ) );
|
||||
size_t N_tri = count / 9;
|
||||
auto trilist = std::make_shared<TriList>( N_tri );
|
||||
std::vector<Point> &A = trilist->A;
|
||||
std::vector<Point> &B = trilist->B;
|
||||
std::vector<Point> &C = trilist->C;
|
||||
|
@ -201,7 +218,7 @@ std::shared_ptr<IO::Mesh> IO::getMesh( const std::string &path, const std::strin
|
|||
mesh = trilist;
|
||||
} else if ( meshDatabase.type == IO::MeshType::VolumeMesh ) {
|
||||
// this was never supported in the old format
|
||||
mesh = std::shared_ptr<DomainMesh>( new DomainMesh() );
|
||||
mesh = std::make_shared<DomainMesh>();
|
||||
} else {
|
||||
ERROR( "Unknown mesh type" );
|
||||
}
|
||||
|
@ -222,13 +239,13 @@ std::shared_ptr<IO::Mesh> IO::getMesh( const std::string &path, const std::strin
|
|||
fclose( fid );
|
||||
ASSERT( count == bytes );
|
||||
if ( meshDatabase.meshClass == "PointList" ) {
|
||||
mesh.reset( new IO::PointList() );
|
||||
mesh = std::make_shared<IO::PointList>();
|
||||
} else if ( meshDatabase.meshClass == "TriMesh" ) {
|
||||
mesh.reset( new IO::TriMesh() );
|
||||
mesh = std::make_shared<IO::TriMesh>();
|
||||
} else if ( meshDatabase.meshClass == "TriList" ) {
|
||||
mesh.reset( new IO::TriList() );
|
||||
mesh = std::make_shared<IO::TriList>();
|
||||
} else if ( meshDatabase.meshClass == "DomainMesh" ) {
|
||||
mesh.reset( new IO::DomainMesh() );
|
||||
mesh = std::make_shared<IO::DomainMesh>();
|
||||
} else {
|
||||
ERROR( "Unknown mesh class" );
|
||||
}
|
||||
|
@ -243,7 +260,7 @@ std::shared_ptr<IO::Mesh> IO::getMesh( const std::string &path, const std::strin
|
|||
if ( meshDatabase.meshClass == "PointList" ) {
|
||||
Array<double> coords = silo::readPointMesh<double>( fid, database.name );
|
||||
ASSERT( coords.size( 1 ) == 3 );
|
||||
std::shared_ptr<IO::PointList> mesh2( new IO::PointList( coords.size( 0 ) ) );
|
||||
auto mesh2 = std::make_shared<IO::PointList>( coords.size( 0 ) );
|
||||
for ( size_t i = 0; i < coords.size( 1 ); i++ ) {
|
||||
mesh2->points[i].x = coords( i, 0 );
|
||||
mesh2->points[i].y = coords( i, 1 );
|
||||
|
@ -257,7 +274,7 @@ std::shared_ptr<IO::Mesh> IO::getMesh( const std::string &path, const std::strin
|
|||
ASSERT( tri.size( 1 ) == 3 && coords.size( 1 ) == 3 );
|
||||
int N_tri = tri.size( 0 );
|
||||
int N_point = coords.size( 0 );
|
||||
std::shared_ptr<IO::TriMesh> mesh2( new IO::TriMesh( N_tri, N_point ) );
|
||||
auto mesh2 = std::make_shared<IO::TriMesh>( N_tri, N_point );
|
||||
for ( int i = 0; i < N_point; i++ ) {
|
||||
mesh2->vertices->points[i].x = coords( i, 0 );
|
||||
mesh2->vertices->points[i].y = coords( i, 1 );
|
||||
|
@ -280,14 +297,81 @@ std::shared_ptr<IO::Mesh> IO::getMesh( const std::string &path, const std::strin
|
|||
silo::readUniformMesh( fid, database.name, range, N );
|
||||
auto rankinfo = silo::read<int>( fid, database.name + "_rankinfo" );
|
||||
RankInfoStruct rank_data( rankinfo[0], rankinfo[1], rankinfo[2], rankinfo[3] );
|
||||
mesh.reset( new IO::DomainMesh( rank_data, N[0], N[1], N[2], range[1] - range[0],
|
||||
range[3] - range[2], range[5] - range[4] ) );
|
||||
mesh = std::make_shared<IO::DomainMesh>( rank_data, N[0], N[1], N[2],
|
||||
range[1] - range[0], range[3] - range[2], range[5] - range[4] );
|
||||
} else {
|
||||
ERROR( "Unknown mesh class" );
|
||||
}
|
||||
silo::close( fid );
|
||||
#else
|
||||
ERROR( "Build without silo support" );
|
||||
#endif
|
||||
} else if ( meshDatabase.format == FileFormat::HDF5 ) {
|
||||
// Reading an hdf5 file
|
||||
#ifdef USE_HDF5
|
||||
auto &database = meshDatabase.domains[domain];
|
||||
auto filename = path + "/" + timestep + "/" + database.file;
|
||||
auto fid = IO::HDF5::openHDF5( filename, "r" );
|
||||
auto gid = IO::HDF5::openGroup( fid, database.name );
|
||||
if ( meshDatabase.meshClass == "PointList" ) {
|
||||
std::vector<double> x, y, z;
|
||||
IO::HDF5::readHDF5( gid, "x", x );
|
||||
IO::HDF5::readHDF5( gid, "y", y );
|
||||
IO::HDF5::readHDF5( gid, "z", z );
|
||||
ASSERT( y.size() == x.size() && z.size() == x.size() );
|
||||
auto mesh2 = std::make_shared<IO::PointList>( x.size() );
|
||||
for ( size_t i = 0; i < x.size(); i++ ) {
|
||||
mesh2->points[i].x = x[i];
|
||||
mesh2->points[i].y = y[i];
|
||||
mesh2->points[i].z = z[i];
|
||||
}
|
||||
mesh = mesh2;
|
||||
} else if ( meshDatabase.meshClass == "TriMesh" || meshDatabase.meshClass == "TriList" ) {
|
||||
// Read the points
|
||||
std::vector<double> x, y, z;
|
||||
IO::HDF5::readHDF5( gid, "x", x );
|
||||
IO::HDF5::readHDF5( gid, "y", y );
|
||||
IO::HDF5::readHDF5( gid, "z", z );
|
||||
// Read the triangles
|
||||
Array<int> tri;
|
||||
IO::HDF5::readHDF5( gid, "tri", tri );
|
||||
ASSERT( tri.size( 0 ) == 3 );
|
||||
size_t N_tri = tri.size( 1 );
|
||||
size_t N_point = x.size();
|
||||
auto mesh2 = std::make_shared<IO::TriMesh>( N_tri, N_point );
|
||||
for ( size_t i = 0; i < N_point; i++ ) {
|
||||
mesh2->vertices->points[i].x = x[i];
|
||||
mesh2->vertices->points[i].y = y[i];
|
||||
mesh2->vertices->points[i].z = z[i];
|
||||
}
|
||||
for ( size_t i = 0; i < N_tri; i++ ) {
|
||||
mesh2->A[i] = tri( 0, i );
|
||||
mesh2->B[i] = tri( 1, i );
|
||||
mesh2->C[i] = tri( 2, i );
|
||||
}
|
||||
if ( meshDatabase.meshClass == "TriMesh" ) {
|
||||
mesh = mesh2;
|
||||
} else if ( meshDatabase.meshClass == "TriList" ) {
|
||||
auto trilist = IO::getTriList( std::dynamic_pointer_cast<IO::Mesh>( mesh2 ) );
|
||||
mesh = trilist;
|
||||
}
|
||||
} else if ( meshDatabase.meshClass == "DomainMesh" ) {
|
||||
std::vector<double> range;
|
||||
std::vector<int> N;
|
||||
std::vector<int> rankinfo;
|
||||
IO::HDF5::readHDF5( gid, "range", range );
|
||||
IO::HDF5::readHDF5( gid, "N", N );
|
||||
IO::HDF5::readHDF5( gid, "rankinfo", rankinfo );
|
||||
RankInfoStruct rank_data( rankinfo[0], rankinfo[1], rankinfo[2], rankinfo[3] );
|
||||
mesh = std::make_shared<IO::DomainMesh>( rank_data, N[0], N[1], N[2],
|
||||
range[1] - range[0], range[3] - range[2], range[5] - range[4] );
|
||||
} else {
|
||||
ERROR( "Unknown mesh class" );
|
||||
}
|
||||
IO::HDF5::closeGroup( gid );
|
||||
IO::HDF5::closeHDF5( fid );
|
||||
#else
|
||||
ERROR( "Build without hdf5 support" );
|
||||
#endif
|
||||
} else {
|
||||
ERROR( "Unknown format" );
|
||||
|
@ -322,7 +406,7 @@ std::shared_ptr<IO::Variable> IO::getVariable( const std::string &path, const st
|
|||
size_t N = atol( values[2].c_str() );
|
||||
size_t bytes = atol( values[3].c_str() );
|
||||
std::string precision = values[4];
|
||||
var = std::shared_ptr<IO::Variable>( new IO::Variable() );
|
||||
var = std::make_shared<IO::Variable>();
|
||||
var->dim = dim;
|
||||
var->type = getVariableType( type );
|
||||
var->name = variable;
|
||||
|
@ -341,7 +425,7 @@ std::shared_ptr<IO::Variable> IO::getVariable( const std::string &path, const st
|
|||
auto variableDatabase = meshDatabase.getVariableDatabase( variable );
|
||||
std::string filename = path + "/" + timestep + "/" + database.file;
|
||||
auto fid = silo::open( filename, silo::READ );
|
||||
var.reset( new Variable( variableDatabase.dim, variableDatabase.type, variable ) );
|
||||
var = std::make_shared<Variable>( variableDatabase.dim, variableDatabase.type, variable );
|
||||
if ( meshDatabase.meshClass == "PointList" ) {
|
||||
var->data = silo::readPointMeshVariable<double>( fid, variable );
|
||||
} else if ( meshDatabase.meshClass == "TriMesh" || meshDatabase.meshClass == "TriList" ) {
|
||||
|
@ -355,7 +439,30 @@ std::shared_ptr<IO::Variable> IO::getVariable( const std::string &path, const st
|
|||
#else
|
||||
ERROR( "Build without silo support" );
|
||||
#endif
|
||||
|
||||
} else if ( meshDatabase.format == FileFormat::HDF5 ) {
|
||||
// Reading an hdf5 file
|
||||
#ifdef USE_HDF5
|
||||
auto &database = meshDatabase.domains[domain];
|
||||
auto varDatabase = meshDatabase.getVariableDatabase( variable );
|
||||
auto filename = path + "/" + timestep + "/" + database.file;
|
||||
var = std::make_shared<Variable>( varDatabase.dim, varDatabase.type, variable );
|
||||
auto fid = IO::HDF5::openHDF5( filename, "r" );
|
||||
auto gid = IO::HDF5::openGroup( fid, database.name );
|
||||
IO::HDF5::readHDF5( gid, var->name, var->data );
|
||||
IO::HDF5::closeHDF5( fid );
|
||||
if ( meshDatabase.meshClass == "PointList" || meshDatabase.meshClass == "TriMesh" ||
|
||||
meshDatabase.meshClass == "TriList" ) {
|
||||
if ( var->data.ndim() == 2 && var->data.size( 0 ) == 3 )
|
||||
var->data = var->data.permute( { 1, 0 } );
|
||||
} else if ( meshDatabase.meshClass == "DomainMesh" ) {
|
||||
if ( var->data.ndim() == 4 && var->data.size( 0 ) == 3 )
|
||||
var->data = var->data.permute( { 1, 2, 3, 0 } );
|
||||
} else {
|
||||
ERROR( "Unknown mesh class" );
|
||||
}
|
||||
#else
|
||||
ERROR( "Build without silo support" );
|
||||
#endif
|
||||
} else {
|
||||
ERROR( "Unknown format" );
|
||||
}
|
||||
|
|
17
IO/Reader.h
17
IO/Reader.h
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef READER_INC
|
||||
#define READER_INC
|
||||
|
||||
|
@ -87,7 +102,7 @@ std::shared_ptr<IO::Variable> getVariable( const std::string &path, const std::s
|
|||
* @brief Reformat the variable to match the mesh
|
||||
* @details This function modifies the dimensions of the array to match the mesh
|
||||
* @param[in] mesh The underlying mesh
|
||||
* @param[in/out] variable The variable name to read
|
||||
* @param[in,out] var The variable name to read
|
||||
*/
|
||||
void reformatVariable( const IO::Mesh &mesh, IO::Variable &var );
|
||||
|
||||
|
|
253
IO/SiloWriter.cpp
Normal file
253
IO/SiloWriter.cpp
Normal file
|
@ -0,0 +1,253 @@
|
|||
#include "IO/HDF5_IO.h"
|
||||
#include "IO/IOHelpers.h"
|
||||
#include "IO/MeshDatabase.h"
|
||||
#include "IO/Writer.h"
|
||||
#include "IO/silo.h"
|
||||
#include "common/MPI.h"
|
||||
#include "common/Utilities.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <sys/stat.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#ifdef USE_SILO
|
||||
|
||||
|
||||
// Write a PointList mesh (and variables) to a file
|
||||
template<class TYPE>
|
||||
static void writeSiloPointMesh(
|
||||
DBfile *fid, const IO::PointList &mesh, const std::string &meshname )
|
||||
{
|
||||
const auto &points = mesh.getPoints();
|
||||
std::vector<TYPE> x( points.size() ), y( points.size() ), z( points.size() );
|
||||
for ( size_t i = 0; i < x.size(); i++ ) {
|
||||
x[i] = points[i].x;
|
||||
y[i] = points[i].y;
|
||||
z[i] = points[i].z;
|
||||
}
|
||||
const TYPE *coords[] = { x.data(), y.data(), z.data() };
|
||||
IO::silo::writePointMesh<TYPE>( fid, meshname, 3, points.size(), coords );
|
||||
}
|
||||
static void writeSiloPointList(
|
||||
DBfile *fid, const IO::MeshDataStruct &meshData, IO::MeshDatabase database )
|
||||
{
|
||||
const IO::PointList &mesh = dynamic_cast<IO::PointList &>( *meshData.mesh );
|
||||
const std::string meshname = database.domains[0].name;
|
||||
if ( meshData.precision == IO::DataType::Double ) {
|
||||
writeSiloPointMesh<double>( fid, mesh, meshname );
|
||||
} else if ( meshData.precision == IO::DataType::Float ) {
|
||||
writeSiloPointMesh<float>( fid, mesh, meshname );
|
||||
} else {
|
||||
ERROR( "Unsupported format" );
|
||||
}
|
||||
const auto &points = mesh.getPoints();
|
||||
std::vector<double> x( points.size() ), y( points.size() ), z( points.size() );
|
||||
for ( size_t i = 0; i < x.size(); i++ ) {
|
||||
x[i] = points[i].x;
|
||||
y[i] = points[i].y;
|
||||
z[i] = points[i].z;
|
||||
}
|
||||
const double *coords[] = { x.data(), y.data(), z.data() };
|
||||
IO::silo::writePointMesh( fid, meshname, 3, points.size(), coords );
|
||||
for ( size_t i = 0; i < meshData.vars.size(); i++ ) {
|
||||
const IO::Variable &var = *meshData.vars[i];
|
||||
if ( var.precision == IO::DataType::Double ) {
|
||||
IO::silo::writePointMeshVariable( fid, meshname, var.name, var.data );
|
||||
} else if ( var.precision == IO::DataType::Float ) {
|
||||
Array<float> data2( var.data.size() );
|
||||
data2.copy( var.data );
|
||||
IO::silo::writePointMeshVariable( fid, meshname, var.name, data2 );
|
||||
} else if ( var.precision == IO::DataType::Int ) {
|
||||
Array<int> data2( var.data.size() );
|
||||
data2.copy( var.data );
|
||||
IO::silo::writePointMeshVariable( fid, meshname, var.name, data2 );
|
||||
} else {
|
||||
ERROR( "Unsupported format" );
|
||||
}
|
||||
}
|
||||
}
|
||||
// Write a TriMesh mesh (and variables) to a file
|
||||
template<class TYPE>
|
||||
static void writeSiloTriMesh( DBfile *fid, const IO::TriMesh &mesh, const std::string &meshname )
|
||||
{
|
||||
const auto &points = mesh.vertices->getPoints();
|
||||
std::vector<TYPE> x( points.size() ), y( points.size() ), z( points.size() );
|
||||
for ( size_t i = 0; i < x.size(); i++ ) {
|
||||
x[i] = points[i].x;
|
||||
y[i] = points[i].y;
|
||||
z[i] = points[i].z;
|
||||
}
|
||||
const TYPE *coords[] = { x.data(), y.data(), z.data() };
|
||||
const int *tri[] = { mesh.A.data(), mesh.B.data(), mesh.C.data() };
|
||||
IO::silo::writeTriMesh<TYPE>( fid, meshname, 3, 2, points.size(), coords, mesh.A.size(), tri );
|
||||
}
|
||||
static void writeSiloTriMesh2( DBfile *fid, const IO::MeshDataStruct &meshData,
|
||||
const IO::TriMesh &mesh, IO::MeshDatabase database )
|
||||
{
|
||||
const std::string meshname = database.domains[0].name;
|
||||
if ( meshData.precision == IO::DataType::Double ) {
|
||||
writeSiloTriMesh<double>( fid, mesh, meshname );
|
||||
} else if ( meshData.precision == IO::DataType::Float ) {
|
||||
writeSiloTriMesh<float>( fid, mesh, meshname );
|
||||
} else {
|
||||
ERROR( "Unsupported format" );
|
||||
}
|
||||
for ( size_t i = 0; i < meshData.vars.size(); i++ ) {
|
||||
const IO::Variable &var = *meshData.vars[i];
|
||||
if ( var.precision == IO::DataType::Double ) {
|
||||
IO::silo::writeTriMeshVariable( fid, 3, meshname, var.name, var.data, var.type );
|
||||
} else if ( var.precision == IO::DataType::Float ) {
|
||||
Array<float> data2( var.data.size() );
|
||||
data2.copy( var.data );
|
||||
IO::silo::writeTriMeshVariable( fid, 3, meshname, var.name, data2, var.type );
|
||||
} else if ( var.precision == IO::DataType::Int ) {
|
||||
Array<int> data2( var.data.size() );
|
||||
data2.copy( var.data );
|
||||
IO::silo::writeTriMeshVariable( fid, 3, meshname, var.name, data2, var.type );
|
||||
} else {
|
||||
ERROR( "Unsupported format" );
|
||||
}
|
||||
}
|
||||
}
|
||||
static void writeSiloTriMesh(
|
||||
DBfile *fid, const IO::MeshDataStruct &meshData, IO::MeshDatabase database )
|
||||
{
|
||||
const IO::TriMesh &mesh = dynamic_cast<IO::TriMesh &>( *meshData.mesh );
|
||||
writeSiloTriMesh2( fid, meshData, mesh, database );
|
||||
}
|
||||
static void writeSiloTriList(
|
||||
DBfile *fid, const IO::MeshDataStruct &meshData, IO::MeshDatabase database )
|
||||
{
|
||||
auto mesh = getTriMesh( meshData.mesh );
|
||||
writeSiloTriMesh2( fid, meshData, *mesh, database );
|
||||
}
|
||||
// Write a DomainMesh mesh (and variables) to a file
|
||||
static void writeSiloDomainMesh(
|
||||
DBfile *fid, const IO::MeshDataStruct &meshData, IO::MeshDatabase database )
|
||||
{
|
||||
const IO::DomainMesh &mesh = dynamic_cast<IO::DomainMesh &>( *meshData.mesh );
|
||||
RankInfoStruct info( mesh.rank, mesh.nprocx, mesh.nprocy, mesh.nprocz );
|
||||
std::array<double, 6> range = { info.ix * mesh.Lx / info.nx,
|
||||
( info.ix + 1 ) * mesh.Lx / info.nx, info.jy * mesh.Ly / info.ny,
|
||||
( info.jy + 1 ) * mesh.Ly / info.ny, info.kz * mesh.Lz / info.nz,
|
||||
( info.kz + 1 ) * mesh.Lz / info.nz };
|
||||
std::array<int, 3> N = { mesh.nx, mesh.ny, mesh.nz };
|
||||
auto meshname = database.domains[0].name;
|
||||
IO::silo::writeUniformMesh<3>( fid, meshname, range, N );
|
||||
IO::silo::write<int>(
|
||||
fid, meshname + "_rankinfo", { mesh.rank, mesh.nprocx, mesh.nprocy, mesh.nprocz } );
|
||||
for ( size_t i = 0; i < meshData.vars.size(); i++ ) {
|
||||
const auto &var = *meshData.vars[i];
|
||||
if ( var.precision == IO::DataType::Double ) {
|
||||
IO::silo::writeUniformMeshVariable<3>( fid, meshname, N, var.name, var.data, var.type );
|
||||
} else if ( var.precision == IO::DataType::Float ) {
|
||||
Array<float> data2( var.data.size() );
|
||||
data2.copy( var.data );
|
||||
IO::silo::writeUniformMeshVariable<3>( fid, meshname, N, var.name, data2, var.type );
|
||||
} else if ( var.precision == IO::DataType::Int ) {
|
||||
Array<int> data2( var.data.size() );
|
||||
data2.copy( var.data );
|
||||
IO::silo::writeUniformMeshVariable<3>( fid, meshname, N, var.name, data2, var.type );
|
||||
} else {
|
||||
ERROR( "Unsupported format" );
|
||||
}
|
||||
}
|
||||
}
|
||||
// Write a mesh (and variables) to a file
|
||||
static IO::MeshDatabase write_domain_silo( DBfile *fid, const std::string &filename,
|
||||
const IO::MeshDataStruct &mesh, IO::FileFormat format, int rank )
|
||||
{
|
||||
// Create the MeshDatabase
|
||||
auto database = getDatabase( filename, mesh, format, rank );
|
||||
if ( database.meshClass == "PointList" ) {
|
||||
writeSiloPointList( fid, mesh, database );
|
||||
} else if ( database.meshClass == "TriMesh" ) {
|
||||
writeSiloTriMesh( fid, mesh, database );
|
||||
} else if ( database.meshClass == "TriList" ) {
|
||||
writeSiloTriList( fid, mesh, database );
|
||||
} else if ( database.meshClass == "DomainMesh" ) {
|
||||
writeSiloDomainMesh( fid, mesh, database );
|
||||
} else {
|
||||
ERROR( "Unknown mesh class" );
|
||||
}
|
||||
return database;
|
||||
}
|
||||
// Write the summary file for silo
|
||||
std::pair<int, int> getSiloMeshType( const std::string &meshClass )
|
||||
{
|
||||
int meshType = 0;
|
||||
int varType = 0;
|
||||
if ( meshClass == "PointList" ) {
|
||||
meshType = DB_POINTMESH;
|
||||
varType = DB_POINTVAR;
|
||||
} else if ( meshClass == "TriMesh" ) {
|
||||
meshType = DB_UCDMESH;
|
||||
varType = DB_UCDVAR;
|
||||
} else if ( meshClass == "TriList" ) {
|
||||
meshType = DB_UCDMESH;
|
||||
varType = DB_UCDVAR;
|
||||
} else if ( meshClass == "DomainMesh" ) {
|
||||
meshType = DB_QUAD_RECT;
|
||||
varType = DB_QUADVAR;
|
||||
} else {
|
||||
ERROR( "Unknown mesh class" );
|
||||
}
|
||||
return std::make_pair( meshType, varType );
|
||||
}
|
||||
void writeSiloSummary(
|
||||
const std::vector<IO::MeshDatabase> &meshes_written, const std::string &filename )
|
||||
{
|
||||
auto fid = IO::silo::open( filename, IO::silo::CREATE );
|
||||
for ( const auto &data : meshes_written ) {
|
||||
auto type = getSiloMeshType( data.meshClass );
|
||||
std::vector<int> meshTypes( data.domains.size(), type.first );
|
||||
std::vector<int> varTypes( data.domains.size(), type.second );
|
||||
std::vector<std::string> meshNames;
|
||||
for ( const auto &tmp : data.domains )
|
||||
meshNames.push_back( tmp.file + ":" + tmp.name );
|
||||
IO::silo::writeMultiMesh( fid, data.name, meshNames, meshTypes );
|
||||
for ( const auto &variable : data.variables ) {
|
||||
std::vector<std::string> varnames;
|
||||
for ( const auto &tmp : data.domains )
|
||||
varnames.push_back( tmp.file + ":" + variable.name );
|
||||
IO::silo::writeMultiVar( fid, variable.name, varnames, varTypes );
|
||||
}
|
||||
}
|
||||
IO::silo::close( fid );
|
||||
}
|
||||
// Write the mesh data to silo
|
||||
std::vector<IO::MeshDatabase> writeMeshesSilo( const std::vector<IO::MeshDataStruct> &meshData,
|
||||
const std::string &path, IO::FileFormat format, int rank )
|
||||
{
|
||||
std::vector<IO::MeshDatabase> meshes_written;
|
||||
char filename[100], fullpath[200];
|
||||
sprintf( filename, "%05i.silo", rank );
|
||||
sprintf( fullpath, "%s/%s", path.c_str(), filename );
|
||||
auto fid = IO::silo::open( fullpath, IO::silo::CREATE );
|
||||
for ( size_t i = 0; i < meshData.size(); i++ ) {
|
||||
auto mesh = meshData[i].mesh;
|
||||
meshes_written.push_back( write_domain_silo( fid, filename, meshData[i], format, rank ) );
|
||||
}
|
||||
IO::silo::close( fid );
|
||||
return meshes_written;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
// Write the mesh data to silo
|
||||
std::vector<IO::MeshDatabase> writeMeshesSilo(
|
||||
const std::vector<IO::MeshDataStruct> &, const std::string &, IO::FileFormat, int )
|
||||
{
|
||||
return std::vector<IO::MeshDatabase>();
|
||||
}
|
||||
void writeSiloSummary( const std::vector<IO::MeshDatabase> &, const std::string & )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
#endif
|
312
IO/Writer.cpp
312
IO/Writer.cpp
|
@ -1,10 +1,28 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "IO/Writer.h"
|
||||
#include "IO/HDF5_IO.h"
|
||||
#include "IO/IOHelpers.h"
|
||||
#include "IO/MeshDatabase.h"
|
||||
#include "IO/silo.h"
|
||||
#include "IO/Xdmf.h"
|
||||
#include "common/MPI.h"
|
||||
#include "common/Utilities.h"
|
||||
|
||||
#include "ProfilerApp.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
@ -12,7 +30,17 @@
|
|||
#include <vector>
|
||||
|
||||
|
||||
enum class Format { OLD, NEW, SILO, UNKNOWN };
|
||||
enum class Format { OLD, NEW, SILO, HDF5, UNKNOWN };
|
||||
|
||||
|
||||
/****************************************************
|
||||
* External declerations *
|
||||
****************************************************/
|
||||
std::vector<IO::MeshDatabase> writeMeshesSilo(
|
||||
const std::vector<IO::MeshDataStruct> &, const std::string &, IO::FileFormat, int );
|
||||
void writeSiloSummary( const std::vector<IO::MeshDatabase> &, const std::string & );
|
||||
std::vector<IO::MeshDatabase> writeMeshesHDF5(
|
||||
const std::vector<IO::MeshDataStruct> &, const std::string &, IO::FileFormat, int, Xdmf & );
|
||||
|
||||
|
||||
/****************************************************
|
||||
|
@ -75,6 +103,8 @@ void IO::initialize( const std::string &path, const std::string &format, bool ap
|
|||
global_IO_format = Format::NEW;
|
||||
else if ( format == "silo" )
|
||||
global_IO_format = Format::SILO;
|
||||
else if ( format == "hdf5" )
|
||||
global_IO_format = Format::HDF5;
|
||||
else
|
||||
ERROR( "Unknown format" );
|
||||
int rank = Utilities::MPI( MPI_COMM_WORLD ).getRank();
|
||||
|
@ -83,7 +113,7 @@ void IO::initialize( const std::string &path, const std::string &format, bool ap
|
|||
std::string filename;
|
||||
if ( global_IO_format == Format::OLD || global_IO_format == Format::NEW )
|
||||
filename = global_IO_path + "/summary.LBM";
|
||||
else if ( global_IO_format == Format::SILO )
|
||||
else if ( global_IO_format == Format::SILO || global_IO_format == Format::HDF5 )
|
||||
filename = global_IO_path + "/LBM.visit";
|
||||
else
|
||||
ERROR( "Unknown format" );
|
||||
|
@ -116,10 +146,10 @@ static std::vector<IO::MeshDatabase> writeMeshesOrigFormat(
|
|||
domain.file = filename;
|
||||
domain.offset = 0;
|
||||
mesh_entry.domains.push_back( domain );
|
||||
if ( !meshData[i].vars.empty() ) {
|
||||
static bool printVariableSupportMsg = true;
|
||||
if ( !meshData[i].vars.empty() && printVariableSupportMsg ) {
|
||||
printVariableSupportMsg = false;
|
||||
printf( "Warning: variables are not supported with this format (original)\n" );
|
||||
// for (size_t j=0; j<meshData[i].vars.size(); j++)
|
||||
// mesh_entry.variables.push_back( meshData[i].vars[j]->name );
|
||||
}
|
||||
const std::string meshClass = mesh->className();
|
||||
if ( meshClass == "PointList" ) {
|
||||
|
@ -170,7 +200,7 @@ static std::vector<IO::MeshDatabase> writeMeshesOrigFormat(
|
|||
|
||||
|
||||
// Create the database entry for the mesh data
|
||||
static IO::MeshDatabase getDatabase(
|
||||
IO::MeshDatabase IO::getDatabase(
|
||||
const std::string &filename, const IO::MeshDataStruct &mesh, IO::FileFormat format, int rank )
|
||||
{
|
||||
char domainname[100];
|
||||
|
@ -212,6 +242,7 @@ static IO::MeshDatabase getDatabase(
|
|||
static IO::MeshDatabase write_domain( FILE *fid, const std::string &filename,
|
||||
const IO::MeshDataStruct &mesh, IO::FileFormat format, int rank )
|
||||
{
|
||||
ASSERT( !mesh.meshName.empty() );
|
||||
const int level = 0;
|
||||
// Create the MeshDatabase
|
||||
IO::MeshDatabase database = getDatabase( filename, mesh, format, rank );
|
||||
|
@ -234,6 +265,8 @@ static IO::MeshDatabase write_domain( FILE *fid, const std::string &filename,
|
|||
size_t N = mesh.vars[i]->data.length();
|
||||
size_t N_mesh = mesh.mesh->numberPointsVar( mesh.vars[i]->type );
|
||||
ASSERT( N == dim * N_mesh );
|
||||
ASSERT( !type.empty() );
|
||||
ASSERT( !variable.name.empty() );
|
||||
fprintf( fid, "Var: %s-%05i-%s: %i, %s, %lu, %lu, double\n", database.name.c_str(), rank,
|
||||
variable.name.c_str(), dim, type.data(), N_mesh, N * sizeof( double ) );
|
||||
fwrite( mesh.vars[i]->data.data(), sizeof( double ), N, fid );
|
||||
|
@ -243,212 +276,6 @@ static IO::MeshDatabase write_domain( FILE *fid, const std::string &filename,
|
|||
}
|
||||
|
||||
|
||||
#ifdef USE_SILO
|
||||
// Write a PointList mesh (and variables) to a file
|
||||
template<class TYPE>
|
||||
static void writeSiloPointMesh(
|
||||
DBfile *fid, const IO::PointList &mesh, const std::string &meshname )
|
||||
{
|
||||
const auto &points = mesh.getPoints();
|
||||
std::vector<TYPE> x( points.size() ), y( points.size() ), z( points.size() );
|
||||
for ( size_t i = 0; i < x.size(); i++ ) {
|
||||
x[i] = points[i].x;
|
||||
y[i] = points[i].y;
|
||||
z[i] = points[i].z;
|
||||
}
|
||||
const TYPE *coords[] = { x.data(), y.data(), z.data() };
|
||||
IO::silo::writePointMesh<TYPE>( fid, meshname, 3, points.size(), coords );
|
||||
}
|
||||
static void writeSiloPointList(
|
||||
DBfile *fid, const IO::MeshDataStruct &meshData, IO::MeshDatabase database )
|
||||
{
|
||||
const IO::PointList &mesh = dynamic_cast<IO::PointList &>( *meshData.mesh );
|
||||
const std::string meshname = database.domains[0].name;
|
||||
if ( meshData.precision == IO::DataType::Double ) {
|
||||
writeSiloPointMesh<double>( fid, mesh, meshname );
|
||||
} else if ( meshData.precision == IO::DataType::Float ) {
|
||||
writeSiloPointMesh<float>( fid, mesh, meshname );
|
||||
} else {
|
||||
ERROR( "Unsupported format" );
|
||||
}
|
||||
const auto &points = mesh.getPoints();
|
||||
std::vector<double> x( points.size() ), y( points.size() ), z( points.size() );
|
||||
for ( size_t i = 0; i < x.size(); i++ ) {
|
||||
x[i] = points[i].x;
|
||||
y[i] = points[i].y;
|
||||
z[i] = points[i].z;
|
||||
}
|
||||
const double *coords[] = { x.data(), y.data(), z.data() };
|
||||
IO::silo::writePointMesh( fid, meshname, 3, points.size(), coords );
|
||||
for ( size_t i = 0; i < meshData.vars.size(); i++ ) {
|
||||
const IO::Variable &var = *meshData.vars[i];
|
||||
if ( var.precision == IO::DataType::Double ) {
|
||||
IO::silo::writePointMeshVariable( fid, meshname, var.name, var.data );
|
||||
} else if ( var.precision == IO::DataType::Float ) {
|
||||
Array<float> data2( var.data.size() );
|
||||
data2.copy( var.data );
|
||||
IO::silo::writePointMeshVariable( fid, meshname, var.name, data2 );
|
||||
} else if ( var.precision == IO::DataType::Int ) {
|
||||
Array<int> data2( var.data.size() );
|
||||
data2.copy( var.data );
|
||||
IO::silo::writePointMeshVariable( fid, meshname, var.name, data2 );
|
||||
} else {
|
||||
ERROR( "Unsupported format" );
|
||||
}
|
||||
}
|
||||
}
|
||||
// Write a TriMesh mesh (and variables) to a file
|
||||
template<class TYPE>
|
||||
static void writeSiloTriMesh( DBfile *fid, const IO::TriMesh &mesh, const std::string &meshname )
|
||||
{
|
||||
const auto &points = mesh.vertices->getPoints();
|
||||
std::vector<TYPE> x( points.size() ), y( points.size() ), z( points.size() );
|
||||
for ( size_t i = 0; i < x.size(); i++ ) {
|
||||
x[i] = points[i].x;
|
||||
y[i] = points[i].y;
|
||||
z[i] = points[i].z;
|
||||
}
|
||||
const TYPE *coords[] = { x.data(), y.data(), z.data() };
|
||||
const int *tri[] = { mesh.A.data(), mesh.B.data(), mesh.C.data() };
|
||||
IO::silo::writeTriMesh<TYPE>( fid, meshname, 3, 2, points.size(), coords, mesh.A.size(), tri );
|
||||
}
|
||||
static void writeSiloTriMesh2( DBfile *fid, const IO::MeshDataStruct &meshData,
|
||||
const IO::TriMesh &mesh, IO::MeshDatabase database )
|
||||
{
|
||||
const std::string meshname = database.domains[0].name;
|
||||
if ( meshData.precision == IO::DataType::Double ) {
|
||||
writeSiloTriMesh<double>( fid, mesh, meshname );
|
||||
} else if ( meshData.precision == IO::DataType::Float ) {
|
||||
writeSiloTriMesh<float>( fid, mesh, meshname );
|
||||
} else {
|
||||
ERROR( "Unsupported format" );
|
||||
}
|
||||
for ( size_t i = 0; i < meshData.vars.size(); i++ ) {
|
||||
const IO::Variable &var = *meshData.vars[i];
|
||||
if ( var.precision == IO::DataType::Double ) {
|
||||
IO::silo::writeTriMeshVariable( fid, 3, meshname, var.name, var.data, var.type );
|
||||
} else if ( var.precision == IO::DataType::Float ) {
|
||||
Array<float> data2( var.data.size() );
|
||||
data2.copy( var.data );
|
||||
IO::silo::writeTriMeshVariable( fid, 3, meshname, var.name, data2, var.type );
|
||||
} else if ( var.precision == IO::DataType::Int ) {
|
||||
Array<int> data2( var.data.size() );
|
||||
data2.copy( var.data );
|
||||
IO::silo::writeTriMeshVariable( fid, 3, meshname, var.name, data2, var.type );
|
||||
} else {
|
||||
ERROR( "Unsupported format" );
|
||||
}
|
||||
}
|
||||
}
|
||||
static void writeSiloTriMesh(
|
||||
DBfile *fid, const IO::MeshDataStruct &meshData, IO::MeshDatabase database )
|
||||
{
|
||||
const IO::TriMesh &mesh = dynamic_cast<IO::TriMesh &>( *meshData.mesh );
|
||||
writeSiloTriMesh2( fid, meshData, mesh, database );
|
||||
}
|
||||
static void writeSiloTriList(
|
||||
DBfile *fid, const IO::MeshDataStruct &meshData, IO::MeshDatabase database )
|
||||
{
|
||||
auto mesh = getTriMesh( meshData.mesh );
|
||||
writeSiloTriMesh2( fid, meshData, *mesh, database );
|
||||
}
|
||||
// Write a DomainMesh mesh (and variables) to a file
|
||||
static void writeSiloDomainMesh(
|
||||
DBfile *fid, const IO::MeshDataStruct &meshData, IO::MeshDatabase database )
|
||||
{
|
||||
const IO::DomainMesh &mesh = dynamic_cast<IO::DomainMesh &>( *meshData.mesh );
|
||||
RankInfoStruct info( mesh.rank, mesh.nprocx, mesh.nprocy, mesh.nprocz );
|
||||
std::array<double, 6> range = { info.ix * mesh.Lx / info.nx,
|
||||
( info.ix + 1 ) * mesh.Lx / info.nx, info.jy * mesh.Ly / info.ny,
|
||||
( info.jy + 1 ) * mesh.Ly / info.ny, info.kz * mesh.Lz / info.nz,
|
||||
( info.kz + 1 ) * mesh.Lz / info.nz };
|
||||
std::array<int, 3> N = { mesh.nx, mesh.ny, mesh.nz };
|
||||
auto meshname = database.domains[0].name;
|
||||
IO::silo::writeUniformMesh<3>( fid, meshname, range, N );
|
||||
IO::silo::write<int>(
|
||||
fid, meshname + "_rankinfo", { mesh.rank, mesh.nprocx, mesh.nprocy, mesh.nprocz } );
|
||||
for ( size_t i = 0; i < meshData.vars.size(); i++ ) {
|
||||
const auto &var = *meshData.vars[i];
|
||||
if ( var.precision == IO::DataType::Double ) {
|
||||
IO::silo::writeUniformMeshVariable<3>( fid, meshname, N, var.name, var.data, var.type );
|
||||
} else if ( var.precision == IO::DataType::Float ) {
|
||||
Array<float> data2( var.data.size() );
|
||||
data2.copy( var.data );
|
||||
IO::silo::writeUniformMeshVariable<3>( fid, meshname, N, var.name, data2, var.type );
|
||||
} else if ( var.precision == IO::DataType::Int ) {
|
||||
Array<int> data2( var.data.size() );
|
||||
data2.copy( var.data );
|
||||
IO::silo::writeUniformMeshVariable<3>( fid, meshname, N, var.name, data2, var.type );
|
||||
} else {
|
||||
ERROR( "Unsupported format" );
|
||||
}
|
||||
}
|
||||
}
|
||||
// Write a mesh (and variables) to a file
|
||||
static IO::MeshDatabase write_domain_silo( DBfile *fid, const std::string &filename,
|
||||
const IO::MeshDataStruct &mesh, IO::FileFormat format, int rank )
|
||||
{
|
||||
// Create the MeshDatabase
|
||||
auto database = getDatabase( filename, mesh, format, rank );
|
||||
if ( database.meshClass == "PointList" ) {
|
||||
writeSiloPointList( fid, mesh, database );
|
||||
} else if ( database.meshClass == "TriMesh" ) {
|
||||
writeSiloTriMesh( fid, mesh, database );
|
||||
} else if ( database.meshClass == "TriList" ) {
|
||||
writeSiloTriList( fid, mesh, database );
|
||||
} else if ( database.meshClass == "DomainMesh" ) {
|
||||
writeSiloDomainMesh( fid, mesh, database );
|
||||
} else {
|
||||
ERROR( "Unknown mesh class" );
|
||||
}
|
||||
return database;
|
||||
}
|
||||
// Write the summary file for silo
|
||||
std::pair<int, int> getSiloMeshType( const std::string &meshClass )
|
||||
{
|
||||
int meshType = 0;
|
||||
int varType = 0;
|
||||
if ( meshClass == "PointList" ) {
|
||||
meshType = DB_POINTMESH;
|
||||
varType = DB_POINTVAR;
|
||||
} else if ( meshClass == "TriMesh" ) {
|
||||
meshType = DB_UCDMESH;
|
||||
varType = DB_UCDVAR;
|
||||
} else if ( meshClass == "TriList" ) {
|
||||
meshType = DB_UCDMESH;
|
||||
varType = DB_UCDVAR;
|
||||
} else if ( meshClass == "DomainMesh" ) {
|
||||
meshType = DB_QUAD_RECT;
|
||||
varType = DB_QUADVAR;
|
||||
} else {
|
||||
ERROR( "Unknown mesh class" );
|
||||
}
|
||||
return std::make_pair( meshType, varType );
|
||||
}
|
||||
void writeSiloSummary(
|
||||
const std::vector<IO::MeshDatabase> &meshes_written, const std::string &filename )
|
||||
{
|
||||
auto fid = IO::silo::open( filename, IO::silo::CREATE );
|
||||
for ( const auto &data : meshes_written ) {
|
||||
auto type = getSiloMeshType( data.meshClass );
|
||||
std::vector<int> meshTypes( data.domains.size(), type.first );
|
||||
std::vector<int> varTypes( data.domains.size(), type.second );
|
||||
std::vector<std::string> meshNames;
|
||||
for ( const auto &tmp : data.domains )
|
||||
meshNames.push_back( tmp.file + ":" + tmp.name );
|
||||
IO::silo::writeMultiMesh( fid, data.name, meshNames, meshTypes );
|
||||
for ( const auto &variable : data.variables ) {
|
||||
std::vector<std::string> varnames;
|
||||
for ( const auto &tmp : data.domains )
|
||||
varnames.push_back( tmp.file + ":" + variable.name );
|
||||
IO::silo::writeMultiVar( fid, variable.name, varnames, varTypes );
|
||||
}
|
||||
}
|
||||
IO::silo::close( fid );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Write the mesh data in the new format
|
||||
static std::vector<IO::MeshDatabase> writeMeshesNewFormat(
|
||||
const std::vector<IO::MeshDataStruct> &meshData, const std::string &path, IO::FileFormat format,
|
||||
|
@ -459,43 +286,14 @@ static std::vector<IO::MeshDatabase> writeMeshesNewFormat(
|
|||
sprintf( filename, "%05i", rank );
|
||||
sprintf( fullpath, "%s/%s", path.c_str(), filename );
|
||||
FILE *fid = fopen( fullpath, "wb" );
|
||||
for ( size_t i = 0; i < meshData.size(); i++ ) {
|
||||
std::shared_ptr<IO::Mesh> mesh = meshData[i].mesh;
|
||||
ASSERT( fid != nullptr );
|
||||
for ( size_t i = 0; i < meshData.size(); i++ )
|
||||
meshes_written.push_back( write_domain( fid, filename, meshData[i], format, rank ) );
|
||||
}
|
||||
fclose( fid );
|
||||
return meshes_written;
|
||||
}
|
||||
|
||||
|
||||
// Write the mesh data to silo
|
||||
static std::vector<IO::MeshDatabase> writeMeshesSilo(
|
||||
const std::vector<IO::MeshDataStruct> &meshData, const std::string &path, IO::FileFormat format,
|
||||
int rank )
|
||||
{
|
||||
#ifdef USE_SILO
|
||||
std::vector<IO::MeshDatabase> meshes_written;
|
||||
char filename[100], fullpath[200];
|
||||
sprintf( filename, "%05i.silo", rank );
|
||||
sprintf( fullpath, "%s/%s", path.c_str(), filename );
|
||||
auto fid = IO::silo::open( fullpath, IO::silo::CREATE );
|
||||
for ( size_t i = 0; i < meshData.size(); i++ ) {
|
||||
auto mesh = meshData[i].mesh;
|
||||
meshes_written.push_back( write_domain_silo( fid, filename, meshData[i], format, rank ) );
|
||||
}
|
||||
IO::silo::close( fid );
|
||||
return meshes_written;
|
||||
#else
|
||||
NULL_USE( meshData );
|
||||
NULL_USE( path );
|
||||
NULL_USE( format );
|
||||
NULL_USE( rank );
|
||||
ERROR( "Application built without silo support" );
|
||||
return std::vector<IO::MeshDatabase>();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/****************************************************
|
||||
* Write the mesh data *
|
||||
****************************************************/
|
||||
|
@ -513,6 +311,7 @@ void IO::writeData( const std::string &subdir, const std::vector<IO::MeshDataStr
|
|||
std::string path = global_IO_path + "/" + subdir;
|
||||
recursiveMkdir( path, S_IRWXU | S_IRGRP );
|
||||
// Write the mesh files
|
||||
Xdmf xmf;
|
||||
std::vector<IO::MeshDatabase> meshes_written;
|
||||
if ( global_IO_format == Format::OLD ) {
|
||||
// Write the original triangle format
|
||||
|
@ -523,24 +322,28 @@ void IO::writeData( const std::string &subdir, const std::vector<IO::MeshDataStr
|
|||
} else if ( global_IO_format == Format::SILO ) {
|
||||
// Write silo
|
||||
meshes_written = writeMeshesSilo( meshData, path, IO::FileFormat::SILO, rank );
|
||||
} else if ( global_IO_format == Format::HDF5 ) {
|
||||
// Write hdf5
|
||||
meshes_written = writeMeshesHDF5( meshData, path, IO::FileFormat::HDF5, rank, xmf );
|
||||
} else {
|
||||
ERROR( "Unknown format" );
|
||||
}
|
||||
// Gather a complete list of files on rank 0
|
||||
meshes_written = gatherAll( meshes_written, comm );
|
||||
// Gather xmf file (if applicable)
|
||||
if ( global_IO_format == Format::HDF5 ) {
|
||||
xmf.gather( comm );
|
||||
}
|
||||
// Write the summary files
|
||||
if ( rank == 0 ) {
|
||||
// Write the summary file for the current timestep
|
||||
char filename[200];
|
||||
sprintf( filename, "%s/LBM.summary", path.c_str() );
|
||||
write( meshes_written, filename );
|
||||
// Write summary silo file if needed
|
||||
#ifdef USE_SILO
|
||||
write( meshes_written, path + "/LBM.summary" );
|
||||
// Write summary file if needed
|
||||
if ( global_IO_format == Format::SILO ) {
|
||||
sprintf( filename, "%s/summary.silo", path.c_str() );
|
||||
writeSiloSummary( meshes_written, filename );
|
||||
writeSiloSummary( meshes_written, path + "/summary.silo" );
|
||||
} else if ( global_IO_format == Format::HDF5 ) {
|
||||
xmf.write( path + "/summary.xmf" );
|
||||
}
|
||||
#endif
|
||||
// Add the timestep to the global summary file
|
||||
if ( global_IO_format == Format::OLD || global_IO_format == Format::NEW ) {
|
||||
auto filename = global_IO_path + "/summary.LBM";
|
||||
|
@ -552,6 +355,11 @@ void IO::writeData( const std::string &subdir, const std::vector<IO::MeshDataStr
|
|||
FILE *fid = fopen( filename.c_str(), "ab" );
|
||||
fprintf( fid, "%s/summary.silo\n", subdir.c_str() );
|
||||
fclose( fid );
|
||||
} else if ( global_IO_format == Format::HDF5 ) {
|
||||
auto filename = global_IO_path + "/LBM.visit";
|
||||
FILE *fid = fopen( filename.c_str(), "ab" );
|
||||
fprintf( fid, "%s/summary.xmf\n", subdir.c_str() );
|
||||
fclose( fid );
|
||||
} else {
|
||||
ERROR( "Unknown format" );
|
||||
}
|
||||
|
|
26
IO/Writer.h
26
IO/Writer.h
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef WRITER_INC
|
||||
#define WRITER_INC
|
||||
|
||||
|
@ -21,11 +36,13 @@ namespace IO {
|
|||
* @param[in] format The data format to use:
|
||||
* old - Old mesh format
|
||||
* (provided for backward compatibility, cannot write variables)
|
||||
* new - New format, 1 file/process silo - Silo
|
||||
* new - New format, 1 file/process
|
||||
* silo - Silo
|
||||
* hdf5 - HDF5 + XMDF
|
||||
* @param[in] append Append any existing data (default is false)
|
||||
*/
|
||||
void initialize(
|
||||
const std::string &path = "", const std::string &format = "silo", bool append = false );
|
||||
const std::string &path = "", const std::string &format = "hdf5", bool append = false );
|
||||
|
||||
|
||||
/*!
|
||||
|
@ -55,6 +72,11 @@ inline void writeData(
|
|||
}
|
||||
|
||||
|
||||
// Create the database entry for the mesh data
|
||||
IO::MeshDatabase getDatabase(
|
||||
const std::string &filename, const IO::MeshDataStruct &mesh, IO::FileFormat format, int rank );
|
||||
|
||||
|
||||
} // namespace IO
|
||||
|
||||
#endif
|
||||
|
|
620
IO/Xdmf.cpp
Normal file
620
IO/Xdmf.cpp
Normal file
|
@ -0,0 +1,620 @@
|
|||
#include "IO/Xdmf.h"
|
||||
|
||||
#include "common/Array.h"
|
||||
#include "common/UtilityMacros.h"
|
||||
|
||||
|
||||
ArraySize squeeze( const ArraySize &x )
|
||||
{
|
||||
int Nd = 0;
|
||||
size_t N[5] = { 1 };
|
||||
for ( size_t i = 0; i < x.maxDim(); i++ ) {
|
||||
if ( x[i] != 1 )
|
||||
N[Nd++] = x[i];
|
||||
}
|
||||
return ArraySize( std::max( Nd, 1 ), N );
|
||||
}
|
||||
|
||||
|
||||
// Helper functions
|
||||
static void addDataItem(
|
||||
FILE *xmf, const std::string &indent, ArraySize size, const std::string &location )
|
||||
{
|
||||
size = squeeze( size );
|
||||
if ( size.ndim() == 1 ) {
|
||||
fprintf( xmf, "%s<DataItem Dimensions=\"%lu\"", indent.data(), size[0] );
|
||||
} else if ( size.ndim() == 2 ) {
|
||||
fprintf( xmf, "%s<DataItem Dimensions=\"%lu %lu\"", indent.data(), size[1], size[0] );
|
||||
} else if ( size.ndim() == 3 ) {
|
||||
fprintf( xmf, "%s<DataItem Dimensions=\"%lu %lu %lu\"", indent.data(), size[2], size[1],
|
||||
size[0] );
|
||||
} else if ( size.ndim() == 4 ) {
|
||||
fprintf( xmf, "%s<DataItem Dimensions=\"%lu %lu %lu %lu\"", indent.data(), size[3], size[2],
|
||||
size[1], size[0] );
|
||||
} else {
|
||||
ERROR( "Invalid number of dimensions" );
|
||||
}
|
||||
fprintf( xmf, " Format=\"HDF\">\n" );
|
||||
fprintf( xmf, "%s %s\n", indent.data(), location.data() );
|
||||
fprintf( xmf, "%s</DataItem>\n", indent.data() );
|
||||
}
|
||||
template<class TYPE>
|
||||
static void addVariable( FILE *xmf, const std::string &indent, const std::string &name,
|
||||
const std::string &type, const std::string ¢er, ArraySize size,
|
||||
const std::string &location )
|
||||
{
|
||||
fprintf( xmf, "%s<Attribute Name=\"%s\" AttributeType=\"%s\" Center=\"%s\">\n", indent.data(),
|
||||
name.data(), type.data(), center.data() );
|
||||
addDataItem( xmf, indent + " ", size, location );
|
||||
fprintf( xmf, "%s</Attribute>\n", indent.data() );
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Enum functions *
|
||||
****************************************************************/
|
||||
/*template<class TYPE>
|
||||
static Xdmf::DataType getDataType()
|
||||
{
|
||||
if ( std::is_same<TYPE, char>::value )
|
||||
return Xdmf::DataType::Char;
|
||||
else if ( std::is_same<TYPE, int32_t>::value )
|
||||
return Xdmf::DataType::Int32;
|
||||
else if ( std::is_same<TYPE, int64_t>::value )
|
||||
return Xdmf::DataType::Int64;
|
||||
else if ( std::is_same<TYPE, uint32_t>::value )
|
||||
return Xdmf::DataType::Uint32;
|
||||
else if ( std::is_same<TYPE, uint64_t>::value )
|
||||
return Xdmf::DataType::Uint64;
|
||||
else if ( std::is_same<TYPE, float>::value )
|
||||
return Xdmf::DataType::Float;
|
||||
else if ( std::is_same<TYPE, double>::value )
|
||||
return Xdmf::DataType::Double;
|
||||
else
|
||||
ERROR( "Invalid type" );
|
||||
}*/
|
||||
static const char *TopologyTypeNames[] = { "", "Polyvertex", "Polyline", "Polygon", "Triangle",
|
||||
"Quadrilateral", "Tetrahedron", "Pyramid", "Wedge", "Hexahedron", "Edge_3", "Triangle_6",
|
||||
"Quadrilateral_8", "Tetrahedron_10", "Pyramid_13", "Wedge_15", "Hexahedron_20", "Mixed",
|
||||
"CurvilinearMesh2D", "CurvilinearMesh3D", "RectangularMesh2D", "RectangularMesh3D",
|
||||
"UniformMesh2D", "UniformMesh3D" };
|
||||
static const uint8_t TopologyTypeDOFs[] = { 0, 1, 2, 0, 3, 4, 4, 5, 6, 8, 3, 6, 8, 10, 13, 15, 20,
|
||||
0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Create a mesh *
|
||||
****************************************************************/
|
||||
Xdmf::MeshData Xdmf::createPointMesh( const std::string &name, uint8_t NDIM, size_t N,
|
||||
const std::string &x, const std::string &y, const std::string &z )
|
||||
{
|
||||
return createUnstructuredMesh( name, NDIM, TopologyType::Polyvertex, N, "", N, x, y, z );
|
||||
}
|
||||
Xdmf::MeshData Xdmf::createUniformMesh(
|
||||
const std::string &name, const std::vector<double> &range, ArraySize size )
|
||||
{
|
||||
ASSERT( range.size() == 2 * size.ndim() );
|
||||
MeshData data;
|
||||
data.name = name;
|
||||
data.size = size;
|
||||
if ( size.ndim() == 2 )
|
||||
data.type = TopologyType::UniformMesh2D;
|
||||
else if ( size.ndim() == 3 )
|
||||
data.type = TopologyType::UniformMesh3D;
|
||||
else
|
||||
ERROR( "# of dimensions != 2 or 3" );
|
||||
for ( int i = 0; i < 2 * size.ndim(); i++ )
|
||||
data.range[i] = range[i];
|
||||
return data;
|
||||
}
|
||||
Xdmf::MeshData Xdmf::createCurvilinearMesh( const std::string &name, ArraySize size,
|
||||
const std::string &x, const std::string &y, const std::string &z )
|
||||
{
|
||||
MeshData data;
|
||||
data.name = name;
|
||||
if ( size.ndim() == 2 )
|
||||
data.type = TopologyType::CurvilinearMesh2D;
|
||||
else if ( size.ndim() == 3 )
|
||||
data.type = TopologyType::CurvilinearMesh3D;
|
||||
else
|
||||
ERROR( "Invalid size for Curvilinear mesh" );
|
||||
data.size = size;
|
||||
data.x = x;
|
||||
data.y = y;
|
||||
data.z = z;
|
||||
return data;
|
||||
}
|
||||
Xdmf::MeshData Xdmf::createUnstructuredMesh( const std::string &name, uint8_t NDIM,
|
||||
TopologyType type, size_t NumElements, const std::string &dofMap, size_t NumNodes,
|
||||
const std::string &x, const std::string &y, const std::string &z )
|
||||
{
|
||||
ASSERT( type != TopologyType::Null );
|
||||
MeshData data;
|
||||
data.name = name;
|
||||
data.type = type;
|
||||
data.size = { NDIM, NumElements, NumNodes };
|
||||
data.dofMap = dofMap;
|
||||
data.x = x;
|
||||
data.y = y;
|
||||
data.z = z;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Add a variable *
|
||||
****************************************************************/
|
||||
void Xdmf::MeshData::addVariable( const std::string &meshName, const std::string &varName,
|
||||
ArraySize varSize, RankType rank, Center center, const std::string &varData )
|
||||
{
|
||||
VarData var;
|
||||
var.name = varName;
|
||||
var.size = varSize;
|
||||
var.data = varData;
|
||||
var.rankType = rank;
|
||||
var.center = center;
|
||||
vars.push_back( std::move( var ) );
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Add a mesh domain *
|
||||
****************************************************************/
|
||||
void Xdmf::addMesh( const std::string &meshName, const MeshData &domain )
|
||||
{
|
||||
auto &domains = d_meshData[meshName];
|
||||
for ( const auto &domain2 : domains )
|
||||
ASSERT( domain2.name != domain.name );
|
||||
domains.push_back( domain );
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Write a variable *
|
||||
****************************************************************/
|
||||
static void writeVariable( FILE *fid, const Xdmf::VarData &var, const std::string &indent )
|
||||
{
|
||||
// Write the variable name
|
||||
fprintf( fid, "%s<Attribute Name=\"%s\"", indent.data(), var.name.data() );
|
||||
// Write the variable type
|
||||
if ( var.rankType == Xdmf::RankType::Scalar ) {
|
||||
fprintf( fid, " AttributeType=\"Scalar\"" );
|
||||
} else if ( var.rankType == Xdmf::RankType::Vector ) {
|
||||
fprintf( fid, " AttributeType=\"Vector\"" );
|
||||
} else if ( var.rankType == Xdmf::RankType::Tensor ) {
|
||||
fprintf( fid, " AttributeType=\"Tensor\"" );
|
||||
} else if ( var.rankType == Xdmf::RankType::Tensor6 ) {
|
||||
fprintf( fid, " AttributeType=\"Tensor6\"" );
|
||||
} else if ( var.rankType == Xdmf::RankType::Matrix ) {
|
||||
fprintf( fid, " AttributeType=\"Matrix\"" );
|
||||
} else if ( var.rankType == Xdmf::RankType::GlobalID ) {
|
||||
fprintf( fid, " AttributeType=\"GlobalID\"" );
|
||||
} else {
|
||||
ERROR( "Unknown center type" );
|
||||
}
|
||||
// Write the variable centering
|
||||
if ( var.center == Xdmf::Center::Node ) {
|
||||
fprintf( fid, " Center=\"Node\">\n" );
|
||||
} else if ( var.center == Xdmf::Center::Cell ) {
|
||||
fprintf( fid, " Center=\"Cell\">\n" );
|
||||
} else if ( var.center == Xdmf::Center::Grid ) {
|
||||
fprintf( fid, " Center=\"Grid\">\n" );
|
||||
} else if ( var.center == Xdmf::Center::Face ) {
|
||||
fprintf( fid, " Center=\"Face\">\n" );
|
||||
} else if ( var.center == Xdmf::Center::Edge ) {
|
||||
fprintf( fid, " Center=\"Edge\">\n" );
|
||||
} else if ( var.center == Xdmf::Center::Other ) {
|
||||
fprintf( fid, " Center=\"Other\">\n" );
|
||||
} else {
|
||||
ERROR( "Unknown center type" );
|
||||
}
|
||||
// Write the data item
|
||||
addDataItem( fid, indent + " ", var.size, var.data );
|
||||
// Finished
|
||||
fprintf( fid, "%s</Attribute>\n", indent.data() );
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Write the mesh grid *
|
||||
****************************************************************/
|
||||
static void writeMeshGrid( FILE *fid, const Xdmf::MeshData &mesh, const std::string &indent )
|
||||
{
|
||||
const char *s = indent.data();
|
||||
double x0[3] = { mesh.range[0], mesh.range[2], mesh.range[4] };
|
||||
double dx[3] = { ( mesh.range[1] - mesh.range[0] ) / mesh.size[0],
|
||||
( mesh.range[3] - mesh.range[2] ) / mesh.size[1],
|
||||
( mesh.range[5] - mesh.range[4] ) / mesh.size[2] };
|
||||
switch ( mesh.type ) {
|
||||
case Xdmf::TopologyType::UniformMesh2D:
|
||||
// Write a uniform 2d mesh
|
||||
fprintf( fid, "%s<Grid Name=\"%s\" GridType=\"Uniform\">\n", s, mesh.name.data() );
|
||||
fprintf( fid,
|
||||
"%s <Topology TopologyType=\"2DCoRectMesh\" NumberOfElements=\"%lu %lu\"/>\n", s,
|
||||
mesh.size[1] + 1, mesh.size[0] + 1 );
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"ORIGIN_DXDY\">\n", s );
|
||||
fprintf(
|
||||
fid, "%s <DataItem Format=\"XML\" NumberType=\"float\" Dimensions=\"2\">\n", s );
|
||||
fprintf( fid, "%s %0.12e %0.12e\n", s, x0[0], x0[1] );
|
||||
fprintf( fid, "%s </DataItem>\n", s );
|
||||
fprintf(
|
||||
fid, "%s <DataItem Format=\"XML\" NumberType=\"float\" Dimensions=\"2\">\n", s );
|
||||
fprintf( fid, "%s %0.12e %0.12e\n", s, dx[0], dx[1] );
|
||||
fprintf( fid, "%s </DataItem>\n", s );
|
||||
fprintf( fid, "%s </Geometry>\n", s );
|
||||
break;
|
||||
case Xdmf::TopologyType::UniformMesh3D:
|
||||
// Write a uniform 3d mesh
|
||||
fprintf( fid, "%s<Grid Name=\"%s\" GridType=\"Uniform\">\n", s, mesh.name.data() );
|
||||
fprintf( fid,
|
||||
"%s <Topology TopologyType=\"3DCoRectMesh\" NumberOfElements=\"%lu %lu\"/>\n", s,
|
||||
mesh.size[1] + 1, mesh.size[0] + 1 );
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"ORIGIN_DXDYDZ\">\n", s );
|
||||
fprintf(
|
||||
fid, "%s <DataItem Format=\"XML\" NumberType=\"float\" Dimensions=\"3\">\n", s );
|
||||
fprintf( fid, "%s %0.12e %0.12e %0.12e\n", s, x0[0], x0[1], x0[2] );
|
||||
fprintf( fid, "%s </DataItem>\n", s );
|
||||
fprintf(
|
||||
fid, "%s <DataItem Format=\"XML\" NumberType=\"float\" Dimensions=\"3\">\n", s );
|
||||
fprintf( fid, "%s %0.12e %0.12e %0.12e\n", s, dx[0], dx[1], dx[2] );
|
||||
fprintf( fid, "%s </DataItem>\n", s );
|
||||
fprintf( fid, "%s </Geometry>\n", s );
|
||||
break;
|
||||
case Xdmf::TopologyType::CurvilinearMesh2D:
|
||||
// Write a 2D curvillinear mesh
|
||||
fprintf( fid, "%s<Grid Name=\"%s\" GridType=\"Uniform\">\n", s, mesh.name.data() );
|
||||
fprintf( fid, "%s <Topology TopologyType=\"2DSMesh\" NumberOfElements=\"%lu %lu\"/>\n", s,
|
||||
mesh.size[1] + 1, mesh.size[0] + 1 );
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"X_Y\">\n", s );
|
||||
addDataItem( fid, indent + " ", mesh.size + 1, mesh.x );
|
||||
addDataItem( fid, indent + " ", mesh.size + 1, mesh.y );
|
||||
fprintf( fid, "%s </Geometry>\n", s );
|
||||
break;
|
||||
case Xdmf::TopologyType::CurvilinearMesh3D:
|
||||
// Write a 3D curvillinear mesh
|
||||
fprintf( fid, "%s<Grid Name=\"%s\" GridType=\"Uniform\">\n", s, mesh.name.data() );
|
||||
fprintf( fid, "%s <Topology TopologyType=\"3DSMesh\" NumberOfElements=\"%lu %lu %lu\"/>\n",
|
||||
s, mesh.size[2] + 1, mesh.size[1] + 1, mesh.size[0] + 1 );
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"X_Y_Z\">\n", s );
|
||||
addDataItem( fid, indent + " ", mesh.size + 1, mesh.x );
|
||||
addDataItem( fid, indent + " ", mesh.size + 1, mesh.y );
|
||||
addDataItem( fid, indent + " ", mesh.size + 1, mesh.z );
|
||||
fprintf( fid, "%s </Geometry>\n", s );
|
||||
break;
|
||||
case Xdmf::TopologyType::Polyvertex:
|
||||
case Xdmf::TopologyType::Polyline:
|
||||
case Xdmf::TopologyType::Polygon:
|
||||
case Xdmf::TopologyType::Triangle:
|
||||
case Xdmf::TopologyType::Quadrilateral:
|
||||
case Xdmf::TopologyType::Tetrahedron:
|
||||
case Xdmf::TopologyType::Pyramid:
|
||||
case Xdmf::TopologyType::Wedge:
|
||||
case Xdmf::TopologyType::Hexahedron:
|
||||
case Xdmf::TopologyType::Edge_3:
|
||||
case Xdmf::TopologyType::Triangle_6:
|
||||
case Xdmf::TopologyType::Quadrilateral_8:
|
||||
case Xdmf::TopologyType::Tetrahedron_10:
|
||||
case Xdmf::TopologyType::Pyramid_13:
|
||||
case Xdmf::TopologyType::Wedge_15:
|
||||
case Xdmf::TopologyType::Hexahedron_20:
|
||||
// Write an unstructured mesh
|
||||
{
|
||||
int NDIM = mesh.size[0];
|
||||
size_t Nelem = mesh.size[1];
|
||||
size_t Nnode = mesh.size[2];
|
||||
uint8_t Ndofs = TopologyTypeDOFs[static_cast<int>( mesh.type )];
|
||||
auto type = TopologyTypeNames[static_cast<int>( mesh.type )];
|
||||
fprintf( fid, "%s<Grid Name=\"%s\">\n", s, mesh.name.data() );
|
||||
fprintf( fid, "%s <Topology TopologyType=\"%s\"", s, type );
|
||||
fprintf( fid, " NumberOfElements=\"%lu\">\n", Nelem );
|
||||
if ( !mesh.dofMap.empty() )
|
||||
addDataItem( fid, indent + " ", { Ndofs, Nelem }, mesh.dofMap );
|
||||
fprintf( fid, "%s </Topology>\n", s );
|
||||
if ( NDIM == 2 ) {
|
||||
if ( mesh.y.empty() ) {
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"XY\">\n", s );
|
||||
addDataItem( fid, indent + " ", { 2, Nnode }, mesh.x );
|
||||
} else {
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"X_Y\">\n", s );
|
||||
addDataItem( fid, indent + " ", Nnode, mesh.x );
|
||||
addDataItem( fid, indent + " ", Nnode, mesh.y );
|
||||
}
|
||||
} else if ( NDIM == 3 ) {
|
||||
if ( mesh.y.empty() ) {
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"XYZ\">\n", s );
|
||||
addDataItem( fid, indent + " ", { 2, Nnode }, mesh.x );
|
||||
} else {
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"X_Y_Z\">\n", s );
|
||||
addDataItem( fid, indent + " ", Nnode, mesh.x );
|
||||
addDataItem( fid, indent + " ", Nnode, mesh.y );
|
||||
addDataItem( fid, indent + " ", Nnode, mesh.z );
|
||||
}
|
||||
} else {
|
||||
ERROR( "Dimensions other than 2 or 3 are not supported" );
|
||||
}
|
||||
fprintf( fid, "%s </Geometry>\n", s );
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
auto msg = "Invalid mesh type: " + std::to_string( static_cast<int>( mesh.type ) ) + " - " +
|
||||
mesh.name;
|
||||
ERROR( msg );
|
||||
}
|
||||
}
|
||||
// Write the variables
|
||||
for ( const auto &var : mesh.vars )
|
||||
writeVariable( fid, var, indent + " " );
|
||||
fprintf( fid, "%s </Grid>\n", s );
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Write the XDMF xml file *
|
||||
****************************************************************/
|
||||
void Xdmf::write( const std::string &filename ) const
|
||||
{
|
||||
// Create XDMF file
|
||||
auto fid = fopen( filename.data(), "w" );
|
||||
fprintf( fid, "<?xml version=\"1.0\" ?>\n" );
|
||||
fprintf( fid, "<!DOCTYPE Xdmf SYSTEM \"Xdmf.dtd\" []>\n" );
|
||||
fprintf( fid, "<Xdmf Version=\"2.0\">\n" );
|
||||
fprintf( fid, "<Domain>\n" );
|
||||
// Write an empty mesh to enable collections to work properly
|
||||
fprintf( fid, " <Grid Name=\"\" GridType=\"Uniform\"></Grid>\n\n" );
|
||||
// Write each mesh
|
||||
for ( const auto &data : d_meshData ) {
|
||||
auto name = data.first;
|
||||
auto domains = data.second;
|
||||
if ( domains.empty() )
|
||||
continue;
|
||||
if ( domains.size() == 1u && name == domains[0].name ) {
|
||||
writeMeshGrid( fid, domains[0], " " );
|
||||
} else {
|
||||
fprintf( fid, " <Grid Name=\"%s\" GridType=\"Collection\">\n", name.data() );
|
||||
for ( const auto &domain : domains )
|
||||
writeMeshGrid( fid, domain, " " );
|
||||
fprintf( fid, " </Grid>\n\n" );
|
||||
}
|
||||
}
|
||||
fprintf( fid, "</Domain>\n" );
|
||||
fprintf( fid, "</Xdmf>\n" );
|
||||
fclose( fid );
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Pack/Unpack data *
|
||||
****************************************************************/
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_trivially_copyable<T>::value, size_t>::type size( const T & )
|
||||
{
|
||||
return sizeof( T );
|
||||
}
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_trivially_copyable<T>::value, char *>::type pack(
|
||||
char *ptr, const T &x )
|
||||
{
|
||||
memcpy( ptr, &x, sizeof( T ) );
|
||||
return ptr + sizeof( T );
|
||||
}
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_trivially_copyable<T>::value, char *>::type unpack(
|
||||
char *ptr, T &x )
|
||||
{
|
||||
memcpy( &x, ptr, sizeof( T ) );
|
||||
return ptr + sizeof( T );
|
||||
}
|
||||
static size_t size( const std::string &str ) { return sizeof( int ) + str.size(); }
|
||||
static char *pack( char *ptr, const std::string &str )
|
||||
{
|
||||
int N = str.size();
|
||||
memcpy( ptr, &N, sizeof( int ) );
|
||||
ptr += sizeof( int );
|
||||
memcpy( ptr, str.data(), str.size() );
|
||||
ptr += str.size();
|
||||
return ptr;
|
||||
}
|
||||
static char *unpack( char *ptr, std::string &str )
|
||||
{
|
||||
int N = 0;
|
||||
memcpy( &N, ptr, sizeof( int ) );
|
||||
ASSERT( N >= 0 && N < 1000 );
|
||||
ptr += sizeof( int );
|
||||
str = std::string( ptr, N );
|
||||
ptr += N;
|
||||
return ptr;
|
||||
}
|
||||
static size_t size( const Xdmf::VarData &data )
|
||||
{
|
||||
size_t bytes = 0;
|
||||
bytes += size( data.name );
|
||||
bytes += size( data.size );
|
||||
bytes += size( data.rankType );
|
||||
bytes += size( data.center );
|
||||
bytes += size( data.data );
|
||||
return bytes;
|
||||
}
|
||||
static char *pack( char *ptr, const Xdmf::VarData &data )
|
||||
{
|
||||
ptr = pack( ptr, data.name );
|
||||
ptr = pack( ptr, data.size );
|
||||
ptr = pack( ptr, data.rankType );
|
||||
ptr = pack( ptr, data.center );
|
||||
ptr = pack( ptr, data.data );
|
||||
return ptr;
|
||||
}
|
||||
static char *unpack( char *ptr, Xdmf::VarData &data )
|
||||
{
|
||||
int rankType = 0, center = 0;
|
||||
ptr = unpack( ptr, data.name );
|
||||
ptr = unpack( ptr, data.size );
|
||||
ptr = unpack( ptr, rankType );
|
||||
ptr = unpack( ptr, center );
|
||||
ptr = unpack( ptr, data.data );
|
||||
data.rankType = static_cast<Xdmf::RankType>( rankType );
|
||||
data.center = static_cast<Xdmf::Center>( center );
|
||||
return ptr;
|
||||
}
|
||||
static size_t size( const Xdmf::MeshData &data )
|
||||
{
|
||||
int N_vars = data.vars.size();
|
||||
size_t bytes = 0;
|
||||
bytes += size( data.name );
|
||||
bytes += size( data.type );
|
||||
bytes += size( data.size );
|
||||
bytes += size( data.range );
|
||||
bytes += size( data.x );
|
||||
bytes += size( data.y );
|
||||
bytes += size( data.z );
|
||||
bytes += size( N_vars );
|
||||
for ( int i = 0; i < N_vars; i++ )
|
||||
bytes += size( data.vars[i] );
|
||||
return bytes;
|
||||
}
|
||||
static char *pack( char *ptr, const Xdmf::MeshData &data )
|
||||
{
|
||||
int N_vars = data.vars.size();
|
||||
ptr = pack( ptr, data.name );
|
||||
ptr = pack( ptr, data.type );
|
||||
ptr = pack( ptr, data.size );
|
||||
ptr = pack( ptr, data.range );
|
||||
ptr = pack( ptr, data.x );
|
||||
ptr = pack( ptr, data.y );
|
||||
ptr = pack( ptr, data.z );
|
||||
ptr = pack( ptr, N_vars );
|
||||
for ( int i = 0; i < N_vars; i++ )
|
||||
ptr = pack( ptr, data.vars[i] );
|
||||
return ptr;
|
||||
}
|
||||
static char *unpack( char *ptr, Xdmf::MeshData &data )
|
||||
{
|
||||
int N_vars = 0;
|
||||
ptr = unpack( ptr, data.name );
|
||||
ptr = unpack( ptr, data.type );
|
||||
ptr = unpack( ptr, data.size );
|
||||
ptr = unpack( ptr, data.range );
|
||||
ptr = unpack( ptr, data.x );
|
||||
ptr = unpack( ptr, data.y );
|
||||
ptr = unpack( ptr, data.z );
|
||||
ptr = unpack( ptr, N_vars );
|
||||
data.vars.resize( N_vars );
|
||||
for ( int i = 0; i < N_vars; i++ )
|
||||
ptr = unpack( ptr, data.vars[i] );
|
||||
return ptr;
|
||||
}
|
||||
static size_t size( const std::vector<Xdmf::MeshData> &data )
|
||||
{
|
||||
size_t bytes = 0;
|
||||
int N = data.size();
|
||||
bytes += size( N );
|
||||
for ( int i = 0; i < N; i++ )
|
||||
bytes += size( data[i] );
|
||||
return bytes;
|
||||
}
|
||||
static char *pack( char *ptr, const std::vector<Xdmf::MeshData> &data )
|
||||
{
|
||||
int N = data.size();
|
||||
ptr = pack( ptr, N );
|
||||
for ( int i = 0; i < N; i++ )
|
||||
ptr = pack( ptr, data[i] );
|
||||
return ptr;
|
||||
}
|
||||
static char *unpack( char *ptr, std::vector<Xdmf::MeshData> &data )
|
||||
{
|
||||
data.clear();
|
||||
int N = data.size();
|
||||
ptr = unpack( ptr, N );
|
||||
data.resize( N );
|
||||
for ( int i = 0; i < N; i++ )
|
||||
ptr = unpack( ptr, data[i] );
|
||||
return ptr;
|
||||
}
|
||||
static size_t size( const std::map<std::string, std::vector<Xdmf::MeshData>> &data )
|
||||
{
|
||||
size_t bytes = 0;
|
||||
int N_map = data.size();
|
||||
bytes += size( N_map );
|
||||
for ( const auto &tmp : data ) {
|
||||
bytes += size( tmp.first );
|
||||
bytes += size( tmp.second );
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
static char *pack( char *ptr, const std::map<std::string, std::vector<Xdmf::MeshData>> &data )
|
||||
{
|
||||
int N_map = data.size();
|
||||
ptr = pack( ptr, N_map );
|
||||
for ( const auto &tmp : data ) {
|
||||
ptr = pack( ptr, tmp.first );
|
||||
ptr = pack( ptr, tmp.second );
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
static char *unpack( char *ptr, std::map<std::string, std::vector<Xdmf::MeshData>> &data )
|
||||
{
|
||||
data.clear();
|
||||
int N_map = data.size();
|
||||
ptr = unpack( ptr, N_map );
|
||||
for ( int i = 0; i < N_map; i++ ) {
|
||||
std::string name;
|
||||
std::vector<Xdmf::MeshData> data2;
|
||||
ptr = unpack( ptr, name );
|
||||
ptr = unpack( ptr, data2 );
|
||||
data[name] = std::move( data2 );
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Gather all data to rank 0 *
|
||||
****************************************************************/
|
||||
void Xdmf::gather( const Utilities::MPI &comm )
|
||||
{
|
||||
if ( comm.getRank() == 0 ) {
|
||||
for ( int i = 1; i < comm.getSize(); i++ ) {
|
||||
// Recieve the data
|
||||
size_t N_meshes = 0, N_bytes = 0;
|
||||
comm.recv( &N_meshes, 1, i, 717 );
|
||||
comm.recv( &N_bytes, 1, i, 718 );
|
||||
auto buf = new char[N_bytes];
|
||||
comm.recv( buf, N_bytes, i, 719 );
|
||||
// Unpack the data
|
||||
std::map<std::string, std::vector<MeshData>> data;
|
||||
unpack( buf, data );
|
||||
delete[] buf;
|
||||
// Add the meshes
|
||||
for ( auto tmp : data ) {
|
||||
const auto &name = tmp.first;
|
||||
const auto &domains = tmp.second;
|
||||
if ( domains.size() == 1u && domains[0].name == name ) {
|
||||
// We are dealing with a single mesh
|
||||
ASSERT( d_meshData.find( name ) == d_meshData.end() );
|
||||
d_meshData.insert( tmp );
|
||||
} else {
|
||||
// Add the domains
|
||||
auto &meshes = d_meshData[name];
|
||||
for ( auto domain : domains ) {
|
||||
for ( const auto &tmp : meshes )
|
||||
ASSERT( tmp.name != domain.name );
|
||||
meshes.push_back( domain );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Send the number of meshes
|
||||
size_t N_meshes = d_meshData.size();
|
||||
comm.send( &N_meshes, 1, 0, 717 );
|
||||
// Pack the send data
|
||||
size_t N_bytes = size( d_meshData );
|
||||
comm.send( &N_bytes, 1, 0, 718 );
|
||||
auto buf = new char[N_bytes];
|
||||
pack( buf, d_meshData );
|
||||
// Send the data to rank 0
|
||||
comm.send( buf, N_bytes, 0, 719 );
|
||||
delete[] buf;
|
||||
// Clear the internal data
|
||||
d_meshData.clear();
|
||||
}
|
||||
}
|
131
IO/Xdmf.h
Normal file
131
IO/Xdmf.h
Normal file
|
@ -0,0 +1,131 @@
|
|||
#include "IO/HDF5_IO.h"
|
||||
#include "common/Array.h"
|
||||
#include "common/MPI.h"
|
||||
#include "common/Utilities.h"
|
||||
|
||||
#include <map>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
|
||||
|
||||
// Helper class to write/read XDMF files
|
||||
class Xdmf
|
||||
{
|
||||
public:
|
||||
enum class TopologyType {
|
||||
Null = 0,
|
||||
Polyvertex,
|
||||
Polyline,
|
||||
Polygon,
|
||||
Triangle,
|
||||
Quadrilateral,
|
||||
Tetrahedron,
|
||||
Pyramid,
|
||||
Wedge,
|
||||
Hexahedron,
|
||||
Edge_3,
|
||||
Triangle_6,
|
||||
Quadrilateral_8,
|
||||
Tetrahedron_10,
|
||||
Pyramid_13,
|
||||
Wedge_15,
|
||||
Hexahedron_20,
|
||||
Mixed,
|
||||
CurvilinearMesh2D,
|
||||
CurvilinearMesh3D,
|
||||
RectangularMesh2D,
|
||||
RectangularMesh3D,
|
||||
UniformMesh2D,
|
||||
UniformMesh3D,
|
||||
};
|
||||
enum class DataType { Null = 0, Char, Int32, Int64, Uint32, Uint64, Float, Double };
|
||||
enum class RankType { Null = 0, Scalar, Vector, Tensor, Tensor6, Matrix, GlobalID };
|
||||
enum class Center { Null = 0, Node, Edge, Face, Cell, Grid, Other };
|
||||
|
||||
struct VarData {
|
||||
std::string name; // Variable name
|
||||
ArraySize size; // Size of variable
|
||||
RankType rankType; // Rank order of data
|
||||
Center center; // Variable centering
|
||||
std::string data; // Variable data
|
||||
};
|
||||
|
||||
struct MeshData {
|
||||
std::string name; // Name of mesh
|
||||
TopologyType type; // Type of mesh
|
||||
ArraySize size; // Size of mesh (meaning depends on mesh type)
|
||||
double range[6]; // Range of the mesh (only used for UniformMesh2D/UniformMesh3D)
|
||||
std::string x; // x coordinates (or xy/xyz coordinates)
|
||||
std::string y; // y coordinates
|
||||
std::string z; // z coordinates
|
||||
std::string dofMap; // mesh connectivity
|
||||
std::vector<VarData> vars; // Variables
|
||||
MeshData() : type( TopologyType::Null ), range{ 0 } {}
|
||||
//! Add a variable
|
||||
void addVariable( const std::string &meshName, const std::string &varName,
|
||||
ArraySize varSize, RankType rank, Center center, const std::string &varData );
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
//! Add a Point mesh
|
||||
static MeshData createPointMesh( const std::string &name, uint8_t NDIM, size_t N,
|
||||
const std::string &x, const std::string &y = "", const std::string &z = "" );
|
||||
|
||||
/*!
|
||||
* @brief Add a uniform mesh
|
||||
* @details This function adds a uniform rectangular mesh
|
||||
* @param[in] name The name of the mesh
|
||||
* @param[in] range The range of the mesh [ x_min, x_max, y_min, y_max, z_min, z_max ]
|
||||
* @param[in] size The number of cells in the mesh
|
||||
*/
|
||||
static MeshData createUniformMesh(
|
||||
const std::string &name, const std::vector<double> &range, ArraySize size );
|
||||
|
||||
/*!
|
||||
* @brief Add a Curvilinear mesh
|
||||
* @details This function adds a curvilinear mesh
|
||||
* @param[in] name The name of the mesh
|
||||
* @param[in] size The number of cells in the mesh
|
||||
* @param[in] x The x coordinates or the xy/xyz coordinates
|
||||
* @param[in] y The y coordinates (may be null)
|
||||
* @param[in] z The z coordinates (may be null)
|
||||
*/
|
||||
static MeshData createCurvilinearMesh( const std::string &name, ArraySize size,
|
||||
const std::string &x, const std::string &y, const std::string &z = "" );
|
||||
|
||||
/*!
|
||||
* @brief Add an unstructured mesh
|
||||
* @details This function adds an unstructerd mesh to the class to write.
|
||||
* The mesh may be one of several unsupported unstructured mesh types.
|
||||
* This function does not support mixed elements.
|
||||
* @param[in] name The name of the mesh
|
||||
* @param[in] NDIM The number of physical dimensions
|
||||
* @param[in] type The element type
|
||||
* @param[in] NumElements The number of elements
|
||||
* @param[in] dofMap The connectivity information (type x NumElements)
|
||||
* @param[in] NumNodes The number of nodes
|
||||
* @param[in] x The x coordinates or the xy/xyz coordinates
|
||||
* @param[in] y The y coordinates (may be null)
|
||||
* @param[in] z The z coordinates (may be null)
|
||||
*/
|
||||
static MeshData createUnstructuredMesh( const std::string &name, uint8_t NDIM,
|
||||
TopologyType type, size_t NumElements, const std::string &dofMap, size_t NumNodes,
|
||||
const std::string &x, const std::string &y = "", const std::string &z = "" );
|
||||
|
||||
|
||||
public:
|
||||
//! Add a sub-domain
|
||||
void addMesh( const std::string &meshName, const MeshData &domain );
|
||||
|
||||
//! Gather all data to rank 0
|
||||
void gather( const Utilities::MPI &comm );
|
||||
|
||||
//! Write the xml file
|
||||
void write( const std::string &filename ) const;
|
||||
|
||||
|
||||
private:
|
||||
std::map<std::string, std::vector<MeshData>> d_meshData;
|
||||
};
|
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "IO/netcdf.h"
|
||||
#include "common/MPI.h"
|
||||
#include "common/Utilities.h"
|
||||
|
@ -496,7 +511,7 @@ template void write<double>( int fid, const std::string &var, const std::vector<
|
|||
const Array<double> &data, const RankInfoStruct &info );
|
||||
|
||||
|
||||
}; // namespace netcdf
|
||||
} // namespace netcdf
|
||||
|
||||
#else
|
||||
|
||||
|
|
25
IO/netcdf.h
25
IO/netcdf.h
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef NETCDF_READER
|
||||
#define NETCDF_READER
|
||||
|
||||
|
@ -123,6 +138,8 @@ Array<TYPE> getAtt( int fid, const std::string &att );
|
|||
* @brief Write the dimensions
|
||||
* @details This function writes the grid dimensions to netcdf.
|
||||
* @param fid Handle to the open file
|
||||
* @param names
|
||||
* @param dims
|
||||
*/
|
||||
std::vector<int> defDim(
|
||||
int fid, const std::vector<std::string> &names, const std::vector<int> &dims );
|
||||
|
@ -132,11 +149,17 @@ std::vector<int> defDim(
|
|||
* @brief Write a variable
|
||||
* @details This function writes a variable to netcdf.
|
||||
* @param fid Handle to the open file
|
||||
* @param var Variable to read
|
||||
* @param dimids
|
||||
* @param data
|
||||
* @param rank_info
|
||||
*/
|
||||
template<class TYPE>
|
||||
void write( int fid, const std::string &var, const std::vector<int> &dimids,
|
||||
const Array<TYPE> &data, const RankInfoStruct &rank_info );
|
||||
|
||||
|
||||
}; // namespace netcdf
|
||||
} // namespace netcdf
|
||||
|
||||
|
||||
#endif
|
||||
|
|
21
IO/silo.cpp
21
IO/silo.cpp
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "IO/silo.h"
|
||||
#include "common/MPI.h"
|
||||
#include "common/Utilities.h"
|
||||
|
@ -10,7 +25,8 @@
|
|||
#include <silo.h>
|
||||
|
||||
|
||||
namespace IO::silo {
|
||||
namespace IO {
|
||||
namespace silo {
|
||||
|
||||
|
||||
/****************************************************
|
||||
|
@ -99,7 +115,8 @@ void writeMultiVar( DBfile *fid, const std::string &varname,
|
|||
}
|
||||
|
||||
|
||||
}; // namespace IO::silo
|
||||
} // namespace silo
|
||||
} // namespace IO
|
||||
|
||||
|
||||
#else
|
||||
|
|
19
IO/silo.h
19
IO/silo.h
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SILO_INTERFACE
|
||||
#define SILO_INTERFACE
|
||||
|
||||
|
@ -49,7 +64,7 @@ void close( DBfile *fid );
|
|||
* @param[in] fid Handle to the open file
|
||||
* @param[in] name Name of variable
|
||||
*/
|
||||
DataType varDataType( DBfile *dbfile, const std::string &name );
|
||||
DataType varDataType( DBfile *fid, const std::string &name );
|
||||
|
||||
|
||||
/*!
|
||||
|
@ -250,8 +265,6 @@ void writeMultiMesh( DBfile *fid, const std::string &meshname,
|
|||
* @param[in] varname Mesh name
|
||||
* @param[in] subVarNames Names of the sub meshes in the form "filename:meshname"
|
||||
* @param[in] subVarTypes Type of each submesh
|
||||
* @param[in] ndim Dimension of variable (used to determine suffix)
|
||||
* @param[in] nvar Number of subvariables (used to determine suffix)
|
||||
*/
|
||||
void writeMultiVar( DBfile *fid, const std::string &varname,
|
||||
const std::vector<std::string> &subVarNames, const std::vector<int> &subVarTypes );
|
||||
|
|
32
IO/silo.hpp
32
IO/silo.hpp
|
@ -1,3 +1,33 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SILO_INTERFACE_HPP
|
||||
#define SILO_INTERFACE_HPP
|
||||
|
||||
|
@ -245,11 +275,11 @@ Array<TYPE> readUniformMeshVariable( DBfile *fid, const std::string &varname )
|
|||
copyData<TYPE>( data2, type, var->vals[i] );
|
||||
memcpy( &data( 0, i ), data2.data(), var->nels * sizeof( TYPE ) );
|
||||
}
|
||||
DBFreeQuadvar( var );
|
||||
std::vector<size_t> dims( var->ndims + 1, var->nvals );
|
||||
for ( int d = 0; d < var->ndims; d++ )
|
||||
dims[d] = var->dims[d];
|
||||
data.reshape( dims );
|
||||
DBFreeQuadvar( var );
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
675
LICENSE
675
LICENSE
|
@ -1,3 +1,677 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
Copyright (c) 2015, JamesEMcClure
|
||||
All rights reserved.
|
||||
|
||||
|
@ -21,4 +695,3 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ Configure, build & install procedure
|
|||
|
||||
* edit configure script from sample_scripts directory and configure (e.g.)
|
||||
|
||||
`/path/to/LBPM-WIA/sample_scripts/configure_desktop`
|
||||
`/path/to/LBPM/sample_scripts/configure_desktop`
|
||||
|
||||
* compile and install
|
||||
|
||||
|
|
|
@ -856,7 +856,7 @@ static void getFileAndLineObject( staticVector<StackTrace::stack_info*,blockSize
|
|||
char *buf = tmp2;
|
||||
if ( buf[0] != '?' && buf[0] != 0 ) {
|
||||
size_t j = 0;
|
||||
for ( j = 0; j < 4095 && buf[j] != ':'; j++ ) {
|
||||
for ( j = 0; j < 1024 && buf[j] != ':'; j++ ) {
|
||||
}
|
||||
buf[j] = 0;
|
||||
copy( buf, info[i]->filename, info[i]->filenamePath );
|
||||
|
|
|
@ -1,3 +1,18 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef included_StackTrace
|
||||
#define included_StackTrace
|
||||
|
||||
|
|
|
@ -1,137 +1,177 @@
|
|||
#include "analysis/ElectroChemistry.h"
|
||||
|
||||
ElectroChemistryAnalyzer::ElectroChemistryAnalyzer(std::shared_ptr <Domain> dm):
|
||||
Dm(dm)
|
||||
{
|
||||
|
||||
Nx=dm->Nx; Ny=dm->Ny; Nz=dm->Nz;
|
||||
Volume=(Nx-2)*(Ny-2)*(Nz-2)*Dm->nprocx()*Dm->nprocy()*Dm->nprocz()*1.0;
|
||||
|
||||
ChemicalPotential.resize(Nx,Ny,Nz); ChemicalPotential.fill(0);
|
||||
ElectricalPotential.resize(Nx,Ny,Nz); ElectricalPotential.fill(0);
|
||||
Pressure.resize(Nx,Ny,Nz); Pressure.fill(0);
|
||||
Rho.resize(Nx,Ny,Nz); Rho.fill(0);
|
||||
Vel_x.resize(Nx,Ny,Nz); Vel_x.fill(0); // Gradient of the phase indicator field
|
||||
Vel_y.resize(Nx,Ny,Nz); Vel_y.fill(0);
|
||||
Vel_z.resize(Nx,Ny,Nz); Vel_z.fill(0);
|
||||
SDs.resize(Nx,Ny,Nz); SDs.fill(0);
|
||||
|
||||
if (Dm->rank()==0){
|
||||
bool WriteHeader=false;
|
||||
TIMELOG = fopen("electrokinetic.csv","r");
|
||||
if (TIMELOG != NULL)
|
||||
fclose(TIMELOG);
|
||||
else
|
||||
WriteHeader=true;
|
||||
ElectroChemistryAnalyzer::ElectroChemistryAnalyzer(std::shared_ptr<Domain> dm)
|
||||
: Dm(dm) {
|
||||
|
||||
TIMELOG = fopen("electrokinetic.csv","a+");
|
||||
if (WriteHeader)
|
||||
{
|
||||
// If timelog is empty, write a short header to list the averages
|
||||
//fprintf(TIMELOG,"--------------------------------------------------------------------------------------\n");
|
||||
fprintf(TIMELOG,"TBD TBD\n");
|
||||
}
|
||||
}
|
||||
Nx = dm->Nx;
|
||||
Ny = dm->Ny;
|
||||
Nz = dm->Nz;
|
||||
Volume = (Nx - 2) * (Ny - 2) * (Nz - 2) * Dm->nprocx() * Dm->nprocy() *
|
||||
Dm->nprocz() * 1.0;
|
||||
|
||||
ChemicalPotential.resize(Nx, Ny, Nz);
|
||||
ChemicalPotential.fill(0);
|
||||
ElectricalPotential.resize(Nx, Ny, Nz);
|
||||
ElectricalPotential.fill(0);
|
||||
ElectricalField_x.resize(Nx, Ny, Nz);
|
||||
ElectricalField_x.fill(0);
|
||||
ElectricalField_y.resize(Nx, Ny, Nz);
|
||||
ElectricalField_y.fill(0);
|
||||
ElectricalField_z.resize(Nx, Ny, Nz);
|
||||
ElectricalField_z.fill(0);
|
||||
Pressure.resize(Nx, Ny, Nz);
|
||||
Pressure.fill(0);
|
||||
Rho.resize(Nx, Ny, Nz);
|
||||
Rho.fill(0);
|
||||
Vel_x.resize(Nx, Ny, Nz);
|
||||
Vel_x.fill(0); // Gradient of the phase indicator field
|
||||
Vel_y.resize(Nx, Ny, Nz);
|
||||
Vel_y.fill(0);
|
||||
Vel_z.resize(Nx, Ny, Nz);
|
||||
Vel_z.fill(0);
|
||||
SDs.resize(Nx, Ny, Nz);
|
||||
SDs.fill(0);
|
||||
IonFluxDiffusive_x.resize(Nx, Ny, Nz);
|
||||
IonFluxDiffusive_x.fill(0);
|
||||
IonFluxDiffusive_y.resize(Nx, Ny, Nz);
|
||||
IonFluxDiffusive_y.fill(0);
|
||||
IonFluxDiffusive_z.resize(Nx, Ny, Nz);
|
||||
IonFluxDiffusive_z.fill(0);
|
||||
IonFluxAdvective_x.resize(Nx, Ny, Nz);
|
||||
IonFluxAdvective_x.fill(0);
|
||||
IonFluxAdvective_y.resize(Nx, Ny, Nz);
|
||||
IonFluxAdvective_y.fill(0);
|
||||
IonFluxAdvective_z.resize(Nx, Ny, Nz);
|
||||
IonFluxAdvective_z.fill(0);
|
||||
IonFluxElectrical_x.resize(Nx, Ny, Nz);
|
||||
IonFluxElectrical_x.fill(0);
|
||||
IonFluxElectrical_y.resize(Nx, Ny, Nz);
|
||||
IonFluxElectrical_y.fill(0);
|
||||
IonFluxElectrical_z.resize(Nx, Ny, Nz);
|
||||
IonFluxElectrical_z.fill(0);
|
||||
|
||||
if (Dm->rank() == 0) {
|
||||
bool WriteHeader = false;
|
||||
TIMELOG = fopen("electrokinetic.csv", "r");
|
||||
if (TIMELOG != NULL)
|
||||
fclose(TIMELOG);
|
||||
else
|
||||
WriteHeader = true;
|
||||
|
||||
TIMELOG = fopen("electrokinetic.csv", "a+");
|
||||
if (WriteHeader) {
|
||||
// If timelog is empty, write a short header to list the averages
|
||||
//fprintf(TIMELOG,"--------------------------------------------------------------------------------------\n");
|
||||
fprintf(TIMELOG, "TBD TBD\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ElectroChemistryAnalyzer::~ElectroChemistryAnalyzer(){
|
||||
if (Dm->rank()==0){
|
||||
fclose(TIMELOG);
|
||||
}
|
||||
ElectroChemistryAnalyzer::~ElectroChemistryAnalyzer() {
|
||||
if (Dm->rank() == 0) {
|
||||
fclose(TIMELOG);
|
||||
}
|
||||
}
|
||||
|
||||
void ElectroChemistryAnalyzer::SetParams(){
|
||||
|
||||
}
|
||||
void ElectroChemistryAnalyzer::SetParams() {}
|
||||
|
||||
void ElectroChemistryAnalyzer::Basic(ScaLBL_IonModel &Ion, ScaLBL_Poisson &Poisson, ScaLBL_StokesModel &Stokes, int timestep){
|
||||
void ElectroChemistryAnalyzer::Basic(ScaLBL_IonModel &Ion,
|
||||
ScaLBL_Poisson &Poisson,
|
||||
ScaLBL_StokesModel &Stokes, int timestep) {
|
||||
|
||||
int i,j,k;
|
||||
double Vin=0.0;
|
||||
double Vout=0.0;
|
||||
Poisson.getElectricPotential(ElectricalPotential);
|
||||
|
||||
/* local sub-domain averages */
|
||||
double *rho_avg_local;
|
||||
double *rho_mu_avg_local;
|
||||
double *rho_mu_fluctuation_local;
|
||||
double *rho_psi_avg_local;
|
||||
double *rho_psi_fluctuation_local;
|
||||
/* global averages */
|
||||
double *rho_avg_global;
|
||||
double *rho_mu_avg_global;
|
||||
double *rho_mu_fluctuation_global;
|
||||
double *rho_psi_avg_global;
|
||||
double *rho_psi_fluctuation_global;
|
||||
|
||||
/* local sub-domain averages */
|
||||
rho_avg_local = new double [Ion.number_ion_species];
|
||||
rho_mu_avg_local = new double [Ion.number_ion_species];
|
||||
rho_mu_fluctuation_local = new double [Ion.number_ion_species];
|
||||
rho_psi_avg_local = new double [Ion.number_ion_species];
|
||||
rho_psi_fluctuation_local = new double [Ion.number_ion_species];
|
||||
/* global averages */
|
||||
rho_avg_global = new double [Ion.number_ion_species];
|
||||
rho_mu_avg_global = new double [Ion.number_ion_species];
|
||||
rho_mu_fluctuation_global = new double [Ion.number_ion_species];
|
||||
rho_psi_avg_global = new double [Ion.number_ion_species];
|
||||
rho_psi_fluctuation_global = new double [Ion.number_ion_species];
|
||||
|
||||
for (size_t ion=0; ion<Ion.number_ion_species; ion++){
|
||||
rho_avg_local[ion] = 0.0;
|
||||
rho_mu_avg_local[ion] = 0.0;
|
||||
rho_psi_avg_local[ion] = 0.0;
|
||||
Ion.getIonConcentration(Rho,ion);
|
||||
/* Compute averages for each ion */
|
||||
for (k=1; k<Nz; k++){
|
||||
for (j=1; j<Ny; j++){
|
||||
for (i=1; i<Nx; i++){
|
||||
rho_avg_local[ion] += Rho(i,j,k);
|
||||
rho_mu_avg_local[ion] += Rho(i,j,k)*Rho(i,j,k);
|
||||
rho_psi_avg_local[ion] += Rho(i,j,k)*ElectricalPotential(i,j,k);
|
||||
}
|
||||
}
|
||||
}
|
||||
rho_avg_global[ion]=Dm->Comm.sumReduce( rho_avg_local[ion]) / Volume;
|
||||
rho_mu_avg_global[ion]=Dm->Comm.sumReduce( rho_mu_avg_local[ion]) / Volume;
|
||||
rho_psi_avg_global[ion]=Dm->Comm.sumReduce( rho_psi_avg_local[ion]) / Volume;
|
||||
int i, j, k;
|
||||
double Vin = 0.0;
|
||||
double Vout = 0.0;
|
||||
Poisson.getElectricPotential(ElectricalPotential);
|
||||
|
||||
if (rho_avg_global[ion] > 0.0){
|
||||
rho_mu_avg_global[ion] /= rho_avg_global[ion];
|
||||
rho_psi_avg_global[ion] /= rho_avg_global[ion];
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t ion=0; ion<Ion.number_ion_species; ion++){
|
||||
rho_mu_fluctuation_local[ion] = 0.0;
|
||||
rho_psi_fluctuation_local[ion] = 0.0;
|
||||
/* Compute averages for each ion */
|
||||
for (k=1; k<Nz; k++){
|
||||
for (j=1; j<Ny; j++){
|
||||
for (i=1; i<Nx; i++){
|
||||
rho_mu_fluctuation_local[ion] += (Rho(i,j,k)*Rho(i,j,k) - rho_mu_avg_global[ion]);
|
||||
rho_psi_fluctuation_local[ion] += (Rho(i,j,k)*ElectricalPotential(i,j,k) - rho_psi_avg_global[ion]);
|
||||
}
|
||||
}
|
||||
}
|
||||
rho_mu_fluctuation_global[ion]=Dm->Comm.sumReduce( rho_mu_fluctuation_local[ion]);
|
||||
rho_psi_fluctuation_global[ion]=Dm->Comm.sumReduce( rho_psi_fluctuation_local[ion]);
|
||||
}
|
||||
|
||||
if (Dm->rank()==0){
|
||||
fprintf(TIMELOG,"%i ",timestep);
|
||||
for (size_t ion=0; ion<Ion.number_ion_species; ion++){
|
||||
fprintf(TIMELOG,"%.8g ",rho_avg_global[ion]);
|
||||
fprintf(TIMELOG,"%.8g ",rho_mu_avg_global[ion]);
|
||||
fprintf(TIMELOG,"%.8g ",rho_psi_avg_global[ion]);
|
||||
fprintf(TIMELOG,"%.8g ",rho_mu_fluctuation_global[ion]);
|
||||
fprintf(TIMELOG,"%.8g ",rho_psi_fluctuation_global[ion]);
|
||||
}
|
||||
fprintf(TIMELOG,"%.8g %.8g\n",Vin,Vout);
|
||||
fflush(TIMELOG);
|
||||
}
|
||||
/* else{
|
||||
/* local sub-domain averages */
|
||||
double *rho_avg_local;
|
||||
double *rho_mu_avg_local;
|
||||
double *rho_mu_fluctuation_local;
|
||||
double *rho_psi_avg_local;
|
||||
double *rho_psi_fluctuation_local;
|
||||
/* global averages */
|
||||
double *rho_avg_global;
|
||||
double *rho_mu_avg_global;
|
||||
double *rho_mu_fluctuation_global;
|
||||
double *rho_psi_avg_global;
|
||||
double *rho_psi_fluctuation_global;
|
||||
|
||||
/* local sub-domain averages */
|
||||
rho_avg_local = new double[Ion.number_ion_species];
|
||||
rho_mu_avg_local = new double[Ion.number_ion_species];
|
||||
rho_mu_fluctuation_local = new double[Ion.number_ion_species];
|
||||
rho_psi_avg_local = new double[Ion.number_ion_species];
|
||||
rho_psi_fluctuation_local = new double[Ion.number_ion_species];
|
||||
/* global averages */
|
||||
rho_avg_global = new double[Ion.number_ion_species];
|
||||
rho_mu_avg_global = new double[Ion.number_ion_species];
|
||||
rho_mu_fluctuation_global = new double[Ion.number_ion_species];
|
||||
rho_psi_avg_global = new double[Ion.number_ion_species];
|
||||
rho_psi_fluctuation_global = new double[Ion.number_ion_species];
|
||||
|
||||
for (size_t ion = 0; ion < Ion.number_ion_species; ion++) {
|
||||
rho_avg_local[ion] = 0.0;
|
||||
rho_mu_avg_local[ion] = 0.0;
|
||||
rho_psi_avg_local[ion] = 0.0;
|
||||
Ion.getIonConcentration(Rho, ion);
|
||||
/* Compute averages for each ion */
|
||||
for (k = 1; k < Nz; k++) {
|
||||
for (j = 1; j < Ny; j++) {
|
||||
for (i = 1; i < Nx; i++) {
|
||||
rho_avg_local[ion] += Rho(i, j, k);
|
||||
rho_mu_avg_local[ion] += Rho(i, j, k) * Rho(i, j, k);
|
||||
rho_psi_avg_local[ion] +=
|
||||
Rho(i, j, k) * ElectricalPotential(i, j, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
rho_avg_global[ion] = Dm->Comm.sumReduce(rho_avg_local[ion]) / Volume;
|
||||
rho_mu_avg_global[ion] =
|
||||
Dm->Comm.sumReduce(rho_mu_avg_local[ion]) / Volume;
|
||||
rho_psi_avg_global[ion] =
|
||||
Dm->Comm.sumReduce(rho_psi_avg_local[ion]) / Volume;
|
||||
|
||||
if (rho_avg_global[ion] > 0.0) {
|
||||
rho_mu_avg_global[ion] /= rho_avg_global[ion];
|
||||
rho_psi_avg_global[ion] /= rho_avg_global[ion];
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t ion = 0; ion < Ion.number_ion_species; ion++) {
|
||||
rho_mu_fluctuation_local[ion] = 0.0;
|
||||
rho_psi_fluctuation_local[ion] = 0.0;
|
||||
/* Compute averages for each ion */
|
||||
for (k = 1; k < Nz; k++) {
|
||||
for (j = 1; j < Ny; j++) {
|
||||
for (i = 1; i < Nx; i++) {
|
||||
rho_mu_fluctuation_local[ion] +=
|
||||
(Rho(i, j, k) * Rho(i, j, k) - rho_mu_avg_global[ion]);
|
||||
rho_psi_fluctuation_local[ion] +=
|
||||
(Rho(i, j, k) * ElectricalPotential(i, j, k) -
|
||||
rho_psi_avg_global[ion]);
|
||||
}
|
||||
}
|
||||
}
|
||||
rho_mu_fluctuation_global[ion] =
|
||||
Dm->Comm.sumReduce(rho_mu_fluctuation_local[ion]);
|
||||
rho_psi_fluctuation_global[ion] =
|
||||
Dm->Comm.sumReduce(rho_psi_fluctuation_local[ion]);
|
||||
}
|
||||
|
||||
if (Dm->rank() == 0) {
|
||||
fprintf(TIMELOG, "%i ", timestep);
|
||||
for (size_t ion = 0; ion < Ion.number_ion_species; ion++) {
|
||||
fprintf(TIMELOG, "%.8g ", rho_avg_global[ion]);
|
||||
fprintf(TIMELOG, "%.8g ", rho_mu_avg_global[ion]);
|
||||
fprintf(TIMELOG, "%.8g ", rho_psi_avg_global[ion]);
|
||||
fprintf(TIMELOG, "%.8g ", rho_mu_fluctuation_global[ion]);
|
||||
fprintf(TIMELOG, "%.8g ", rho_psi_fluctuation_global[ion]);
|
||||
}
|
||||
fprintf(TIMELOG, "%.8g %.8g\n", Vin, Vout);
|
||||
fflush(TIMELOG);
|
||||
}
|
||||
/* else{
|
||||
fprintf(TIMELOG,"%i ",timestep);
|
||||
for (int ion=0; ion<Ion.number_ion_species; ion++){
|
||||
fprintf(TIMELOG,"%.8g ",rho_avg_local[ion]);
|
||||
|
@ -144,104 +184,414 @@ void ElectroChemistryAnalyzer::Basic(ScaLBL_IonModel &Ion, ScaLBL_Poisson &Poiss
|
|||
} */
|
||||
}
|
||||
|
||||
void ElectroChemistryAnalyzer::WriteVis( ScaLBL_IonModel &Ion, ScaLBL_Poisson &Poisson, ScaLBL_StokesModel &Stokes, std::shared_ptr<Database> input_db, int timestep){
|
||||
|
||||
auto vis_db = input_db->getDatabase( "Visualization" );
|
||||
char VisName[40];
|
||||
|
||||
std::vector<IO::MeshDataStruct> visData;
|
||||
fillHalo<double> fillData(Dm->Comm,Dm->rank_info,{Dm->Nx-2,Dm->Ny-2,Dm->Nz-2},{1,1,1},0,1);
|
||||
void ElectroChemistryAnalyzer::WriteVis(ScaLBL_IonModel &Ion,
|
||||
ScaLBL_Poisson &Poisson,
|
||||
ScaLBL_StokesModel &Stokes,
|
||||
std::shared_ptr<Database> input_db,
|
||||
int timestep) {
|
||||
|
||||
IO::initialize("","silo","false");
|
||||
auto vis_db = input_db->getDatabase("Visualization");
|
||||
char VisName[40];
|
||||
auto format = vis_db->getWithDefault<string>( "format", "hdf5" );
|
||||
|
||||
std::vector<IO::MeshDataStruct> visData;
|
||||
fillHalo<double> fillData(Dm->Comm, Dm->rank_info,
|
||||
{Dm->Nx - 2, Dm->Ny - 2, Dm->Nz - 2}, {1, 1, 1},
|
||||
0, 1);
|
||||
|
||||
IO::initialize("",format,"false");
|
||||
// Create the MeshDataStruct
|
||||
visData.resize(1);
|
||||
|
||||
visData[0].meshName = "domain";
|
||||
visData[0].mesh = std::make_shared<IO::DomainMesh>( Dm->rank_info,Dm->Nx-2,Dm->Ny-2,Dm->Nz-2,Dm->Lx,Dm->Ly,Dm->Lz );
|
||||
auto ElectricPotential = std::make_shared<IO::Variable>();
|
||||
visData[0].mesh =
|
||||
std::make_shared<IO::DomainMesh>(Dm->rank_info, Dm->Nx - 2, Dm->Ny - 2,
|
||||
Dm->Nz - 2, Dm->Lx, Dm->Ly, Dm->Lz);
|
||||
//electric potential
|
||||
auto ElectricPotentialVar = std::make_shared<IO::Variable>();
|
||||
//electric field
|
||||
auto ElectricFieldVar_x = std::make_shared<IO::Variable>();
|
||||
auto ElectricFieldVar_y = std::make_shared<IO::Variable>();
|
||||
auto ElectricFieldVar_z = std::make_shared<IO::Variable>();
|
||||
|
||||
//ion concentration
|
||||
std::vector<shared_ptr<IO::Variable>> IonConcentration;
|
||||
for (size_t ion=0; ion<Ion.number_ion_species; ion++){
|
||||
for (size_t ion = 0; ion < Ion.number_ion_species; ion++) {
|
||||
IonConcentration.push_back(std::make_shared<IO::Variable>());
|
||||
}
|
||||
//fluid velocity
|
||||
auto VxVar = std::make_shared<IO::Variable>();
|
||||
auto VyVar = std::make_shared<IO::Variable>();
|
||||
auto VzVar = std::make_shared<IO::Variable>();
|
||||
|
||||
if (vis_db->getWithDefault<bool>( "save_electric_potential", true )){
|
||||
ElectricPotential->name = "ElectricPotential";
|
||||
ElectricPotential->type = IO::VariableType::VolumeVariable;
|
||||
ElectricPotential->dim = 1;
|
||||
ElectricPotential->data.resize(Dm->Nx-2,Dm->Ny-2,Dm->Nz-2);
|
||||
visData[0].vars.push_back(ElectricPotential);
|
||||
// diffusive ion flux
|
||||
std::vector<shared_ptr<IO::Variable>> IonFluxDiffusive;
|
||||
for (size_t ion = 0; ion < Ion.number_ion_species; ion++) {
|
||||
//push in x-,y-, and z-component for each ion species
|
||||
IonFluxDiffusive.push_back(std::make_shared<IO::Variable>());
|
||||
IonFluxDiffusive.push_back(std::make_shared<IO::Variable>());
|
||||
IonFluxDiffusive.push_back(std::make_shared<IO::Variable>());
|
||||
}
|
||||
// advective ion flux
|
||||
std::vector<shared_ptr<IO::Variable>> IonFluxAdvective;
|
||||
for (size_t ion = 0; ion < Ion.number_ion_species; ion++) {
|
||||
//push in x-,y-, and z-component for each ion species
|
||||
IonFluxAdvective.push_back(std::make_shared<IO::Variable>());
|
||||
IonFluxAdvective.push_back(std::make_shared<IO::Variable>());
|
||||
IonFluxAdvective.push_back(std::make_shared<IO::Variable>());
|
||||
}
|
||||
// electro-migrational ion flux
|
||||
std::vector<shared_ptr<IO::Variable>> IonFluxElectrical;
|
||||
for (size_t ion = 0; ion < Ion.number_ion_species; ion++) {
|
||||
//push in x-,y-, and z-component for each ion species
|
||||
IonFluxElectrical.push_back(std::make_shared<IO::Variable>());
|
||||
IonFluxElectrical.push_back(std::make_shared<IO::Variable>());
|
||||
IonFluxElectrical.push_back(std::make_shared<IO::Variable>());
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------Create Names for Variables------------------------------------------------------
|
||||
if (vis_db->getWithDefault<bool>("save_electric_potential", true)) {
|
||||
ElectricPotentialVar->name = "ElectricPotential";
|
||||
ElectricPotentialVar->type = IO::VariableType::VolumeVariable;
|
||||
ElectricPotentialVar->dim = 1;
|
||||
ElectricPotentialVar->data.resize(Dm->Nx - 2, Dm->Ny - 2, Dm->Nz - 2);
|
||||
visData[0].vars.push_back(ElectricPotentialVar);
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>( "save_concentration", true )){
|
||||
for (size_t ion=0; ion<Ion.number_ion_species; ion++){
|
||||
sprintf(VisName,"IonConcentration_%zu",ion+1);
|
||||
IonConcentration[ion]->name = VisName;
|
||||
IonConcentration[ion]->type = IO::VariableType::VolumeVariable;
|
||||
IonConcentration[ion]->dim = 1;
|
||||
IonConcentration[ion]->data.resize(Dm->Nx-2,Dm->Ny-2,Dm->Nz-2);
|
||||
visData[0].vars.push_back(IonConcentration[ion]);
|
||||
}
|
||||
if (vis_db->getWithDefault<bool>("save_concentration", true)) {
|
||||
for (size_t ion = 0; ion < Ion.number_ion_species; ion++) {
|
||||
sprintf(VisName, "IonConcentration_%zu", ion + 1);
|
||||
IonConcentration[ion]->name = VisName;
|
||||
IonConcentration[ion]->type = IO::VariableType::VolumeVariable;
|
||||
IonConcentration[ion]->dim = 1;
|
||||
IonConcentration[ion]->data.resize(Dm->Nx - 2, Dm->Ny - 2,
|
||||
Dm->Nz - 2);
|
||||
visData[0].vars.push_back(IonConcentration[ion]);
|
||||
}
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>( "save_velocity", false )){
|
||||
if (vis_db->getWithDefault<bool>("save_velocity", false)) {
|
||||
VxVar->name = "Velocity_x";
|
||||
VxVar->type = IO::VariableType::VolumeVariable;
|
||||
VxVar->dim = 1;
|
||||
VxVar->data.resize(Dm->Nx-2,Dm->Ny-2,Dm->Nz-2);
|
||||
VxVar->data.resize(Dm->Nx - 2, Dm->Ny - 2, Dm->Nz - 2);
|
||||
visData[0].vars.push_back(VxVar);
|
||||
VyVar->name = "Velocity_y";
|
||||
VyVar->type = IO::VariableType::VolumeVariable;
|
||||
VyVar->dim = 1;
|
||||
VyVar->data.resize(Dm->Nx-2,Dm->Ny-2,Dm->Nz-2);
|
||||
VyVar->data.resize(Dm->Nx - 2, Dm->Ny - 2, Dm->Nz - 2);
|
||||
visData[0].vars.push_back(VyVar);
|
||||
VzVar->name = "Velocity_z";
|
||||
VzVar->type = IO::VariableType::VolumeVariable;
|
||||
VzVar->dim = 1;
|
||||
VzVar->data.resize(Dm->Nx-2,Dm->Ny-2,Dm->Nz-2);
|
||||
VzVar->data.resize(Dm->Nx - 2, Dm->Ny - 2, Dm->Nz - 2);
|
||||
visData[0].vars.push_back(VzVar);
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>( "save_electric_potential", true )){
|
||||
ASSERT(visData[0].vars[0]->name=="ElectricPotential");
|
||||
Poisson.getElectricPotential(ElectricalPotential);
|
||||
Array<double>& ElectricPotentialData = visData[0].vars[0]->data;
|
||||
fillData.copy(ElectricalPotential,ElectricPotentialData);
|
||||
|
||||
if (vis_db->getWithDefault<bool>("save_ion_flux_diffusive", false)) {
|
||||
for (size_t ion = 0; ion < Ion.number_ion_species; ion++) {
|
||||
// x-component of diffusive flux
|
||||
sprintf(VisName, "Ion%zu_FluxDiffusive_x", ion + 1);
|
||||
IonFluxDiffusive[3 * ion + 0]->name = VisName;
|
||||
IonFluxDiffusive[3 * ion + 0]->type =
|
||||
IO::VariableType::VolumeVariable;
|
||||
IonFluxDiffusive[3 * ion + 0]->dim = 1;
|
||||
IonFluxDiffusive[3 * ion + 0]->data.resize(Dm->Nx - 2, Dm->Ny - 2,
|
||||
Dm->Nz - 2);
|
||||
visData[0].vars.push_back(IonFluxDiffusive[3 * ion + 0]);
|
||||
// y-component of diffusive flux
|
||||
sprintf(VisName, "Ion%zu_FluxDiffusive_y", ion + 1);
|
||||
IonFluxDiffusive[3 * ion + 1]->name = VisName;
|
||||
IonFluxDiffusive[3 * ion + 1]->type =
|
||||
IO::VariableType::VolumeVariable;
|
||||
IonFluxDiffusive[3 * ion + 1]->dim = 1;
|
||||
IonFluxDiffusive[3 * ion + 1]->data.resize(Dm->Nx - 2, Dm->Ny - 2,
|
||||
Dm->Nz - 2);
|
||||
visData[0].vars.push_back(IonFluxDiffusive[3 * ion + 1]);
|
||||
// z-component of diffusive flux
|
||||
sprintf(VisName, "Ion%zu_FluxDiffusive_z", ion + 1);
|
||||
IonFluxDiffusive[3 * ion + 2]->name = VisName;
|
||||
IonFluxDiffusive[3 * ion + 2]->type =
|
||||
IO::VariableType::VolumeVariable;
|
||||
IonFluxDiffusive[3 * ion + 2]->dim = 1;
|
||||
IonFluxDiffusive[3 * ion + 2]->data.resize(Dm->Nx - 2, Dm->Ny - 2,
|
||||
Dm->Nz - 2);
|
||||
visData[0].vars.push_back(IonFluxDiffusive[3 * ion + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>( "save_concentration", true )){
|
||||
for (size_t ion=0; ion<Ion.number_ion_species; ion++){
|
||||
sprintf(VisName,"IonConcentration_%zu",ion+1);
|
||||
IonConcentration[ion]->name = VisName;
|
||||
ASSERT(visData[0].vars[1+ion]->name==VisName);
|
||||
Array<double>& IonConcentrationData = visData[0].vars[1+ion]->data;
|
||||
Ion.getIonConcentration(Rho,ion);
|
||||
fillData.copy(Rho,IonConcentrationData);
|
||||
}
|
||||
if (vis_db->getWithDefault<bool>("save_ion_flux_advective", false)) {
|
||||
for (size_t ion = 0; ion < Ion.number_ion_species; ion++) {
|
||||
// x-component of advective flux
|
||||
sprintf(VisName, "Ion%zu_FluxAdvective_x", ion + 1);
|
||||
IonFluxAdvective[3 * ion + 0]->name = VisName;
|
||||
IonFluxAdvective[3 * ion + 0]->type =
|
||||
IO::VariableType::VolumeVariable;
|
||||
IonFluxAdvective[3 * ion + 0]->dim = 1;
|
||||
IonFluxAdvective[3 * ion + 0]->data.resize(Dm->Nx - 2, Dm->Ny - 2,
|
||||
Dm->Nz - 2);
|
||||
visData[0].vars.push_back(IonFluxAdvective[3 * ion + 0]);
|
||||
// y-component of advective flux
|
||||
sprintf(VisName, "Ion%zu_FluxAdvective_y", ion + 1);
|
||||
IonFluxAdvective[3 * ion + 1]->name = VisName;
|
||||
IonFluxAdvective[3 * ion + 1]->type =
|
||||
IO::VariableType::VolumeVariable;
|
||||
IonFluxAdvective[3 * ion + 1]->dim = 1;
|
||||
IonFluxAdvective[3 * ion + 1]->data.resize(Dm->Nx - 2, Dm->Ny - 2,
|
||||
Dm->Nz - 2);
|
||||
visData[0].vars.push_back(IonFluxAdvective[3 * ion + 1]);
|
||||
// z-component of advective flux
|
||||
sprintf(VisName, "Ion%zu_FluxAdvective_z", ion + 1);
|
||||
IonFluxAdvective[3 * ion + 2]->name = VisName;
|
||||
IonFluxAdvective[3 * ion + 2]->type =
|
||||
IO::VariableType::VolumeVariable;
|
||||
IonFluxAdvective[3 * ion + 2]->dim = 1;
|
||||
IonFluxAdvective[3 * ion + 2]->data.resize(Dm->Nx - 2, Dm->Ny - 2,
|
||||
Dm->Nz - 2);
|
||||
visData[0].vars.push_back(IonFluxAdvective[3 * ion + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>( "save_velocity", false )){
|
||||
ASSERT(visData[0].vars[1+Ion.number_ion_species+0]->name=="Velocity_x");
|
||||
ASSERT(visData[0].vars[1+Ion.number_ion_species+1]->name=="Velocity_y");
|
||||
ASSERT(visData[0].vars[1+Ion.number_ion_species+2]->name=="Velocity_z");
|
||||
Stokes.getVelocity(Vel_x,Vel_y,Vel_z);
|
||||
Array<double>& VelxData = visData[0].vars[1+Ion.number_ion_species+0]->data;
|
||||
Array<double>& VelyData = visData[0].vars[1+Ion.number_ion_species+1]->data;
|
||||
Array<double>& VelzData = visData[0].vars[1+Ion.number_ion_species+2]->data;
|
||||
fillData.copy(Vel_x,VelxData);
|
||||
fillData.copy(Vel_y,VelyData);
|
||||
fillData.copy(Vel_z,VelzData);
|
||||
if (vis_db->getWithDefault<bool>("save_ion_flux_electrical", false)) {
|
||||
for (size_t ion = 0; ion < Ion.number_ion_species; ion++) {
|
||||
// x-component of electro-migrational flux
|
||||
sprintf(VisName, "Ion%zu_FluxElectrical_x", ion + 1);
|
||||
IonFluxElectrical[3 * ion + 0]->name = VisName;
|
||||
IonFluxElectrical[3 * ion + 0]->type =
|
||||
IO::VariableType::VolumeVariable;
|
||||
IonFluxElectrical[3 * ion + 0]->dim = 1;
|
||||
IonFluxElectrical[3 * ion + 0]->data.resize(Dm->Nx - 2, Dm->Ny - 2,
|
||||
Dm->Nz - 2);
|
||||
visData[0].vars.push_back(IonFluxElectrical[3 * ion + 0]);
|
||||
// y-component of electro-migrational flux
|
||||
sprintf(VisName, "Ion%zu_FluxElectrical_y", ion + 1);
|
||||
IonFluxElectrical[3 * ion + 1]->name = VisName;
|
||||
IonFluxElectrical[3 * ion + 1]->type =
|
||||
IO::VariableType::VolumeVariable;
|
||||
IonFluxElectrical[3 * ion + 1]->dim = 1;
|
||||
IonFluxElectrical[3 * ion + 1]->data.resize(Dm->Nx - 2, Dm->Ny - 2,
|
||||
Dm->Nz - 2);
|
||||
visData[0].vars.push_back(IonFluxElectrical[3 * ion + 1]);
|
||||
// z-component of electro-migrational flux
|
||||
sprintf(VisName, "Ion%zu_FluxElectrical_z", ion + 1);
|
||||
IonFluxElectrical[3 * ion + 2]->name = VisName;
|
||||
IonFluxElectrical[3 * ion + 2]->type =
|
||||
IO::VariableType::VolumeVariable;
|
||||
IonFluxElectrical[3 * ion + 2]->dim = 1;
|
||||
IonFluxElectrical[3 * ion + 2]->data.resize(Dm->Nx - 2, Dm->Ny - 2,
|
||||
Dm->Nz - 2);
|
||||
visData[0].vars.push_back(IonFluxElectrical[3 * ion + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>( "write_silo", true ))
|
||||
IO::writeData( timestep, visData, Dm->Comm );
|
||||
|
||||
/* if (vis_db->getWithDefault<bool>( "save_8bit_raw", true )){
|
||||
if (vis_db->getWithDefault<bool>("save_electric_field", false)) {
|
||||
ElectricFieldVar_x->name = "ElectricField_x";
|
||||
ElectricFieldVar_x->type = IO::VariableType::VolumeVariable;
|
||||
ElectricFieldVar_x->dim = 1;
|
||||
ElectricFieldVar_x->data.resize(Dm->Nx - 2, Dm->Ny - 2, Dm->Nz - 2);
|
||||
visData[0].vars.push_back(ElectricFieldVar_x);
|
||||
ElectricFieldVar_y->name = "ElectricField_y";
|
||||
ElectricFieldVar_y->type = IO::VariableType::VolumeVariable;
|
||||
ElectricFieldVar_y->dim = 1;
|
||||
ElectricFieldVar_y->data.resize(Dm->Nx - 2, Dm->Ny - 2, Dm->Nz - 2);
|
||||
visData[0].vars.push_back(ElectricFieldVar_y);
|
||||
ElectricFieldVar_z->name = "ElectricField_z";
|
||||
ElectricFieldVar_z->type = IO::VariableType::VolumeVariable;
|
||||
ElectricFieldVar_z->dim = 1;
|
||||
ElectricFieldVar_z->data.resize(Dm->Nx - 2, Dm->Ny - 2, Dm->Nz - 2);
|
||||
visData[0].vars.push_back(ElectricFieldVar_z);
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------Save All Variables--------------------------------------------------------------
|
||||
if (vis_db->getWithDefault<bool>("save_electric_potential", true)) {
|
||||
ASSERT(visData[0].vars[0]->name == "ElectricPotential");
|
||||
Poisson.getElectricPotential(ElectricalPotential);
|
||||
Array<double> &ElectricPotentialData = visData[0].vars[0]->data;
|
||||
fillData.copy(ElectricalPotential, ElectricPotentialData);
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>("save_concentration", true)) {
|
||||
for (size_t ion = 0; ion < Ion.number_ion_species; ion++) {
|
||||
sprintf(VisName, "IonConcentration_%zu", ion + 1);
|
||||
//IonConcentration[ion]->name = VisName;
|
||||
ASSERT(visData[0].vars[1 + ion]->name == VisName);
|
||||
Array<double> &IonConcentrationData =
|
||||
visData[0].vars[1 + ion]->data;
|
||||
Ion.getIonConcentration(Rho, ion);
|
||||
fillData.copy(Rho, IonConcentrationData);
|
||||
}
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>("save_velocity", false)) {
|
||||
ASSERT(visData[0].vars[1 + Ion.number_ion_species + 0]->name ==
|
||||
"Velocity_x");
|
||||
ASSERT(visData[0].vars[1 + Ion.number_ion_species + 1]->name ==
|
||||
"Velocity_y");
|
||||
ASSERT(visData[0].vars[1 + Ion.number_ion_species + 2]->name ==
|
||||
"Velocity_z");
|
||||
Stokes.getVelocity(Vel_x, Vel_y, Vel_z);
|
||||
Array<double> &VelxData =
|
||||
visData[0].vars[1 + Ion.number_ion_species + 0]->data;
|
||||
Array<double> &VelyData =
|
||||
visData[0].vars[1 + Ion.number_ion_species + 1]->data;
|
||||
Array<double> &VelzData =
|
||||
visData[0].vars[1 + Ion.number_ion_species + 2]->data;
|
||||
fillData.copy(Vel_x, VelxData);
|
||||
fillData.copy(Vel_y, VelyData);
|
||||
fillData.copy(Vel_z, VelzData);
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>("save_ion_flux_diffusive", false)) {
|
||||
for (size_t ion = 0; ion < Ion.number_ion_species; ion++) {
|
||||
|
||||
// x-component of diffusive flux
|
||||
sprintf(VisName, "Ion%zu_FluxDiffusive_x", ion + 1);
|
||||
//IonFluxDiffusive[3*ion+0]->name = VisName;
|
||||
ASSERT(visData[0]
|
||||
.vars[4 + Ion.number_ion_species + 3 * ion + 0]
|
||||
->name == VisName);
|
||||
// y-component of diffusive flux
|
||||
sprintf(VisName, "Ion%zu_FluxDiffusive_y", ion + 1);
|
||||
//IonFluxDiffusive[3*ion+1]->name = VisName;
|
||||
ASSERT(visData[0]
|
||||
.vars[4 + Ion.number_ion_species + 3 * ion + 1]
|
||||
->name == VisName);
|
||||
// z-component of diffusive flux
|
||||
sprintf(VisName, "Ion%zu_FluxDiffusive_z", ion + 1);
|
||||
//IonFluxDiffusive[3*ion+2]->name = VisName;
|
||||
ASSERT(visData[0]
|
||||
.vars[4 + Ion.number_ion_species + 3 * ion + 2]
|
||||
->name == VisName);
|
||||
|
||||
Array<double> &IonFluxData_x =
|
||||
visData[0].vars[4 + Ion.number_ion_species + 3 * ion + 0]->data;
|
||||
Array<double> &IonFluxData_y =
|
||||
visData[0].vars[4 + Ion.number_ion_species + 3 * ion + 1]->data;
|
||||
Array<double> &IonFluxData_z =
|
||||
visData[0].vars[4 + Ion.number_ion_species + 3 * ion + 2]->data;
|
||||
Ion.getIonFluxDiffusive(IonFluxDiffusive_x, IonFluxDiffusive_y,
|
||||
IonFluxDiffusive_z, ion);
|
||||
fillData.copy(IonFluxDiffusive_x, IonFluxData_x);
|
||||
fillData.copy(IonFluxDiffusive_y, IonFluxData_y);
|
||||
fillData.copy(IonFluxDiffusive_z, IonFluxData_z);
|
||||
}
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>("save_ion_flux_advective", false)) {
|
||||
for (size_t ion = 0; ion < Ion.number_ion_species; ion++) {
|
||||
|
||||
// x-component of diffusive flux
|
||||
sprintf(VisName, "Ion%zu_FluxAdvective_x", ion + 1);
|
||||
//IonFluxDiffusive[3*ion+0]->name = VisName;
|
||||
ASSERT(visData[0]
|
||||
.vars[4 + Ion.number_ion_species * (1 + 3) + 3 * ion + 0]
|
||||
->name == VisName);
|
||||
// y-component of diffusive flux
|
||||
sprintf(VisName, "Ion%zu_FluxAdvective_y", ion + 1);
|
||||
//IonFluxDiffusive[3*ion+1]->name = VisName;
|
||||
ASSERT(visData[0]
|
||||
.vars[4 + Ion.number_ion_species * (1 + 3) + 3 * ion + 1]
|
||||
->name == VisName);
|
||||
// z-component of diffusive flux
|
||||
sprintf(VisName, "Ion%zu_FluxAdvective_z", ion + 1);
|
||||
//IonFluxDiffusive[3*ion+2]->name = VisName;
|
||||
ASSERT(visData[0]
|
||||
.vars[4 + Ion.number_ion_species * (1 + 3) + 3 * ion + 2]
|
||||
->name == VisName);
|
||||
|
||||
Array<double> &IonFluxData_x =
|
||||
visData[0]
|
||||
.vars[4 + Ion.number_ion_species * (1 + 3) + 3 * ion + 0]
|
||||
->data;
|
||||
Array<double> &IonFluxData_y =
|
||||
visData[0]
|
||||
.vars[4 + Ion.number_ion_species * (1 + 3) + 3 * ion + 1]
|
||||
->data;
|
||||
Array<double> &IonFluxData_z =
|
||||
visData[0]
|
||||
.vars[4 + Ion.number_ion_species * (1 + 3) + 3 * ion + 2]
|
||||
->data;
|
||||
Ion.getIonFluxAdvective(IonFluxAdvective_x, IonFluxAdvective_y,
|
||||
IonFluxAdvective_z, ion);
|
||||
fillData.copy(IonFluxAdvective_x, IonFluxData_x);
|
||||
fillData.copy(IonFluxAdvective_y, IonFluxData_y);
|
||||
fillData.copy(IonFluxAdvective_z, IonFluxData_z);
|
||||
}
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>("save_ion_flux_electrical", false)) {
|
||||
for (size_t ion = 0; ion < Ion.number_ion_species; ion++) {
|
||||
|
||||
// x-component of diffusive flux
|
||||
sprintf(VisName, "Ion%zu_FluxElectrical_x", ion + 1);
|
||||
//IonFluxDiffusive[3*ion+0]->name = VisName;
|
||||
ASSERT(visData[0]
|
||||
.vars[4 + Ion.number_ion_species * (1 + 6) + 3 * ion + 0]
|
||||
->name == VisName);
|
||||
// y-component of diffusive flux
|
||||
sprintf(VisName, "Ion%zu_FluxElectrical_y", ion + 1);
|
||||
//IonFluxDiffusive[3*ion+1]->name = VisName;
|
||||
ASSERT(visData[0]
|
||||
.vars[4 + Ion.number_ion_species * (1 + 6) + 3 * ion + 1]
|
||||
->name == VisName);
|
||||
// z-component of diffusive flux
|
||||
sprintf(VisName, "Ion%zu_FluxElectrical_z", ion + 1);
|
||||
//IonFluxDiffusive[3*ion+2]->name = VisName;
|
||||
ASSERT(visData[0]
|
||||
.vars[4 + Ion.number_ion_species * (1 + 6) + 3 * ion + 2]
|
||||
->name == VisName);
|
||||
|
||||
Array<double> &IonFluxData_x =
|
||||
visData[0]
|
||||
.vars[4 + Ion.number_ion_species * (1 + 6) + 3 * ion + 0]
|
||||
->data;
|
||||
Array<double> &IonFluxData_y =
|
||||
visData[0]
|
||||
.vars[4 + Ion.number_ion_species * (1 + 6) + 3 * ion + 1]
|
||||
->data;
|
||||
Array<double> &IonFluxData_z =
|
||||
visData[0]
|
||||
.vars[4 + Ion.number_ion_species * (1 + 6) + 3 * ion + 2]
|
||||
->data;
|
||||
Ion.getIonFluxElectrical(IonFluxElectrical_x, IonFluxElectrical_y,
|
||||
IonFluxElectrical_z, ion);
|
||||
fillData.copy(IonFluxElectrical_x, IonFluxData_x);
|
||||
fillData.copy(IonFluxElectrical_y, IonFluxData_y);
|
||||
fillData.copy(IonFluxElectrical_z, IonFluxData_z);
|
||||
}
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>("save_electric_field", false)) {
|
||||
ASSERT(
|
||||
visData[0].vars[4 + Ion.number_ion_species * (1 + 9) + 0]->name ==
|
||||
"ElectricField_x");
|
||||
ASSERT(
|
||||
visData[0].vars[4 + Ion.number_ion_species * (1 + 9) + 1]->name ==
|
||||
"ElectricField_y");
|
||||
ASSERT(
|
||||
visData[0].vars[4 + Ion.number_ion_species * (1 + 9) + 2]->name ==
|
||||
"ElectricField_z");
|
||||
Poisson.getElectricField(ElectricalField_x, ElectricalField_y,
|
||||
ElectricalField_z);
|
||||
Array<double> &ElectricalFieldxData =
|
||||
visData[0].vars[4 + Ion.number_ion_species * (1 + 9) + 0]->data;
|
||||
Array<double> &ElectricalFieldyData =
|
||||
visData[0].vars[4 + Ion.number_ion_species * (1 + 9) + 1]->data;
|
||||
Array<double> &ElectricalFieldzData =
|
||||
visData[0].vars[4 + Ion.number_ion_species * (1 + 9) + 2]->data;
|
||||
fillData.copy(ElectricalField_x, ElectricalFieldxData);
|
||||
fillData.copy(ElectricalField_y, ElectricalFieldyData);
|
||||
fillData.copy(ElectricalField_z, ElectricalFieldzData);
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>("write_silo", true))
|
||||
IO::writeData(timestep, visData, Dm->Comm);
|
||||
//--------------------------------------------------------------------------------------------------------------------
|
||||
/* if (vis_db->getWithDefault<bool>( "save_8bit_raw", true )){
|
||||
char CurrentIDFilename[40];
|
||||
sprintf(CurrentIDFilename,"id_t%d.raw",timestep);
|
||||
Averages.AggregateLabels(CurrentIDFilename);
|
||||
}
|
||||
*/
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -20,36 +20,50 @@
|
|||
#include "models/PoissonSolver.h"
|
||||
#include "models/StokesModel.h"
|
||||
|
||||
class ElectroChemistryAnalyzer{
|
||||
class ElectroChemistryAnalyzer {
|
||||
public:
|
||||
std::shared_ptr <Domain> Dm;
|
||||
double Volume;
|
||||
// input variables
|
||||
double rho_n, rho_w;
|
||||
double nu_n, nu_w;
|
||||
double gamma_wn, beta;
|
||||
double Fx, Fy, Fz;
|
||||
std::shared_ptr<Domain> Dm;
|
||||
double Volume;
|
||||
// input variables
|
||||
double rho_n, rho_w;
|
||||
double nu_n, nu_w;
|
||||
double gamma_wn, beta;
|
||||
double Fx, Fy, Fz;
|
||||
|
||||
//...........................................................................
|
||||
int Nx,Ny,Nz;
|
||||
DoubleArray Rho; // density field
|
||||
DoubleArray ChemicalPotential; // density field
|
||||
DoubleArray ElectricalPotential; // density field
|
||||
DoubleArray Pressure; // pressure field
|
||||
DoubleArray Vel_x; // velocity field
|
||||
DoubleArray Vel_y;
|
||||
DoubleArray Vel_z;
|
||||
DoubleArray SDs;
|
||||
int Nx, Ny, Nz;
|
||||
DoubleArray Rho; // density field
|
||||
DoubleArray ChemicalPotential; // density field
|
||||
DoubleArray ElectricalPotential; // density field
|
||||
DoubleArray ElectricalField_x; // density field
|
||||
DoubleArray ElectricalField_y; // density field
|
||||
DoubleArray ElectricalField_z; // density field
|
||||
DoubleArray Pressure; // pressure field
|
||||
DoubleArray Vel_x; // velocity field
|
||||
DoubleArray Vel_y;
|
||||
DoubleArray Vel_z;
|
||||
DoubleArray SDs;
|
||||
DoubleArray IonFluxDiffusive_x; //ion diffusive flux components
|
||||
DoubleArray IonFluxDiffusive_y;
|
||||
DoubleArray IonFluxDiffusive_z;
|
||||
DoubleArray IonFluxAdvective_x; //ion advective flux components
|
||||
DoubleArray IonFluxAdvective_y;
|
||||
DoubleArray IonFluxAdvective_z;
|
||||
DoubleArray IonFluxElectrical_x; //ion electromigration flux components
|
||||
DoubleArray IonFluxElectrical_y;
|
||||
DoubleArray IonFluxElectrical_z;
|
||||
|
||||
ElectroChemistryAnalyzer(std::shared_ptr <Domain> Dm);
|
||||
~ElectroChemistryAnalyzer();
|
||||
|
||||
void SetParams();
|
||||
void Basic( ScaLBL_IonModel &Ion, ScaLBL_Poisson &Poisson, ScaLBL_StokesModel &Stokes, int timestep);
|
||||
void WriteVis( ScaLBL_IonModel &Ion, ScaLBL_Poisson &Poisson, ScaLBL_StokesModel &Stokes, std::shared_ptr<Database> input_db, int timestep);
|
||||
ElectroChemistryAnalyzer(std::shared_ptr<Domain> Dm);
|
||||
~ElectroChemistryAnalyzer();
|
||||
|
||||
void SetParams();
|
||||
void Basic(ScaLBL_IonModel &Ion, ScaLBL_Poisson &Poisson,
|
||||
ScaLBL_StokesModel &Stokes, int timestep);
|
||||
void WriteVis(ScaLBL_IonModel &Ion, ScaLBL_Poisson &Poisson,
|
||||
ScaLBL_StokesModel &Stokes,
|
||||
std::shared_ptr<Database> input_db, int timestep);
|
||||
|
||||
private:
|
||||
FILE *TIMELOG;
|
||||
FILE *TIMELOG;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
601
analysis/FlowAdaptor.cpp
Normal file
601
analysis/FlowAdaptor.cpp
Normal file
|
@ -0,0 +1,601 @@
|
|||
/* Flow adaptor class for multiphase flow methods */
|
||||
|
||||
#include "analysis/FlowAdaptor.h"
|
||||
#include "analysis/distance.h"
|
||||
#include "analysis/morphology.h"
|
||||
|
||||
FlowAdaptor::FlowAdaptor(ScaLBL_ColorModel &M) {
|
||||
Nx = M.Dm->Nx;
|
||||
Ny = M.Dm->Ny;
|
||||
Nz = M.Dm->Nz;
|
||||
timestep = -1;
|
||||
timestep_previous = -1;
|
||||
|
||||
phi.resize(Nx, Ny, Nz);
|
||||
phi.fill(0); // phase indicator field
|
||||
phi_t.resize(Nx, Ny, Nz);
|
||||
phi_t.fill(0); // time derivative for the phase indicator field
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
delete PhaseLabel;
|
||||
double saturation = Count / PoreCount;
|
||||
return saturation;
|
||||
}
|
||||
|
||||
double FlowAdaptor::UpdateFractionalFlow(ScaLBL_ColorModel &M) {
|
||||
|
||||
double MASS_FRACTION_CHANGE = 0.006;
|
||||
double FRACTIONAL_FLOW_EPSILON = 5e-6;
|
||||
if (M.db->keyExists("FlowAdaptor")) {
|
||||
auto flow_db = M.db->getDatabase("FlowAdaptor");
|
||||
MASS_FRACTION_CHANGE =
|
||||
flow_db->getWithDefault<double>("mass_fraction_factor", 0.006);
|
||||
FRACTIONAL_FLOW_EPSILON =
|
||||
flow_db->getWithDefault<double>("fractional_flow_epsilon", 5e-6);
|
||||
}
|
||||
int Np = M.Np;
|
||||
double dA, dB, phi;
|
||||
double vx, vy, vz;
|
||||
double mass_a, mass_b, mass_a_global, mass_b_global;
|
||||
|
||||
double *Aq_tmp, *Bq_tmp;
|
||||
double *Vel_x, *Vel_y, *Vel_z, *Phase;
|
||||
|
||||
Aq_tmp = new double[7 * Np];
|
||||
Bq_tmp = new double[7 * Np];
|
||||
Phase = new double[Np];
|
||||
Vel_x = new double[Np];
|
||||
Vel_y = new double[Np];
|
||||
Vel_z = new double[Np];
|
||||
|
||||
ScaLBL_CopyToHost(Aq_tmp, M.Aq, 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_y, &M.Velocity[Np], Np * sizeof(double));
|
||||
ScaLBL_CopyToHost(Vel_z, &M.Velocity[2 * Np], Np * sizeof(double));
|
||||
|
||||
int Nx = M.Nx;
|
||||
int Ny = M.Ny;
|
||||
int Nz = M.Nz;
|
||||
|
||||
mass_a = mass_b = 0.0;
|
||||
double maxSpeed = 0.0;
|
||||
double localMaxSpeed = 0.0;
|
||||
/* compute mass change based on weights */
|
||||
double sum_weights_A = 0.0;
|
||||
double sum_weights_B = 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;
|
||||
vx = Vel_x[n];
|
||||
vy = Vel_y[n];
|
||||
vz = Vel_z[n];
|
||||
double local_momentum = sqrt(vx * vx + vy * vy + vz * vz);
|
||||
double local_weight =
|
||||
(FRACTIONAL_FLOW_EPSILON + local_momentum);
|
||||
if (phi > 0.0) {
|
||||
sum_weights_A += local_weight * dA;
|
||||
} else {
|
||||
sum_weights_B += local_weight * dB;
|
||||
}
|
||||
if (local_momentum > localMaxSpeed) {
|
||||
localMaxSpeed = local_momentum;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
maxSpeed = M.Dm->Comm.maxReduce(localMaxSpeed);
|
||||
mass_a_global = M.Dm->Comm.sumReduce(mass_a);
|
||||
mass_b_global = M.Dm->Comm.sumReduce(mass_b);
|
||||
double sum_weights_A_global = M.Dm->Comm.sumReduce(sum_weights_A);
|
||||
double sum_weights_B_global = M.Dm->Comm.sumReduce(sum_weights_B);
|
||||
sum_weights_A_global /= (FRACTIONAL_FLOW_EPSILON + maxSpeed);
|
||||
sum_weights_B_global /= (FRACTIONAL_FLOW_EPSILON + maxSpeed);
|
||||
|
||||
//double total_momentum_A = sqrt(vax_global*vax_global+vay_global*vay_global+vaz_global*vaz_global);
|
||||
//double total_momentum_B = sqrt(vbx_global*vbx_global+vby_global*vby_global+vbz_global*vbz_global);
|
||||
/* compute the total mass change */
|
||||
double TOTAL_MASS_CHANGE =
|
||||
MASS_FRACTION_CHANGE * (mass_a_global + mass_b_global);
|
||||
if (fabs(TOTAL_MASS_CHANGE) > 0.1 * mass_a_global)
|
||||
TOTAL_MASS_CHANGE = 0.1 * mass_a_global;
|
||||
if (fabs(TOTAL_MASS_CHANGE) > 0.1 * mass_b_global)
|
||||
TOTAL_MASS_CHANGE = 0.1 * mass_b_global;
|
||||
|
||||
double MASS_FACTOR_A = TOTAL_MASS_CHANGE / sum_weights_A_global;
|
||||
double MASS_FACTOR_B = TOTAL_MASS_CHANGE / sum_weights_B_global;
|
||||
|
||||
double LOCAL_MASS_CHANGE = 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);
|
||||
if (!(n < 0)) {
|
||||
phi = Phase[n];
|
||||
vx = Vel_x[n];
|
||||
vy = Vel_y[n];
|
||||
vz = Vel_z[n];
|
||||
double local_momentum = sqrt(vx * vx + vy * vy + vz * vz);
|
||||
double local_weight =
|
||||
(FRACTIONAL_FLOW_EPSILON + local_momentum) /
|
||||
(FRACTIONAL_FLOW_EPSILON + maxSpeed);
|
||||
/* impose ceiling for spurious currents */
|
||||
//if (local_momentum > maxSpeed) local_momentum = maxSpeed;
|
||||
if (phi > 0.0) {
|
||||
LOCAL_MASS_CHANGE = MASS_FACTOR_A * local_weight;
|
||||
Aq_tmp[n] -= 0.3333333333333333 * LOCAL_MASS_CHANGE;
|
||||
Aq_tmp[n + Np] -=
|
||||
0.1111111111111111 * LOCAL_MASS_CHANGE;
|
||||
Aq_tmp[n + 2 * Np] -=
|
||||
0.1111111111111111 * LOCAL_MASS_CHANGE;
|
||||
Aq_tmp[n + 3 * Np] -=
|
||||
0.1111111111111111 * LOCAL_MASS_CHANGE;
|
||||
Aq_tmp[n + 4 * Np] -=
|
||||
0.1111111111111111 * LOCAL_MASS_CHANGE;
|
||||
Aq_tmp[n + 5 * Np] -=
|
||||
0.1111111111111111 * LOCAL_MASS_CHANGE;
|
||||
Aq_tmp[n + 6 * Np] -=
|
||||
0.1111111111111111 * LOCAL_MASS_CHANGE;
|
||||
//DebugMassA[n] = (-1.0)*LOCAL_MASS_CHANGE;
|
||||
} else {
|
||||
LOCAL_MASS_CHANGE = MASS_FACTOR_B * local_weight;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (M.rank == 0)
|
||||
printf("Update Fractional Flow: change mass of fluid B by %f \n",
|
||||
TOTAL_MASS_CHANGE / mass_b_global);
|
||||
|
||||
// Need to initialize Aq, Bq, Den, Phi directly
|
||||
//ScaLBL_CopyToDevice(Phi,phase.data(),7*Np*sizeof(double));
|
||||
ScaLBL_CopyToDevice(M.Aq, Aq_tmp, 7 * Np * sizeof(double));
|
||||
ScaLBL_CopyToDevice(M.Bq, Bq_tmp, 7 * Np * sizeof(double));
|
||||
|
||||
delete Aq_tmp;
|
||||
delete Bq_tmp;
|
||||
delete Vel_x;
|
||||
delete Vel_y;
|
||||
delete Vel_z;
|
||||
delete Phase;
|
||||
|
||||
return (TOTAL_MASS_CHANGE);
|
||||
}
|
||||
|
||||
void FlowAdaptor::Flatten(ScaLBL_ColorModel &M) {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
double FlowAdaptor::MoveInterface(ScaLBL_ColorModel &M) {
|
||||
|
||||
double INTERFACE_CUTOFF =
|
||||
M.color_db->getWithDefault<double>("move_interface_cutoff", 0.1);
|
||||
double MOVE_INTERFACE_FACTOR =
|
||||
M.color_db->getWithDefault<double>("move_interface_factor", 10.0);
|
||||
|
||||
ScaLBL_CopyToHost(phi.data(), M.Phi, Nx * Ny * Nz * sizeof(double));
|
||||
/* compute the local derivative of phase indicator field */
|
||||
double beta = M.beta;
|
||||
double factor = 0.5 / beta;
|
||||
double total_interface_displacement = 0.0;
|
||||
double total_interface_sites = 0.0;
|
||||
for (int n = 0; n < Nx * Ny * Nz; n++) {
|
||||
/* compute the distance to the interface */
|
||||
double value1 = M.Averages->Phi(n);
|
||||
double dist1 = factor * log((1.0 + value1) / (1.0 - value1));
|
||||
double value2 = phi(n);
|
||||
double dist2 = factor * log((1.0 + value2) / (1.0 - value2));
|
||||
phi_t(n) = value2;
|
||||
if (value1 < INTERFACE_CUTOFF && value1 > -1 * INTERFACE_CUTOFF &&
|
||||
value2 < INTERFACE_CUTOFF && value2 > -1 * INTERFACE_CUTOFF) {
|
||||
/* time derivative of distance */
|
||||
double dxdt = 0.125 * (dist2 - dist1);
|
||||
/* extrapolate to move the distance further */
|
||||
double dist3 = dist2 + MOVE_INTERFACE_FACTOR * dxdt;
|
||||
/* compute the new phase interface */
|
||||
phi_t(n) = (2.f * (exp(-2.f * beta * (dist3))) /
|
||||
(1.f + exp(-2.f * beta * (dist3))) -
|
||||
1.f);
|
||||
total_interface_displacement += fabs(MOVE_INTERFACE_FACTOR * dxdt);
|
||||
total_interface_sites += 1.0;
|
||||
}
|
||||
}
|
||||
ScaLBL_CopyToDevice(M.Phi, phi_t.data(), Nx * Ny * Nz * sizeof(double));
|
||||
return total_interface_sites;
|
||||
}
|
||||
|
||||
double FlowAdaptor::ShellAggregation(ScaLBL_ColorModel &M,
|
||||
const double target_delta_volume) {
|
||||
|
||||
const RankInfoStruct rank_info(M.rank, M.nprocx, M.nprocy, M.nprocz);
|
||||
auto rank = M.rank;
|
||||
auto Nx = M.Nx;
|
||||
auto Ny = M.Ny;
|
||||
auto Nz = M.Nz;
|
||||
auto N = Nx * Ny * Nz;
|
||||
double vF = 0.f;
|
||||
double vS = 0.f;
|
||||
double delta_volume;
|
||||
double WallFactor = 1.0;
|
||||
bool USE_CONNECTED_NWP = false;
|
||||
|
||||
DoubleArray phase(Nx, Ny, Nz);
|
||||
IntArray phase_label(Nx, Ny, Nz);
|
||||
;
|
||||
DoubleArray phase_distance(Nx, Ny, Nz);
|
||||
Array<char> phase_id(Nx, Ny, Nz);
|
||||
fillHalo<double> fillDouble(M.Dm->Comm, M.Dm->rank_info,
|
||||
{Nx - 2, Ny - 2, Nz - 2}, {1, 1, 1}, 0, 1);
|
||||
|
||||
// Basic algorithm to
|
||||
// 1. Copy phase field to CPU
|
||||
ScaLBL_CopyToHost(phase.data(), M.Phi, N * sizeof(double));
|
||||
|
||||
double count = 0.f;
|
||||
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 (phase(i, j, k) > 0.f && M.Averages->SDs(i, j, k) > 0.f)
|
||||
count += 1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
double volume_initial = M.Dm->Comm.sumReduce(count);
|
||||
double PoreVolume = M.Dm->Volume * M.Dm->Porosity();
|
||||
/*ensure target isn't an absurdly small fraction of pore volume */
|
||||
if (volume_initial < target_delta_volume * PoreVolume) {
|
||||
volume_initial = target_delta_volume * PoreVolume;
|
||||
}
|
||||
|
||||
// 2. Identify connected components of phase field -> phase_label
|
||||
|
||||
double volume_connected = 0.0;
|
||||
double second_biggest = 0.0;
|
||||
if (USE_CONNECTED_NWP) {
|
||||
ComputeGlobalBlobIDs(Nx - 2, Ny - 2, Nz - 2, rank_info, phase,
|
||||
M.Averages->SDs, vF, vS, phase_label, M.Dm->Comm);
|
||||
M.Dm->Comm.barrier();
|
||||
|
||||
// only operate on component "0"ScaLBL_ColorModel &M,
|
||||
count = 0.0;
|
||||
|
||||
for (int k = 0; k < Nz; k++) {
|
||||
for (int j = 0; j < Ny; j++) {
|
||||
for (int i = 0; i < Nx; i++) {
|
||||
int label = phase_label(i, j, k);
|
||||
if (label == 0) {
|
||||
phase_id(i, j, k) = 0;
|
||||
count += 1.0;
|
||||
} else
|
||||
phase_id(i, j, k) = 1;
|
||||
if (label == 1) {
|
||||
second_biggest += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
volume_connected = M.Dm->Comm.sumReduce(count);
|
||||
second_biggest = M.Dm->Comm.sumReduce(second_biggest);
|
||||
} else {
|
||||
// use the whole NWP
|
||||
for (int k = 0; k < Nz; k++) {
|
||||
for (int j = 0; j < Ny; j++) {
|
||||
for (int i = 0; i < Nx; i++) {
|
||||
if (M.Averages->SDs(i, j, k) > 0.f) {
|
||||
if (phase(i, j, k) > 0.f) {
|
||||
phase_id(i, j, k) = 0;
|
||||
} else {
|
||||
phase_id(i, j, k) = 1;
|
||||
}
|
||||
} else {
|
||||
phase_id(i, j, k) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Generate a distance map to the largest object -> phase_distance
|
||||
CalcDist(phase_distance, phase_id, *M.Dm);
|
||||
|
||||
double temp, value;
|
||||
double factor = 0.5 / M.beta;
|
||||
for (int k = 0; k < Nz; k++) {
|
||||
for (int j = 0; j < Ny; j++) {
|
||||
for (int i = 0; i < Nx; i++) {
|
||||
if (phase_distance(i, j, k) < 3.f) {
|
||||
value = phase(i, j, k);
|
||||
if (value > 1.f)
|
||||
value = 1.f;
|
||||
if (value < -1.f)
|
||||
value = -1.f;
|
||||
// temp -- distance based on analytical form McClure, Prins et al, Comp. Phys. Comm.
|
||||
temp = -factor * log((1.0 + value) / (1.0 - value));
|
||||
/// use this approximation close to the object
|
||||
if (fabs(value) < 0.8 && M.Averages->SDs(i, j, k) > 1.f) {
|
||||
phase_distance(i, j, k) = temp;
|
||||
}
|
||||
// erase the original object
|
||||
phase(i, j, k) = -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rank == 0)
|
||||
printf("Pathway volume / next largest ganglion %f \n",
|
||||
volume_connected / second_biggest);
|
||||
|
||||
if (rank == 0)
|
||||
printf("MorphGrow with target volume fraction change %f \n",
|
||||
target_delta_volume / volume_initial);
|
||||
double target_delta_volume_incremental = target_delta_volume;
|
||||
if (fabs(target_delta_volume) > 0.01 * volume_initial)
|
||||
target_delta_volume_incremental = 0.01 * volume_initial *
|
||||
target_delta_volume /
|
||||
fabs(target_delta_volume);
|
||||
|
||||
delta_volume =
|
||||
MorphGrow(M.Averages->SDs, phase_distance, phase_id, M.Averages->Dm,
|
||||
target_delta_volume_incremental, WallFactor);
|
||||
|
||||
for (int k = 0; k < Nz; k++) {
|
||||
for (int j = 0; j < Ny; j++) {
|
||||
for (int i = 0; i < Nx; i++) {
|
||||
if (phase_distance(i, j, k) < 0.0)
|
||||
phase_id(i, j, k) = 0;
|
||||
else
|
||||
phase_id(i, j, k) = 1;
|
||||
//if (phase_distance(i,j,k) < 0.0 ) phase(i,j,k) = 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CalcDist(phase_distance, phase_id, *M.Dm); // re-calculate distance
|
||||
|
||||
// 5. Update phase indicator field based on new distnace
|
||||
for (int k = 0; k < Nz; k++) {
|
||||
for (int j = 0; j < Ny; j++) {
|
||||
for (int i = 0; i < Nx; i++) {
|
||||
double d = phase_distance(i, j, k);
|
||||
if (M.Averages->SDs(i, j, k) > 0.f) {
|
||||
if (d < 3.f) {
|
||||
//phase(i,j,k) = -1.0;
|
||||
phase(i, j, k) = (2.f * (exp(-2.f * M.beta * d)) /
|
||||
(1.f + exp(-2.f * M.beta * d)) -
|
||||
1.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fillDouble.fill(phase);
|
||||
|
||||
count = 0.f;
|
||||
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 (phase(i, j, k) > 0.f && M.Averages->SDs(i, j, k) > 0.f) {
|
||||
count += 1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
double volume_final = M.Dm->Comm.sumReduce(count);
|
||||
|
||||
delta_volume = (volume_final - volume_initial);
|
||||
if (rank == 0)
|
||||
printf("Shell Aggregation: change fluid volume fraction by %f \n",
|
||||
delta_volume / volume_initial);
|
||||
if (rank == 0)
|
||||
printf(" new saturation = %f \n",
|
||||
volume_final /
|
||||
(M.Mask->Porosity() *
|
||||
double((Nx - 2) * (Ny - 2) * (Nz - 2) * M.nprocs)));
|
||||
|
||||
// 6. copy back to the device
|
||||
//if (rank==0) printf("MorphInit: copy data back to device\n");
|
||||
ScaLBL_CopyToDevice(M.Phi, phase.data(), N * sizeof(double));
|
||||
|
||||
// 7. Re-initialize phase field and density
|
||||
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);
|
||||
auto BoundaryCondition = M.BoundaryCondition;
|
||||
if (BoundaryCondition == 1 || BoundaryCondition == 2 ||
|
||||
BoundaryCondition == 3 || BoundaryCondition == 4) {
|
||||
if (M.Dm->kproc() == 0) {
|
||||
ScaLBL_SetSlice_z(M.Phi, 1.0, Nx, Ny, Nz, 0);
|
||||
ScaLBL_SetSlice_z(M.Phi, 1.0, Nx, Ny, Nz, 1);
|
||||
ScaLBL_SetSlice_z(M.Phi, 1.0, Nx, Ny, Nz, 2);
|
||||
}
|
||||
if (M.Dm->kproc() == M.nprocz - 1) {
|
||||
ScaLBL_SetSlice_z(M.Phi, -1.0, Nx, Ny, Nz, Nz - 1);
|
||||
ScaLBL_SetSlice_z(M.Phi, -1.0, Nx, Ny, Nz, Nz - 2);
|
||||
ScaLBL_SetSlice_z(M.Phi, -1.0, Nx, Ny, Nz, Nz - 3);
|
||||
}
|
||||
}
|
||||
return delta_volume;
|
||||
}
|
||||
|
||||
double FlowAdaptor::SeedPhaseField(ScaLBL_ColorModel &M,
|
||||
const double seed_water_in_oil) {
|
||||
srand(time(NULL));
|
||||
auto rank = M.rank;
|
||||
auto Np = M.Np;
|
||||
double mass_loss = 0.f;
|
||||
double count = 0.f;
|
||||
double *Aq_tmp, *Bq_tmp;
|
||||
|
||||
Aq_tmp = new double[7 * Np];
|
||||
Bq_tmp = new double[7 * Np];
|
||||
|
||||
ScaLBL_CopyToHost(Aq_tmp, M.Aq, 7 * Np * sizeof(double));
|
||||
ScaLBL_CopyToHost(Bq_tmp, M.Bq, 7 * Np * sizeof(double));
|
||||
|
||||
for (int n = 0; n < M.ScaLBL_Comm->LastExterior(); n++) {
|
||||
double random_value = seed_water_in_oil * double(rand()) / RAND_MAX;
|
||||
double 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];
|
||||
double 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];
|
||||
double phase_id = (dA - dB) / (dA + dB);
|
||||
if (phase_id > 0.0) {
|
||||
Aq_tmp[n] -= 0.3333333333333333 * random_value;
|
||||
Aq_tmp[n + Np] -= 0.1111111111111111 * random_value;
|
||||
Aq_tmp[n + 2 * Np] -= 0.1111111111111111 * random_value;
|
||||
Aq_tmp[n + 3 * Np] -= 0.1111111111111111 * random_value;
|
||||
Aq_tmp[n + 4 * Np] -= 0.1111111111111111 * random_value;
|
||||
Aq_tmp[n + 5 * Np] -= 0.1111111111111111 * random_value;
|
||||
Aq_tmp[n + 6 * Np] -= 0.1111111111111111 * random_value;
|
||||
|
||||
Bq_tmp[n] += 0.3333333333333333 * random_value;
|
||||
Bq_tmp[n + Np] += 0.1111111111111111 * random_value;
|
||||
Bq_tmp[n + 2 * Np] += 0.1111111111111111 * random_value;
|
||||
Bq_tmp[n + 3 * Np] += 0.1111111111111111 * random_value;
|
||||
Bq_tmp[n + 4 * Np] += 0.1111111111111111 * random_value;
|
||||
Bq_tmp[n + 5 * Np] += 0.1111111111111111 * random_value;
|
||||
Bq_tmp[n + 6 * Np] += 0.1111111111111111 * random_value;
|
||||
}
|
||||
mass_loss += random_value * seed_water_in_oil;
|
||||
}
|
||||
|
||||
for (int n = M.ScaLBL_Comm->FirstInterior();
|
||||
n < M.ScaLBL_Comm->LastInterior(); n++) {
|
||||
double random_value = seed_water_in_oil * double(rand()) / RAND_MAX;
|
||||
double 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];
|
||||
double 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];
|
||||
double phase_id = (dA - dB) / (dA + dB);
|
||||
if (phase_id > 0.0) {
|
||||
Aq_tmp[n] -= 0.3333333333333333 * random_value;
|
||||
Aq_tmp[n + Np] -= 0.1111111111111111 * random_value;
|
||||
Aq_tmp[n + 2 * Np] -= 0.1111111111111111 * random_value;
|
||||
Aq_tmp[n + 3 * Np] -= 0.1111111111111111 * random_value;
|
||||
Aq_tmp[n + 4 * Np] -= 0.1111111111111111 * random_value;
|
||||
Aq_tmp[n + 5 * Np] -= 0.1111111111111111 * random_value;
|
||||
Aq_tmp[n + 6 * Np] -= 0.1111111111111111 * random_value;
|
||||
|
||||
Bq_tmp[n] += 0.3333333333333333 * random_value;
|
||||
Bq_tmp[n + Np] += 0.1111111111111111 * random_value;
|
||||
Bq_tmp[n + 2 * Np] += 0.1111111111111111 * random_value;
|
||||
Bq_tmp[n + 3 * Np] += 0.1111111111111111 * random_value;
|
||||
Bq_tmp[n + 4 * Np] += 0.1111111111111111 * random_value;
|
||||
Bq_tmp[n + 5 * Np] += 0.1111111111111111 * random_value;
|
||||
Bq_tmp[n + 6 * Np] += 0.1111111111111111 * random_value;
|
||||
}
|
||||
mass_loss += random_value * seed_water_in_oil;
|
||||
}
|
||||
|
||||
count = M.Dm->Comm.sumReduce(count);
|
||||
mass_loss = M.Dm->Comm.sumReduce(mass_loss);
|
||||
if (rank == 0)
|
||||
printf("Remove mass %f from %f voxels \n", mass_loss, count);
|
||||
|
||||
// Need to initialize Aq, Bq, Den, Phi directly
|
||||
//ScaLBL_CopyToDevice(Phi,phase.data(),7*Np*sizeof(double));
|
||||
ScaLBL_CopyToDevice(M.Aq, Aq_tmp, 7 * Np * sizeof(double));
|
||||
ScaLBL_CopyToDevice(M.Bq, Bq_tmp, 7 * Np * sizeof(double));
|
||||
|
||||
delete Aq_tmp;
|
||||
delete Bq_tmp;
|
||||
return (mass_loss);
|
||||
}
|
89
analysis/FlowAdaptor.h
Normal file
89
analysis/FlowAdaptor.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/* Flow adaptor class for multiphase flow methods */
|
||||
|
||||
#ifndef ScaLBL_FlowAdaptor_INC
|
||||
#define ScaLBL_FlowAdaptor_INC
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <fstream>
|
||||
|
||||
#include "models/ColorModel.h"
|
||||
|
||||
/**
|
||||
* \class FlowAdaptor
|
||||
* @brief
|
||||
* The FlowAdaptor class operates on a lattice Boltzmann model to alter the flow conditions
|
||||
*
|
||||
*/
|
||||
|
||||
class FlowAdaptor {
|
||||
public:
|
||||
/**
|
||||
* \brief Create a flow adaptor to operate on the LB model
|
||||
* @param M ScaLBL_ColorModel
|
||||
*/
|
||||
FlowAdaptor(ScaLBL_ColorModel &M);
|
||||
|
||||
/**
|
||||
* \brief Destructor
|
||||
*/
|
||||
~FlowAdaptor();
|
||||
|
||||
/**
|
||||
* \brief Fast-forward interface motion
|
||||
* \details Accelerate the movement of interfaces based on the time derivative
|
||||
* Optional keys to control behavior can be specified in the input database:
|
||||
* move_interface_cutoff -- identifies the diffuse interface region
|
||||
* move_interface_factor -- determines how much to ``fast forward"
|
||||
* @param M ScaLBL_ColorModel
|
||||
*/
|
||||
double MoveInterface(ScaLBL_ColorModel &M);
|
||||
|
||||
/**
|
||||
* \brief Image re-initialization
|
||||
* \details Re-initialize LB simulation from image data
|
||||
* @param M ScaLBL_ColorModel
|
||||
* @param Filename name of input file to be used to read image
|
||||
*/
|
||||
double ImageInit(ScaLBL_ColorModel &M, std::string Filename);
|
||||
|
||||
/**
|
||||
* \details Update volume fraction based on morphological algorithm. Dilation / erosion algorithm will be applied to
|
||||
* grow / shrink the phase regions
|
||||
* @param M ScaLBL_ColorModel
|
||||
* @param delta_volume target change in volume fraction
|
||||
*/
|
||||
double ShellAggregation(ScaLBL_ColorModel &M, const double delta_volume);
|
||||
|
||||
/**
|
||||
* \details Update fractional flow condition. Mass will be preferentially added or removed from
|
||||
* phase regions based on where flow is occurring
|
||||
* @param M ScaLBL_ColorModel
|
||||
*/
|
||||
double UpdateFractionalFlow(ScaLBL_ColorModel &M);
|
||||
|
||||
/**
|
||||
* \brief image re-initialization
|
||||
* \details Re-initialize LB simulation from image data
|
||||
* @param M ScaLBL_ColorModel
|
||||
* @param seed_water_in_oil controls amount of mass to randomly seed into fluids
|
||||
*/
|
||||
double SeedPhaseField(ScaLBL_ColorModel &M, const double seed_water_in_oil);
|
||||
|
||||
/**
|
||||
* \brief Re-initialize LB simulation
|
||||
* @param M ScaLBL_ColorModel
|
||||
*/
|
||||
void Flatten(ScaLBL_ColorModel &M);
|
||||
DoubleArray phi;
|
||||
DoubleArray phi_t;
|
||||
|
||||
private:
|
||||
int Nx, Ny, Nz;
|
||||
int timestep;
|
||||
int timestep_previous;
|
||||
};
|
||||
#endif
|
|
@ -1,55 +1,60 @@
|
|||
#include "analysis/FreeEnergy.h"
|
||||
|
||||
FreeEnergyAnalyzer::FreeEnergyAnalyzer(std::shared_ptr <Domain> dm):
|
||||
Dm(dm)
|
||||
{
|
||||
|
||||
Nx=dm->Nx; Ny=dm->Ny; Nz=dm->Nz;
|
||||
Volume=(Nx-2)*(Ny-2)*(Nz-2)*Dm->nprocx()*Dm->nprocy()*Dm->nprocz()*1.0;
|
||||
|
||||
ChemicalPotential.resize(Nx,Ny,Nz); ChemicalPotential.fill(0);
|
||||
Phi.resize(Nx,Ny,Nz); Phi.fill(0);
|
||||
Pressure.resize(Nx,Ny,Nz); Pressure.fill(0);
|
||||
Rho.resize(Nx,Ny,Nz); Rho.fill(0);
|
||||
Vel_x.resize(Nx,Ny,Nz); Vel_x.fill(0); // Gradient of the phase indicator field
|
||||
Vel_y.resize(Nx,Ny,Nz); Vel_y.fill(0);
|
||||
Vel_z.resize(Nx,Ny,Nz); Vel_z.fill(0);
|
||||
SDs.resize(Nx,Ny,Nz); SDs.fill(0);
|
||||
|
||||
if (Dm->rank()==0){
|
||||
bool WriteHeader=false;
|
||||
TIMELOG = fopen("free.csv","r");
|
||||
if (TIMELOG != NULL)
|
||||
fclose(TIMELOG);
|
||||
else
|
||||
WriteHeader=true;
|
||||
FreeEnergyAnalyzer::FreeEnergyAnalyzer(std::shared_ptr<Domain> dm) : Dm(dm) {
|
||||
|
||||
TIMELOG = fopen("free.csv","a+");
|
||||
if (WriteHeader)
|
||||
{
|
||||
// If timelog is empty, write a short header to list the averages
|
||||
//fprintf(TIMELOG,"--------------------------------------------------------------------------------------\n");
|
||||
fprintf(TIMELOG,"timestep\n");
|
||||
}
|
||||
}
|
||||
Nx = dm->Nx;
|
||||
Ny = dm->Ny;
|
||||
Nz = dm->Nz;
|
||||
Volume = (Nx - 2) * (Ny - 2) * (Nz - 2) * Dm->nprocx() * Dm->nprocy() *
|
||||
Dm->nprocz() * 1.0;
|
||||
|
||||
ChemicalPotential.resize(Nx, Ny, Nz);
|
||||
ChemicalPotential.fill(0);
|
||||
Phi.resize(Nx, Ny, Nz);
|
||||
Phi.fill(0);
|
||||
Pressure.resize(Nx, Ny, Nz);
|
||||
Pressure.fill(0);
|
||||
Rho.resize(Nx, Ny, Nz);
|
||||
Rho.fill(0);
|
||||
Vel_x.resize(Nx, Ny, Nz);
|
||||
Vel_x.fill(0); // Gradient of the phase indicator field
|
||||
Vel_y.resize(Nx, Ny, Nz);
|
||||
Vel_y.fill(0);
|
||||
Vel_z.resize(Nx, Ny, Nz);
|
||||
Vel_z.fill(0);
|
||||
SDs.resize(Nx, Ny, Nz);
|
||||
SDs.fill(0);
|
||||
|
||||
if (Dm->rank() == 0) {
|
||||
bool WriteHeader = false;
|
||||
TIMELOG = fopen("free.csv", "r");
|
||||
if (TIMELOG != NULL)
|
||||
fclose(TIMELOG);
|
||||
else
|
||||
WriteHeader = true;
|
||||
|
||||
TIMELOG = fopen("free.csv", "a+");
|
||||
if (WriteHeader) {
|
||||
// If timelog is empty, write a short header to list the averages
|
||||
//fprintf(TIMELOG,"--------------------------------------------------------------------------------------\n");
|
||||
fprintf(TIMELOG, "timestep\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FreeEnergyAnalyzer::~FreeEnergyAnalyzer(){
|
||||
if (Dm->rank()==0){
|
||||
fclose(TIMELOG);
|
||||
}
|
||||
FreeEnergyAnalyzer::~FreeEnergyAnalyzer() {
|
||||
if (Dm->rank() == 0) {
|
||||
fclose(TIMELOG);
|
||||
}
|
||||
}
|
||||
|
||||
void FreeEnergyAnalyzer::SetParams(){
|
||||
|
||||
}
|
||||
void FreeEnergyAnalyzer::SetParams() {}
|
||||
|
||||
void FreeEnergyAnalyzer::Basic(ScaLBL_FreeLeeModel &LeeModel, int timestep){
|
||||
void FreeEnergyAnalyzer::Basic(ScaLBL_FreeLeeModel &LeeModel, int timestep) {
|
||||
|
||||
if (Dm->rank()==0){
|
||||
fprintf(TIMELOG,"%i ",timestep);
|
||||
/*for (int ion=0; ion<Ion.number_ion_species; ion++){
|
||||
if (Dm->rank() == 0) {
|
||||
fprintf(TIMELOG, "%i ", timestep);
|
||||
/*for (int ion=0; ion<Ion.number_ion_species; ion++){
|
||||
fprintf(TIMELOG,"%.8g ",rho_avg_global[ion]);
|
||||
fprintf(TIMELOG,"%.8g ",rho_mu_avg_global[ion]);
|
||||
fprintf(TIMELOG,"%.8g ",rho_psi_avg_global[ion]);
|
||||
|
@ -57,10 +62,10 @@ void FreeEnergyAnalyzer::Basic(ScaLBL_FreeLeeModel &LeeModel, int timestep){
|
|||
fprintf(TIMELOG,"%.8g ",rho_psi_fluctuation_global[ion]);
|
||||
}
|
||||
*/
|
||||
fprintf(TIMELOG,"\n");
|
||||
fflush(TIMELOG);
|
||||
}
|
||||
/* else{
|
||||
fprintf(TIMELOG, "\n");
|
||||
fflush(TIMELOG);
|
||||
}
|
||||
/* else{
|
||||
fprintf(TIMELOG,"%i ",timestep);
|
||||
for (int ion=0; ion<Ion.number_ion_species; ion++){
|
||||
fprintf(TIMELOG,"%.8g ",rho_avg_local[ion]);
|
||||
|
@ -73,106 +78,111 @@ void FreeEnergyAnalyzer::Basic(ScaLBL_FreeLeeModel &LeeModel, int timestep){
|
|||
} */
|
||||
}
|
||||
|
||||
void FreeEnergyAnalyzer::WriteVis( ScaLBL_FreeLeeModel &LeeModel, std::shared_ptr<Database> input_db, int timestep){
|
||||
|
||||
auto vis_db = input_db->getDatabase( "Visualization" );
|
||||
|
||||
std::vector<IO::MeshDataStruct> visData;
|
||||
fillHalo<double> fillData(Dm->Comm,Dm->rank_info,{Dm->Nx-2,Dm->Ny-2,Dm->Nz-2},{1,1,1},0,1);
|
||||
void FreeEnergyAnalyzer::WriteVis(ScaLBL_FreeLeeModel &LeeModel,
|
||||
std::shared_ptr<Database> input_db,
|
||||
int timestep) {
|
||||
|
||||
IO::initialize("","silo","false");
|
||||
// Create the MeshDataStruct
|
||||
auto vis_db = input_db->getDatabase("Visualization");
|
||||
|
||||
std::vector<IO::MeshDataStruct> visData;
|
||||
fillHalo<double> fillData(Dm->Comm, Dm->rank_info,
|
||||
{Dm->Nx - 2, Dm->Ny - 2, Dm->Nz - 2}, {1, 1, 1},
|
||||
0, 1);
|
||||
|
||||
IO::initialize("", "silo", "false");
|
||||
// Create the MeshDataStruct
|
||||
visData.resize(1);
|
||||
|
||||
visData[0].meshName = "domain";
|
||||
visData[0].mesh = std::make_shared<IO::DomainMesh>( Dm->rank_info,Dm->Nx-2,Dm->Ny-2,Dm->Nz-2,Dm->Lx,Dm->Ly,Dm->Lz );
|
||||
visData[0].mesh =
|
||||
std::make_shared<IO::DomainMesh>(Dm->rank_info, Dm->Nx - 2, Dm->Ny - 2,
|
||||
Dm->Nz - 2, Dm->Lx, Dm->Ly, Dm->Lz);
|
||||
auto VisPhase = std::make_shared<IO::Variable>();
|
||||
auto VisPressure = std::make_shared<IO::Variable>();
|
||||
auto VisChemicalPotential = std::make_shared<IO::Variable>();
|
||||
auto VxVar = std::make_shared<IO::Variable>();
|
||||
auto VyVar = std::make_shared<IO::Variable>();
|
||||
auto VzVar = std::make_shared<IO::Variable>();
|
||||
|
||||
|
||||
if (vis_db->getWithDefault<bool>( "save_phase_field", true )){
|
||||
VisPhase->name = "Phase";
|
||||
VisPhase->type = IO::VariableType::VolumeVariable;
|
||||
VisPhase->dim = 1;
|
||||
VisPhase->data.resize(Dm->Nx-2,Dm->Ny-2,Dm->Nz-2);
|
||||
if (vis_db->getWithDefault<bool>("save_phase_field", true)) {
|
||||
VisPhase->name = "Phase";
|
||||
VisPhase->type = IO::VariableType::VolumeVariable;
|
||||
VisPhase->dim = 1;
|
||||
VisPhase->data.resize(Dm->Nx - 2, Dm->Ny - 2, Dm->Nz - 2);
|
||||
visData[0].vars.push_back(VisPhase);
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>( "save_potential", true )){
|
||||
|
||||
VisPressure->name = "Pressure";
|
||||
VisPressure->type = IO::VariableType::VolumeVariable;
|
||||
VisPressure->dim = 1;
|
||||
VisPressure->data.resize(Dm->Nx-2,Dm->Ny-2,Dm->Nz-2);
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>("save_potential", true)) {
|
||||
|
||||
VisPressure->name = "Pressure";
|
||||
VisPressure->type = IO::VariableType::VolumeVariable;
|
||||
VisPressure->dim = 1;
|
||||
VisPressure->data.resize(Dm->Nx - 2, Dm->Ny - 2, Dm->Nz - 2);
|
||||
visData[0].vars.push_back(VisPressure);
|
||||
|
||||
VisChemicalPotential->name = "ChemicalPotential";
|
||||
VisChemicalPotential->type = IO::VariableType::VolumeVariable;
|
||||
VisChemicalPotential->dim = 1;
|
||||
VisChemicalPotential->data.resize(Dm->Nx-2,Dm->Ny-2,Dm->Nz-2);
|
||||
|
||||
VisChemicalPotential->name = "ChemicalPotential";
|
||||
VisChemicalPotential->type = IO::VariableType::VolumeVariable;
|
||||
VisChemicalPotential->dim = 1;
|
||||
VisChemicalPotential->data.resize(Dm->Nx - 2, Dm->Ny - 2, Dm->Nz - 2);
|
||||
visData[0].vars.push_back(VisChemicalPotential);
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>( "save_velocity", false )){
|
||||
if (vis_db->getWithDefault<bool>("save_velocity", false)) {
|
||||
VxVar->name = "Velocity_x";
|
||||
VxVar->type = IO::VariableType::VolumeVariable;
|
||||
VxVar->dim = 1;
|
||||
VxVar->data.resize(Dm->Nx-2,Dm->Ny-2,Dm->Nz-2);
|
||||
VxVar->data.resize(Dm->Nx - 2, Dm->Ny - 2, Dm->Nz - 2);
|
||||
visData[0].vars.push_back(VxVar);
|
||||
VyVar->name = "Velocity_y";
|
||||
VyVar->type = IO::VariableType::VolumeVariable;
|
||||
VyVar->dim = 1;
|
||||
VyVar->data.resize(Dm->Nx-2,Dm->Ny-2,Dm->Nz-2);
|
||||
VyVar->data.resize(Dm->Nx - 2, Dm->Ny - 2, Dm->Nz - 2);
|
||||
visData[0].vars.push_back(VyVar);
|
||||
VzVar->name = "Velocity_z";
|
||||
VzVar->type = IO::VariableType::VolumeVariable;
|
||||
VzVar->dim = 1;
|
||||
VzVar->data.resize(Dm->Nx-2,Dm->Ny-2,Dm->Nz-2);
|
||||
VzVar->data.resize(Dm->Nx - 2, Dm->Ny - 2, Dm->Nz - 2);
|
||||
visData[0].vars.push_back(VzVar);
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>( "save_phase", true )){
|
||||
ASSERT(visData[0].vars[0]->name=="Phase");
|
||||
LeeModel.getPhase(Phi);
|
||||
Array<double>& PhaseData = visData[0].vars[0]->data;
|
||||
fillData.copy(Phi,PhaseData);
|
||||
|
||||
if (vis_db->getWithDefault<bool>("save_phase", true)) {
|
||||
ASSERT(visData[0].vars[0]->name == "Phase");
|
||||
LeeModel.getPhase(Phi);
|
||||
Array<double> &PhaseData = visData[0].vars[0]->data;
|
||||
fillData.copy(Phi, PhaseData);
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>( "save_potential", true )){
|
||||
ASSERT(visData[0].vars[1]->name=="Pressure");
|
||||
LeeModel.getPotential(Pressure, ChemicalPotential);
|
||||
Array<double>& PressureData = visData[0].vars[1]->data;
|
||||
fillData.copy(Pressure,PressureData);
|
||||
|
||||
ASSERT(visData[0].vars[2]->name=="ChemicalPotential");
|
||||
Array<double>& ChemicalPotentialData = visData[0].vars[2]->data;
|
||||
fillData.copy(ChemicalPotential,ChemicalPotentialData);
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>( "save_velocity", false )){
|
||||
ASSERT(visData[0].vars[3]->name=="Velocity_x");
|
||||
ASSERT(visData[0].vars[4]->name=="Velocity_y");
|
||||
ASSERT(visData[0].vars[5]->name=="Velocity_z");
|
||||
LeeModel.getVelocity(Vel_x,Vel_y,Vel_z);
|
||||
Array<double>& VelxData = visData[0].vars[3]->data;
|
||||
Array<double>& VelyData = visData[0].vars[4]->data;
|
||||
Array<double>& VelzData = visData[0].vars[5]->data;
|
||||
fillData.copy(Vel_x,VelxData);
|
||||
fillData.copy(Vel_y,VelyData);
|
||||
fillData.copy(Vel_z,VelzData);
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>( "write_silo", true ))
|
||||
IO::writeData( timestep, visData, Dm->Comm );
|
||||
if (vis_db->getWithDefault<bool>("save_potential", true)) {
|
||||
ASSERT(visData[0].vars[1]->name == "Pressure");
|
||||
LeeModel.getPotential(Pressure, ChemicalPotential);
|
||||
Array<double> &PressureData = visData[0].vars[1]->data;
|
||||
fillData.copy(Pressure, PressureData);
|
||||
|
||||
/* if (vis_db->getWithDefault<bool>( "save_8bit_raw", true )){
|
||||
ASSERT(visData[0].vars[2]->name == "ChemicalPotential");
|
||||
Array<double> &ChemicalPotentialData = visData[0].vars[2]->data;
|
||||
fillData.copy(ChemicalPotential, ChemicalPotentialData);
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>("save_velocity", false)) {
|
||||
ASSERT(visData[0].vars[3]->name == "Velocity_x");
|
||||
ASSERT(visData[0].vars[4]->name == "Velocity_y");
|
||||
ASSERT(visData[0].vars[5]->name == "Velocity_z");
|
||||
LeeModel.getVelocity(Vel_x, Vel_y, Vel_z);
|
||||
Array<double> &VelxData = visData[0].vars[3]->data;
|
||||
Array<double> &VelyData = visData[0].vars[4]->data;
|
||||
Array<double> &VelzData = visData[0].vars[5]->data;
|
||||
fillData.copy(Vel_x, VelxData);
|
||||
fillData.copy(Vel_y, VelyData);
|
||||
fillData.copy(Vel_z, VelzData);
|
||||
}
|
||||
|
||||
if (vis_db->getWithDefault<bool>("write_silo", true))
|
||||
IO::writeData(timestep, visData, Dm->Comm);
|
||||
|
||||
/* if (vis_db->getWithDefault<bool>( "save_8bit_raw", true )){
|
||||
char CurrentIDFilename[40];
|
||||
sprintf(CurrentIDFilename,"id_t%d.raw",timestep);
|
||||
Averages.AggregateLabels(CurrentIDFilename);
|
||||
}
|
||||
*/
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -19,36 +19,44 @@
|
|||
#include "IO/Writer.h"
|
||||
#include "models/FreeLeeModel.h"
|
||||
|
||||
class FreeEnergyAnalyzer{
|
||||
/**
|
||||
* \class FreeEnergyAnalyzer
|
||||
*
|
||||
* @brief
|
||||
* The FreeEnergyAnalyzer class is constructed to analyze the LBPM free energy model for liquid-gas systems
|
||||
*
|
||||
*/
|
||||
|
||||
class FreeEnergyAnalyzer {
|
||||
public:
|
||||
std::shared_ptr <Domain> Dm;
|
||||
double Volume;
|
||||
// input variables
|
||||
double rho_n, rho_w;
|
||||
double nu_n, nu_w;
|
||||
double gamma_wn, beta;
|
||||
double Fx, Fy, Fz;
|
||||
std::shared_ptr<Domain> Dm;
|
||||
double Volume;
|
||||
// input variables
|
||||
double rho_n, rho_w;
|
||||
double nu_n, nu_w;
|
||||
double gamma_wn, beta;
|
||||
double Fx, Fy, Fz;
|
||||
|
||||
//...........................................................................
|
||||
int Nx,Ny,Nz;
|
||||
DoubleArray Rho;
|
||||
DoubleArray Phi;
|
||||
DoubleArray ChemicalPotential;
|
||||
DoubleArray Pressure;
|
||||
DoubleArray Vel_x;
|
||||
DoubleArray Vel_y;
|
||||
DoubleArray Vel_z;
|
||||
DoubleArray SDs;
|
||||
int Nx, Ny, Nz;
|
||||
DoubleArray Rho;
|
||||
DoubleArray Phi;
|
||||
DoubleArray ChemicalPotential;
|
||||
DoubleArray Pressure;
|
||||
DoubleArray Vel_x;
|
||||
DoubleArray Vel_y;
|
||||
DoubleArray Vel_z;
|
||||
DoubleArray SDs;
|
||||
|
||||
FreeEnergyAnalyzer(std::shared_ptr <Domain> Dm);
|
||||
~FreeEnergyAnalyzer();
|
||||
|
||||
void SetParams();
|
||||
void Basic( ScaLBL_FreeLeeModel &LeeModel, int timestep);
|
||||
void WriteVis( ScaLBL_FreeLeeModel &LeeModel, std::shared_ptr<Database> input_db, int timestep);
|
||||
FreeEnergyAnalyzer(std::shared_ptr<Domain> Dm);
|
||||
~FreeEnergyAnalyzer();
|
||||
|
||||
void SetParams();
|
||||
void Basic(ScaLBL_FreeLeeModel &LeeModel, int timestep);
|
||||
void WriteVis(ScaLBL_FreeLeeModel &LeeModel,
|
||||
std::shared_ptr<Database> input_db, int timestep);
|
||||
|
||||
private:
|
||||
FILE *TIMELOG;
|
||||
FILE *TIMELOG;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,202 +1,234 @@
|
|||
#include "analysis/GreyPhase.h"
|
||||
|
||||
// Constructor
|
||||
GreyPhaseAnalysis::GreyPhaseAnalysis(std::shared_ptr <Domain> dm):
|
||||
Dm(dm)
|
||||
{
|
||||
Nx=dm->Nx; Ny=dm->Ny; Nz=dm->Nz;
|
||||
Volume=(Nx-2)*(Ny-2)*(Nz-2)*Dm->nprocx()*Dm->nprocy()*Dm->nprocz()*1.0;
|
||||
|
||||
// Global arrays
|
||||
SDs.resize(Nx,Ny,Nz); SDs.fill(0);
|
||||
Porosity.resize(Nx,Ny,Nz); Porosity.fill(0);
|
||||
//PhaseID.resize(Nx,Ny,Nz); PhaseID.fill(0);
|
||||
Rho_n.resize(Nx,Ny,Nz); Rho_n.fill(0);
|
||||
Rho_w.resize(Nx,Ny,Nz); Rho_w.fill(0);
|
||||
Pressure.resize(Nx,Ny,Nz); Pressure.fill(0);
|
||||
//Phi.resize(Nx,Ny,Nz); Phi.fill(0);
|
||||
//DelPhi.resize(Nx,Ny,Nz); DelPhi.fill(0);
|
||||
Vel_x.resize(Nx,Ny,Nz); Vel_x.fill(0); // Gradient of the phase indicator field
|
||||
Vel_y.resize(Nx,Ny,Nz); Vel_y.fill(0);
|
||||
Vel_z.resize(Nx,Ny,Nz); Vel_z.fill(0);
|
||||
//.........................................
|
||||
|
||||
if (Dm->rank()==0){
|
||||
bool WriteHeader=false;
|
||||
TIMELOG = fopen("timelog.csv","r");
|
||||
if (TIMELOG != NULL)
|
||||
fclose(TIMELOG);
|
||||
else
|
||||
WriteHeader=true;
|
||||
GreyPhaseAnalysis::GreyPhaseAnalysis(std::shared_ptr<Domain> dm) : Dm(dm) {
|
||||
Nx = dm->Nx;
|
||||
Ny = dm->Ny;
|
||||
Nz = dm->Nz;
|
||||
Volume = (Nx - 2) * (Ny - 2) * (Nz - 2) * Dm->nprocx() * Dm->nprocy() *
|
||||
Dm->nprocz() * 1.0;
|
||||
|
||||
TIMELOG = fopen("timelog.csv","a+");
|
||||
if (WriteHeader)
|
||||
{
|
||||
// If timelog is empty, write a short header to list the averages
|
||||
//fprintf(TIMELOG,"--------------------------------------------------------------------------------------\n");
|
||||
fprintf(TIMELOG,"sw krw krn vw vn pw pn\n");
|
||||
}
|
||||
}
|
||||
// Global arrays
|
||||
SDs.resize(Nx, Ny, Nz);
|
||||
SDs.fill(0);
|
||||
Porosity.resize(Nx, Ny, Nz);
|
||||
Porosity.fill(0);
|
||||
//PhaseID.resize(Nx,Ny,Nz); PhaseID.fill(0);
|
||||
Rho_n.resize(Nx, Ny, Nz);
|
||||
Rho_n.fill(0);
|
||||
Rho_w.resize(Nx, Ny, Nz);
|
||||
Rho_w.fill(0);
|
||||
Pressure.resize(Nx, Ny, Nz);
|
||||
Pressure.fill(0);
|
||||
//Phi.resize(Nx,Ny,Nz); Phi.fill(0);
|
||||
//DelPhi.resize(Nx,Ny,Nz); DelPhi.fill(0);
|
||||
Vel_x.resize(Nx, Ny, Nz);
|
||||
Vel_x.fill(0); // Gradient of the phase indicator field
|
||||
Vel_y.resize(Nx, Ny, Nz);
|
||||
Vel_y.fill(0);
|
||||
Vel_z.resize(Nx, Ny, Nz);
|
||||
Vel_z.fill(0);
|
||||
MobilityRatio.resize(Nx, Ny, Nz);
|
||||
MobilityRatio.fill(0);
|
||||
//.........................................
|
||||
|
||||
if (Dm->rank() == 0) {
|
||||
bool WriteHeader = false;
|
||||
TIMELOG = fopen("timelog.csv", "r");
|
||||
if (TIMELOG != NULL)
|
||||
fclose(TIMELOG);
|
||||
else
|
||||
WriteHeader = true;
|
||||
|
||||
TIMELOG = fopen("timelog.csv", "a+");
|
||||
if (WriteHeader) {
|
||||
// If timelog is empty, write a short header to list the averages
|
||||
//fprintf(TIMELOG,"--------------------------------------------------------------------------------------\n");
|
||||
fprintf(TIMELOG, "sw krw krn vw vn pw pn\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Destructor
|
||||
GreyPhaseAnalysis::~GreyPhaseAnalysis()
|
||||
{
|
||||
GreyPhaseAnalysis::~GreyPhaseAnalysis() {}
|
||||
|
||||
}
|
||||
void GreyPhaseAnalysis::Write(int timestep) {}
|
||||
|
||||
void GreyPhaseAnalysis::Write(int timestep)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GreyPhaseAnalysis::SetParams(double rhoA, double rhoB, double tauA, double tauB, double force_x, double force_y, double force_z, double alpha, double B, double GreyPorosity)
|
||||
{
|
||||
Fx = force_x;
|
||||
Fy = force_y;
|
||||
Fz = force_z;
|
||||
rho_n = rhoA;
|
||||
rho_w = rhoB;
|
||||
nu_n = (tauA-0.5)/3.f;
|
||||
nu_w = (tauB-0.5)/3.f;
|
||||
gamma_wn = 6.0*alpha;
|
||||
beta = B;
|
||||
void GreyPhaseAnalysis::SetParams(double rhoA, double rhoB, double tauA,
|
||||
double tauB, double force_x, double force_y,
|
||||
double force_z, double alpha, double B,
|
||||
double GreyPorosity) {
|
||||
Fx = force_x;
|
||||
Fy = force_y;
|
||||
Fz = force_z;
|
||||
rho_n = rhoA;
|
||||
rho_w = rhoB;
|
||||
nu_n = (tauA - 0.5) / 3.f;
|
||||
nu_w = (tauB - 0.5) / 3.f;
|
||||
gamma_wn = 6.0 * alpha;
|
||||
beta = B;
|
||||
grey_porosity = GreyPorosity;
|
||||
}
|
||||
|
||||
void GreyPhaseAnalysis::Basic(){
|
||||
int i,j,k,n,imin,jmin,kmin,kmax;
|
||||
void GreyPhaseAnalysis::Basic() {
|
||||
int i, j, k, n, imin, jmin, kmin, kmax;
|
||||
|
||||
// If external boundary conditions are set, do not average over the inlet
|
||||
kmin=1; kmax=Nz-1;
|
||||
imin=jmin=1;
|
||||
if (Dm->inlet_layers_z > 0 && Dm->kproc() == 0) kmin += Dm->inlet_layers_z;
|
||||
if (Dm->outlet_layers_z > 0 && Dm->kproc() == Dm->nprocz()-1) kmax -= Dm->outlet_layers_z;
|
||||
// If external boundary conditions are set, do not average over the inlet
|
||||
kmin = 1;
|
||||
kmax = Nz - 1;
|
||||
imin = jmin = 1;
|
||||
if (Dm->inlet_layers_z > 0 && Dm->kproc() == 0)
|
||||
kmin += Dm->inlet_layers_z;
|
||||
if (Dm->outlet_layers_z > 0 && Dm->kproc() == Dm->nprocz() - 1)
|
||||
kmax -= Dm->outlet_layers_z;
|
||||
|
||||
Water_local.reset();
|
||||
Oil_local.reset();
|
||||
double count_w = 0.0;
|
||||
double count_n = 0.0;
|
||||
for (k=kmin; k<kmax; k++){
|
||||
for (j=jmin; j<Ny-1; j++){
|
||||
for (i=imin; i<Nx-1; i++){
|
||||
n = k*Nx*Ny + j*Nx + i;
|
||||
// Compute volume averages
|
||||
if ( Dm->id[n] > 0 ){
|
||||
// compute density
|
||||
double nA = Rho_n(n);
|
||||
double nB = Rho_w(n);
|
||||
double phi = (nA-nB)/(nA+nB);
|
||||
double porosity = Porosity(n);
|
||||
Water_local.M += rho_w*nB*porosity;
|
||||
Water_local.Px += porosity*rho_w*nB*Vel_x(n);
|
||||
Water_local.Py += porosity*rho_w*nB*Vel_y(n);
|
||||
Water_local.Pz += porosity*rho_w*nB*Vel_z(n);
|
||||
Oil_local.M += rho_n*nA*porosity;
|
||||
Oil_local.Px += porosity*rho_n*nA*Vel_x(n);
|
||||
Oil_local.Py += porosity*rho_n*nA*Vel_y(n);
|
||||
Oil_local.Pz += porosity*rho_n*nA*Vel_z(n);
|
||||
Water_local.reset();
|
||||
Oil_local.reset();
|
||||
double count_w = 0.0;
|
||||
double count_n = 0.0;
|
||||
for (k = kmin; k < kmax; k++) {
|
||||
for (j = jmin; j < Ny - 1; j++) {
|
||||
for (i = imin; i < Nx - 1; i++) {
|
||||
n = k * Nx * Ny + j * Nx + i;
|
||||
// Compute volume averages
|
||||
if (Dm->id[n] > 0) {
|
||||
// compute density
|
||||
double nA = Rho_n(n);
|
||||
double nB = Rho_w(n);
|
||||
double phi = (nA - nB) / (nA + nB);
|
||||
double porosity = Porosity(n);
|
||||
double mobility_ratio = MobilityRatio(n);
|
||||
|
||||
if ( phi > 0.99 ){
|
||||
Oil_local.p += Pressure(n);
|
||||
//Oil_local.p += pressure*(rho_n*nA)/(rho_n*nA+rho_w*nB);
|
||||
count_n += 1.0;
|
||||
}
|
||||
else if ( phi < -0.99 ){
|
||||
Water_local.p += Pressure(n);
|
||||
//Water_local.p += pressure*(rho_w*nB)/(rho_n*nA+rho_w*nB);
|
||||
count_w += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Oil.M=Dm->Comm.sumReduce( Oil_local.M);
|
||||
Oil.Px=Dm->Comm.sumReduce( Oil_local.Px);
|
||||
Oil.Py=Dm->Comm.sumReduce( Oil_local.Py);
|
||||
Oil.Pz=Dm->Comm.sumReduce( Oil_local.Pz);
|
||||
|
||||
Water.M=Dm->Comm.sumReduce( Water_local.M);
|
||||
Water.Px=Dm->Comm.sumReduce( Water_local.Px);
|
||||
Water.Py=Dm->Comm.sumReduce( Water_local.Py);
|
||||
Water.Pz=Dm->Comm.sumReduce( Water_local.Pz);
|
||||
Water_local.M += nB * porosity;
|
||||
Water_local.Px += porosity * (nA + nB) * Vel_x(n) * 0.5 *
|
||||
(1.0 - mobility_ratio);
|
||||
Water_local.Py += porosity * (nA + nB) * Vel_y(n) * 0.5 *
|
||||
(1.0 - mobility_ratio);
|
||||
Water_local.Pz += porosity * (nA + nB) * Vel_z(n) * 0.5 *
|
||||
(1.0 - mobility_ratio);
|
||||
|
||||
Oil_local.M += nA * porosity;
|
||||
Oil_local.Px += porosity * (nA + nB) * Vel_x(n) * 0.5 *
|
||||
(1.0 + mobility_ratio);
|
||||
Oil_local.Py += porosity * (nA + nB) * Vel_y(n) * 0.5 *
|
||||
(1.0 + mobility_ratio);
|
||||
Oil_local.Pz += porosity * (nA + nB) * Vel_z(n) * 0.5 *
|
||||
(1.0 + mobility_ratio);
|
||||
|
||||
//Oil.p /= Oil.M;
|
||||
//Water.p /= Water.M;
|
||||
count_w=Dm->Comm.sumReduce( count_w);
|
||||
count_n=Dm->Comm.sumReduce( count_n);
|
||||
if (count_w > 0.0)
|
||||
Water.p=Dm->Comm.sumReduce( Water_local.p) / count_w;
|
||||
else
|
||||
Water.p = 0.0;
|
||||
if (count_n > 0.0)
|
||||
Oil.p=Dm->Comm.sumReduce( Oil_local.p) / count_n;
|
||||
else
|
||||
Oil.p = 0.0;
|
||||
if (phi > 0.99) {
|
||||
Oil_local.p += Pressure(n);
|
||||
//Oil_local.p += pressure*(rho_n*nA)/(rho_n*nA+rho_w*nB);
|
||||
count_n += 1.0;
|
||||
} else if (phi < -0.99) {
|
||||
Water_local.p += Pressure(n);
|
||||
//Water_local.p += pressure*(rho_w*nB)/(rho_n*nA+rho_w*nB);
|
||||
count_w += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Oil.M = Dm->Comm.sumReduce(Oil_local.M);
|
||||
Oil.Px = Dm->Comm.sumReduce(Oil_local.Px);
|
||||
Oil.Py = Dm->Comm.sumReduce(Oil_local.Py);
|
||||
Oil.Pz = Dm->Comm.sumReduce(Oil_local.Pz);
|
||||
|
||||
// check for NaN
|
||||
bool err=false;
|
||||
if (Water.M != Water.M) err=true;
|
||||
if (Water.p != Water.p) err=true;
|
||||
if (Water.Px != Water.Px) err=true;
|
||||
if (Water.Py != Water.Py) err=true;
|
||||
if (Water.Pz != Water.Pz) err=true;
|
||||
Water.M = Dm->Comm.sumReduce(Water_local.M);
|
||||
Water.Px = Dm->Comm.sumReduce(Water_local.Px);
|
||||
Water.Py = Dm->Comm.sumReduce(Water_local.Py);
|
||||
Water.Pz = Dm->Comm.sumReduce(Water_local.Pz);
|
||||
|
||||
if (Oil.M != Oil.M) err=true;
|
||||
if (Oil.p != Oil.p) err=true;
|
||||
if (Oil.Px != Oil.Px) err=true;
|
||||
if (Oil.Py != Oil.Py) err=true;
|
||||
if (Oil.Pz != Oil.Pz) err=true;
|
||||
|
||||
if (Dm->rank() == 0){
|
||||
double force_mag = sqrt(Fx*Fx+Fy*Fy+Fz*Fz);
|
||||
double dir_x = 0.0;
|
||||
double dir_y = 0.0;
|
||||
double dir_z = 0.0;
|
||||
if (force_mag > 0.0){
|
||||
dir_x = Fx/force_mag;
|
||||
dir_y = Fy/force_mag;
|
||||
dir_z = Fz/force_mag;
|
||||
}
|
||||
else {
|
||||
// default to z direction
|
||||
dir_x = 0.0;
|
||||
dir_y = 0.0;
|
||||
dir_z = 1.0;
|
||||
}
|
||||
if (Dm->BoundaryCondition == 1 || Dm->BoundaryCondition == 2 || Dm->BoundaryCondition == 3 || Dm->BoundaryCondition == 4 ){
|
||||
// compute the pressure drop
|
||||
double pressure_drop = (Pressure(Nx*Ny + Nx + 1) - 1.0) / 3.0;
|
||||
double length = ((Nz-2)*Dm->nprocz());
|
||||
force_mag -= pressure_drop/length;
|
||||
}
|
||||
if (force_mag == 0.0){
|
||||
// default to z direction
|
||||
dir_x = 0.0;
|
||||
dir_y = 0.0;
|
||||
dir_z = 1.0;
|
||||
force_mag = 1.0;
|
||||
}
|
||||
saturation=Water.M/(Water.M + Oil.M); // assume constant density
|
||||
water_flow_rate=grey_porosity*saturation*(Water.Px*dir_x + Water.Py*dir_y + Water.Pz*dir_z)/Water.M;
|
||||
oil_flow_rate =grey_porosity*(1.0-saturation)*(Oil.Px*dir_x + Oil.Py*dir_y + Oil.Pz*dir_z)/Oil.M;
|
||||
//Oil.p /= Oil.M;
|
||||
//Water.p /= Water.M;
|
||||
count_w = Dm->Comm.sumReduce(count_w);
|
||||
count_n = Dm->Comm.sumReduce(count_n);
|
||||
if (count_w > 0.0)
|
||||
Water.p = Dm->Comm.sumReduce(Water_local.p) / count_w;
|
||||
else
|
||||
Water.p = 0.0;
|
||||
if (count_n > 0.0)
|
||||
Oil.p = Dm->Comm.sumReduce(Oil_local.p) / count_n;
|
||||
else
|
||||
Oil.p = 0.0;
|
||||
|
||||
double h = Dm->voxel_length;
|
||||
// check for NaN
|
||||
bool err = false;
|
||||
if (Water.M != Water.M)
|
||||
err = true;
|
||||
if (Water.p != Water.p)
|
||||
err = true;
|
||||
if (Water.Px != Water.Px)
|
||||
err = true;
|
||||
if (Water.Py != Water.Py)
|
||||
err = true;
|
||||
if (Water.Pz != Water.Pz)
|
||||
err = true;
|
||||
|
||||
if (Oil.M != Oil.M)
|
||||
err = true;
|
||||
if (Oil.p != Oil.p)
|
||||
err = true;
|
||||
if (Oil.Px != Oil.Px)
|
||||
err = true;
|
||||
if (Oil.Py != Oil.Py)
|
||||
err = true;
|
||||
if (Oil.Pz != Oil.Pz)
|
||||
err = true;
|
||||
|
||||
if (Dm->rank() == 0) {
|
||||
double force_mag = sqrt(Fx * Fx + Fy * Fy + Fz * Fz);
|
||||
double dir_x = 0.0;
|
||||
double dir_y = 0.0;
|
||||
double dir_z = 0.0;
|
||||
if (force_mag > 0.0) {
|
||||
dir_x = Fx / force_mag;
|
||||
dir_y = Fy / force_mag;
|
||||
dir_z = Fz / force_mag;
|
||||
} else {
|
||||
// default to z direction
|
||||
dir_x = 0.0;
|
||||
dir_y = 0.0;
|
||||
dir_z = 1.0;
|
||||
}
|
||||
if (Dm->BoundaryCondition == 1 || Dm->BoundaryCondition == 2 ||
|
||||
Dm->BoundaryCondition == 3 || Dm->BoundaryCondition == 4) {
|
||||
// compute the pressure drop
|
||||
double pressure_drop = (Pressure(Nx * Ny + Nx + 1) - 1.0) / 3.0;
|
||||
double length = ((Nz - 2) * Dm->nprocz());
|
||||
force_mag -= pressure_drop / length;
|
||||
}
|
||||
if (force_mag == 0.0) {
|
||||
// default to z direction
|
||||
dir_x = 0.0;
|
||||
dir_y = 0.0;
|
||||
dir_z = 1.0;
|
||||
force_mag = 1.0;
|
||||
}
|
||||
saturation = Water.M / (Water.M + Oil.M); // assume constant density
|
||||
water_flow_rate =
|
||||
grey_porosity * saturation *
|
||||
(Water.Px * dir_x + Water.Py * dir_y + Water.Pz * dir_z) / Water.M;
|
||||
oil_flow_rate = grey_porosity * (1.0 - saturation) *
|
||||
(Oil.Px * dir_x + Oil.Py * dir_y + Oil.Pz * dir_z) /
|
||||
Oil.M;
|
||||
|
||||
double h = Dm->voxel_length;
|
||||
//TODO check if need greyporosity or domain porosity ? - compare to analytical solution
|
||||
double krn = h*h*nu_n*oil_flow_rate / force_mag ;
|
||||
double krw = h*h*nu_w*water_flow_rate / force_mag;
|
||||
//printf(" water saturation = %f, fractional flow =%f \n",saturation,fractional_flow);
|
||||
fprintf(TIMELOG,"%.5g %.5g %.5g %.5g %.5g %.5g %.5g\n",saturation,krw,krn,h*water_flow_rate,h*oil_flow_rate, Water.p, Oil.p);
|
||||
fflush(TIMELOG);
|
||||
}
|
||||
double krn = h * h * nu_n * oil_flow_rate / force_mag;
|
||||
double krw = h * h * nu_w * water_flow_rate / force_mag;
|
||||
//printf(" water saturation = %f, fractional flow =%f \n",saturation,fractional_flow);
|
||||
fprintf(TIMELOG, "%.5g %.5g %.5g %.5g %.5g %.5g %.5g\n", saturation,
|
||||
krw, krn, h * water_flow_rate, h * oil_flow_rate, Water.p,
|
||||
Oil.p);
|
||||
fflush(TIMELOG);
|
||||
}
|
||||
|
||||
if (err==true){
|
||||
// exception if simulation produceds NaN
|
||||
printf("GreyPhaseAnalysis.cpp: NaN encountered, may need to check simulation parameters \n");
|
||||
}
|
||||
ASSERT(err==false);
|
||||
if (err == true) {
|
||||
// exception if simulation produceds NaN
|
||||
printf("GreyPhaseAnalysis.cpp: NaN encountered, may need to check "
|
||||
"simulation parameters \n");
|
||||
}
|
||||
ASSERT(err == false);
|
||||
}
|
||||
/*
|
||||
inline void InterfaceTransportMeasures( double beta, double rA, double rB, double nA, double nB,
|
||||
|
|
|
@ -15,57 +15,71 @@
|
|||
#include "IO/Reader.h"
|
||||
#include "IO/Writer.h"
|
||||
|
||||
class GreyPhase{
|
||||
public:
|
||||
double p;
|
||||
double M,Px,Py,Pz;
|
||||
void reset(){
|
||||
p=M=Px=Py=Pz=0.0;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class GreyPhaseAnalysis{
|
||||
/**
|
||||
* \class GreyPhase
|
||||
*
|
||||
* @brief
|
||||
* The GreyPhase class tracks pressure, mass and momentum within a grey phase
|
||||
*
|
||||
*/
|
||||
class GreyPhase {
|
||||
public:
|
||||
std::shared_ptr <Domain> Dm;
|
||||
double Volume;
|
||||
// input variables
|
||||
double rho_n, rho_w;
|
||||
double nu_n, nu_w;
|
||||
double gamma_wn, beta;
|
||||
double Fx, Fy, Fz;
|
||||
double grey_porosity;
|
||||
// outputs
|
||||
double saturation,water_flow_rate, oil_flow_rate;
|
||||
|
||||
//simulation outputs (averaged values)
|
||||
GreyPhase Water, Oil;
|
||||
GreyPhase Water_local, Oil_local;
|
||||
//...........................................................................
|
||||
int Nx,Ny,Nz;
|
||||
//IntArray PhaseID; // Phase ID array
|
||||
DoubleArray SDs; // contains porosity map
|
||||
DoubleArray Porosity; // contains porosity map
|
||||
DoubleArray Rho_n; // density field
|
||||
DoubleArray Rho_w; // density field
|
||||
//DoubleArray Phi; // phase indicator field
|
||||
//DoubleArray DelPhi; // Magnitude of Gradient of the phase indicator field
|
||||
DoubleArray Pressure; // pressure field
|
||||
DoubleArray Vel_x; // velocity field
|
||||
DoubleArray Vel_y;
|
||||
DoubleArray Vel_z;
|
||||
|
||||
GreyPhaseAnalysis(std::shared_ptr <Domain> Dm);
|
||||
~GreyPhaseAnalysis();
|
||||
|
||||
void SetParams(double rhoA, double rhoB, double tauA, double tauB, double force_x, double force_y, double force_z, double alpha, double beta, double GreyPorosity);
|
||||
void Basic();
|
||||
void Write(int time);
|
||||
double p;
|
||||
double M, Px, Py, Pz;
|
||||
void reset() { p = M = Px = Py = Pz = 0.0; }
|
||||
|
||||
private:
|
||||
FILE *TIMELOG;
|
||||
};
|
||||
|
||||
/**
|
||||
* \class GreyPhaseAnalysis
|
||||
*
|
||||
* @brief
|
||||
* The GreyPhaseAnalysis class is constructed to analyze the LBPM greyscale model
|
||||
*
|
||||
*/
|
||||
class GreyPhaseAnalysis {
|
||||
public:
|
||||
std::shared_ptr<Domain> Dm;
|
||||
double Volume;
|
||||
// input variables
|
||||
double rho_n, rho_w;
|
||||
double nu_n, nu_w;
|
||||
double gamma_wn, beta;
|
||||
double Fx, Fy, Fz;
|
||||
double grey_porosity;
|
||||
// outputs
|
||||
double saturation, water_flow_rate, oil_flow_rate;
|
||||
|
||||
//simulation outputs (averaged values)
|
||||
GreyPhase Water, Oil;
|
||||
GreyPhase Water_local, Oil_local;
|
||||
//...........................................................................
|
||||
int Nx, Ny, Nz;
|
||||
//IntArray PhaseID; // Phase ID array
|
||||
DoubleArray SDs; // contains porosity map
|
||||
DoubleArray Porosity; // contains porosity map
|
||||
DoubleArray Rho_n; // density field
|
||||
DoubleArray Rho_w; // density field
|
||||
//DoubleArray Phi; // phase indicator field
|
||||
//DoubleArray DelPhi; // Magnitude of Gradient of the phase indicator field
|
||||
DoubleArray Pressure; // pressure field
|
||||
DoubleArray Vel_x; // velocity field
|
||||
DoubleArray Vel_y;
|
||||
DoubleArray Vel_z;
|
||||
DoubleArray MobilityRatio;
|
||||
|
||||
GreyPhaseAnalysis(std::shared_ptr<Domain> Dm);
|
||||
~GreyPhaseAnalysis();
|
||||
|
||||
void SetParams(double rhoA, double rhoB, double tauA, double tauB,
|
||||
double force_x, double force_y, double force_z, double alpha,
|
||||
double beta, double GreyPorosity);
|
||||
void Basic();
|
||||
void Write(int time);
|
||||
|
||||
private:
|
||||
FILE *TIMELOG;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "analysis/Minkowski.h"
|
||||
#include "analysis/pmmc.h"
|
||||
#include "analysis/analysis.h"
|
||||
|
@ -13,282 +29,278 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
|
||||
#define PI 3.14159265359
|
||||
|
||||
// Constructor
|
||||
Minkowski::Minkowski(std::shared_ptr <Domain> dm):
|
||||
kstart(0), kfinish(0), isovalue(0), Volume(0),
|
||||
LOGFILE(NULL), Dm(dm), Vi(0), Vi_global(0)
|
||||
{
|
||||
Nx=dm->Nx; Ny=dm->Ny; Nz=dm->Nz;
|
||||
Volume=double((Nx-2)*(Ny-2)*(Nz-2))*double(Dm->nprocx()*Dm->nprocy()*Dm->nprocz());
|
||||
|
||||
id.resize(Nx,Ny,Nz); id.fill(0);
|
||||
label.resize(Nx,Ny,Nz); label.fill(0);
|
||||
distance.resize(Nx,Ny,Nz); distance.fill(0);
|
||||
Minkowski::Minkowski(std::shared_ptr<Domain> dm)
|
||||
: kstart(0), kfinish(0), isovalue(0), Volume(0), LOGFILE(NULL), Dm(dm),
|
||||
Vi(0), Vi_global(0) {
|
||||
Nx = dm->Nx;
|
||||
Ny = dm->Ny;
|
||||
Nz = dm->Nz;
|
||||
Volume = double((Nx - 2) * (Ny - 2) * (Nz - 2)) *
|
||||
double(Dm->nprocx() * Dm->nprocy() * Dm->nprocz());
|
||||
|
||||
if (Dm->rank()==0){
|
||||
LOGFILE = fopen("minkowski.csv","a+");
|
||||
if (fseek(LOGFILE,0,SEEK_SET) == fseek(LOGFILE,0,SEEK_CUR))
|
||||
{
|
||||
// If LOGFILE is empty, write a short header to list the averages
|
||||
//fprintf(LOGFILE,"--------------------------------------------------------------------------------------\n");
|
||||
fprintf(LOGFILE,"Vn An Jn Xn\n"); //miknowski measures,
|
||||
}
|
||||
}
|
||||
id.resize(Nx, Ny, Nz);
|
||||
id.fill(0);
|
||||
label.resize(Nx, Ny, Nz);
|
||||
label.fill(0);
|
||||
distance.resize(Nx, Ny, Nz);
|
||||
distance.fill(0);
|
||||
|
||||
if (Dm->rank() == 0) {
|
||||
LOGFILE = fopen("minkowski.csv", "a+");
|
||||
if (fseek(LOGFILE, 0, SEEK_SET) == fseek(LOGFILE, 0, SEEK_CUR)) {
|
||||
// If LOGFILE is empty, write a short header to list the averages
|
||||
//fprintf(LOGFILE,"--------------------------------------------------------------------------------------\n");
|
||||
fprintf(LOGFILE, "Vn An Jn Xn\n"); //miknowski measures,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Destructor
|
||||
Minkowski::~Minkowski()
|
||||
{
|
||||
if ( LOGFILE!=NULL ) { fclose(LOGFILE); }
|
||||
Minkowski::~Minkowski() {
|
||||
if (LOGFILE != NULL) {
|
||||
fclose(LOGFILE);
|
||||
}
|
||||
}
|
||||
|
||||
void Minkowski::ComputeScalar(const DoubleArray& Field, const double isovalue)
|
||||
{
|
||||
void Minkowski::ComputeScalar(const DoubleArray &Field, const double isovalue) {
|
||||
PROFILE_START("ComputeScalar");
|
||||
Xi = Ji = Ai = 0.0;
|
||||
DECL object;
|
||||
int e1,e2,e3;
|
||||
double s,s1,s2,s3;
|
||||
double a1,a2,a3;
|
||||
//double Vx,Vy,Vz,Wx,Wy,Wz,nx,ny,nz,norm;
|
||||
//int Nx = Field.size(0);
|
||||
//int Ny = Field.size(1);
|
||||
//int Nz = Field.size(2);
|
||||
for (int k=1; k<Nz-1; k++){
|
||||
for (int j=1; j<Ny-1; j++){
|
||||
for (int i=1; i<Nx-1; i++){
|
||||
object.LocalIsosurface(Field,isovalue,i,j,k);
|
||||
for (int idx=0; idx<object.TriangleCount; idx++){
|
||||
e1 = object.Face(idx);
|
||||
e2 = object.halfedge.next(e1);
|
||||
e3 = object.halfedge.next(e2);
|
||||
auto P1 = object.vertex.coords(object.halfedge.v1(e1));
|
||||
auto P2 = object.vertex.coords(object.halfedge.v1(e2));
|
||||
auto P3 = object.vertex.coords(object.halfedge.v1(e3));
|
||||
// Surface area
|
||||
s1 = Distance( P1, P2 );
|
||||
s2 = Distance( P2, P3 );
|
||||
s3 = Distance( P1, P3 );
|
||||
s = 0.5*(s1+s2+s3);
|
||||
Ai += sqrt(s*(s-s1)*(s-s2)*(s-s3));
|
||||
// Mean curvature based on half edge angle
|
||||
a1 = object.EdgeAngle(e1);
|
||||
a2 = object.EdgeAngle(e2);
|
||||
a3 = object.EdgeAngle(e3);
|
||||
Ji += (a1*s1+a2*s2+a3*s3);
|
||||
//if (0.08333333333333*(a1*s1+a2*s2+a3*s3) < 0.f){
|
||||
//double intcurv=0.08333333333333*(a1*s1+a2*s2+a3*s3);
|
||||
//double surfarea=sqrt(s*(s-s1)*(s-s2)*(s-s3));
|
||||
//printf(" (%i,%i,%i) PQ(%i,%i)={%f,%f,%f} {%f,%f,%f} a=%f l=%f \n",i,j,k,e1,object.halfedge.twin(e1),P1.x,P1.y,P1.z,P2.x,P2.y,P2.z,a1,s1);
|
||||
// printf(" (%i,%i,%i) QR(%i,%i)={%f,%f,%f} {%f,%f,%f} a=%f l=%f \n",i,j,k,e2,object.halfedge.twin(e2),P2.x,P2.y,P2.z,P3.x,P3.y,P3.z,a2,s2);
|
||||
// printf(" (%i,%i,%i) RP(%i,%i)={%f,%f,%f} {%f,%f,%f} a=%f l=%f \n",i,j,k,e3,object.halfedge.twin(e3),P3.x,P3.y,P3.z,P1.x,P1.y,P1.z,a3,s3);
|
||||
//}
|
||||
// Euler characteristic (half edge rule: one face - 0.5*(three edges))
|
||||
Xi -= 0.5;
|
||||
}
|
||||
// Euler characteristic -- each vertex shared by four cubes
|
||||
//Xi += 0.25*double(object.VertexCount);
|
||||
// check if vertices are at corners
|
||||
for (int idx=0; idx<object.VertexCount; idx++){
|
||||
/*auto P1 = object.vertex.coords(idx);
|
||||
Xi = Ji = Ai = 0.0;
|
||||
DCEL object;
|
||||
int e1, e2, e3;
|
||||
double s, s1, s2, s3;
|
||||
double a1, a2, a3;
|
||||
//double Vx,Vy,Vz,Wx,Wy,Wz,nx,ny,nz,norm;
|
||||
//int Nx = Field.size(0);
|
||||
//int Ny = Field.size(1);
|
||||
//int Nz = Field.size(2);
|
||||
for (int k = 1; k < Nz - 1; k++) {
|
||||
for (int j = 1; j < Ny - 1; j++) {
|
||||
for (int i = 1; i < Nx - 1; i++) {
|
||||
object.LocalIsosurface(Field, isovalue, i, j, k);
|
||||
for (int idx = 0; idx < object.TriangleCount; idx++) {
|
||||
e1 = object.Face(idx);
|
||||
e2 = object.halfedge.next(e1);
|
||||
e3 = object.halfedge.next(e2);
|
||||
auto P1 = object.vertex.coords(object.halfedge.v1(e1));
|
||||
auto P2 = object.vertex.coords(object.halfedge.v1(e2));
|
||||
auto P3 = object.vertex.coords(object.halfedge.v1(e3));
|
||||
// Surface area
|
||||
s1 = Distance(P1, P2);
|
||||
s2 = Distance(P2, P3);
|
||||
s3 = Distance(P1, P3);
|
||||
s = 0.5 * (s1 + s2 + s3);
|
||||
Ai += sqrt(s * (s - s1) * (s - s2) * (s - s3));
|
||||
// Mean curvature based on half edge angle
|
||||
a1 = object.EdgeAngle(e1);
|
||||
a2 = object.EdgeAngle(e2);
|
||||
a3 = object.EdgeAngle(e3);
|
||||
Ji += (a1 * s1 + a2 * s2 + a3 * s3);
|
||||
//if (0.08333333333333*(a1*s1+a2*s2+a3*s3) < 0.f){
|
||||
//double intcurv=0.08333333333333*(a1*s1+a2*s2+a3*s3);
|
||||
//double surfarea=sqrt(s*(s-s1)*(s-s2)*(s-s3));
|
||||
//printf(" (%i,%i,%i) PQ(%i,%i)={%f,%f,%f} {%f,%f,%f} a=%f l=%f \n",i,j,k,e1,object.halfedge.twin(e1),P1.x,P1.y,P1.z,P2.x,P2.y,P2.z,a1,s1);
|
||||
// printf(" (%i,%i,%i) QR(%i,%i)={%f,%f,%f} {%f,%f,%f} a=%f l=%f \n",i,j,k,e2,object.halfedge.twin(e2),P2.x,P2.y,P2.z,P3.x,P3.y,P3.z,a2,s2);
|
||||
// printf(" (%i,%i,%i) RP(%i,%i)={%f,%f,%f} {%f,%f,%f} a=%f l=%f \n",i,j,k,e3,object.halfedge.twin(e3),P3.x,P3.y,P3.z,P1.x,P1.y,P1.z,a3,s3);
|
||||
//}
|
||||
// Euler characteristic (half edge rule: one face - 0.5*(three edges))
|
||||
Xi -= 0.5;
|
||||
}
|
||||
// Euler characteristic -- each vertex shared by four cubes
|
||||
//Xi += 0.25*double(object.VertexCount);
|
||||
// check if vertices are at corners
|
||||
for (int idx = 0; idx < object.VertexCount; idx++) {
|
||||
/*auto P1 = object.vertex.coords(idx);
|
||||
if ( remainder(P1.x,1.0)==0.0 && remainder(P1.y,1.0)==0.0 && remainder(P1.z,1.0)==0.0 ){
|
||||
Xi += 0.125;
|
||||
}
|
||||
else
|
||||
*/
|
||||
Xi += 0.25;
|
||||
}
|
||||
/*double nside_extern = double(npts);
|
||||
Xi += 0.25;
|
||||
}
|
||||
/*double nside_extern = double(npts);
|
||||
double nside_intern = double(npts)-3.0;
|
||||
EulerChar=0.0;
|
||||
if (npts > 0) EulerChar = (0.25*nvert - nside_intern - 0.5*nside_extern + nface); */
|
||||
}
|
||||
}
|
||||
}
|
||||
// Voxel counting for volume fraction
|
||||
Vi = 0.f;
|
||||
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 (Field(i,j,k) < isovalue){
|
||||
Vi += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// convert X for 2D manifold to 3D object
|
||||
Xi *= 0.5;
|
||||
|
||||
Dm->Comm.barrier();
|
||||
// Phase averages
|
||||
Vi_global = Dm->Comm.sumReduce( Vi );
|
||||
Xi_global = Dm->Comm.sumReduce( Xi );
|
||||
Ai_global = Dm->Comm.sumReduce( Ai );
|
||||
Ji_global = Dm->Comm.sumReduce( Ji );
|
||||
Dm->Comm.barrier();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Voxel counting for volume fraction
|
||||
Vi = 0.f;
|
||||
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 (Field(i, j, k) < isovalue) {
|
||||
Vi += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// convert X for 2D manifold to 3D object
|
||||
Xi *= 0.5;
|
||||
|
||||
Dm->Comm.barrier();
|
||||
// Phase averages
|
||||
Vi_global = Dm->Comm.sumReduce(Vi);
|
||||
Xi_global = Dm->Comm.sumReduce(Xi);
|
||||
Ai_global = Dm->Comm.sumReduce(Ai);
|
||||
Ji_global = Dm->Comm.sumReduce(Ji);
|
||||
Dm->Comm.barrier();
|
||||
PROFILE_STOP("ComputeScalar");
|
||||
}
|
||||
|
||||
|
||||
void Minkowski::MeasureObject(){
|
||||
/*
|
||||
void Minkowski::MeasureObject() {
|
||||
/*
|
||||
* compute the distance to an object
|
||||
*
|
||||
* THIS ALGORITHM ASSUMES THAT id() is populated with phase id to distinguish objects
|
||||
* 0 - labels the object
|
||||
* 1 - labels the rest of the
|
||||
*/
|
||||
//DoubleArray smooth_distance(Nx,Ny,Nz);
|
||||
for (int k=0; k<Nz; k++){
|
||||
for (int j=0; j<Ny; j++){
|
||||
for (int i=0; i<Nx; i++){
|
||||
distance(i,j,k) =2.0*double(id(i,j,k))-1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
CalcDist(distance,id,*Dm);
|
||||
//Mean3D(distance,smooth_distance);
|
||||
//Eikonal(distance, id, *Dm, 20, {true, true, true});
|
||||
ComputeScalar(distance,0.0);
|
||||
//DoubleArray smooth_distance(Nx,Ny,Nz);
|
||||
for (int k = 0; k < Nz; k++) {
|
||||
for (int j = 0; j < Ny; j++) {
|
||||
for (int i = 0; i < Nx; i++) {
|
||||
distance(i, j, k) = 2.0 * double(id(i, j, k)) - 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
CalcDist(distance, id, *Dm);
|
||||
//Mean3D(distance,smooth_distance);
|
||||
//Eikonal(distance, id, *Dm, 20, {true, true, true});
|
||||
ComputeScalar(distance, 0.0);
|
||||
}
|
||||
|
||||
|
||||
void Minkowski::MeasureObject(double factor, const DoubleArray &Phi){
|
||||
/*
|
||||
void Minkowski::MeasureObject(double factor, const DoubleArray &Phi) {
|
||||
/*
|
||||
* compute the distance to an object
|
||||
*
|
||||
* THIS ALGORITHM ASSUMES THAT id() is populated with phase id to distinguish objects
|
||||
* 0 - labels the object
|
||||
* 1 - labels the rest of the
|
||||
*/
|
||||
for (int k=0; k<Nz; k++){
|
||||
for (int j=0; j<Ny; j++){
|
||||
for (int i=0; i<Nx; i++){
|
||||
distance(i,j,k) =2.0*double(id(i,j,k))-1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
CalcDist(distance,id,*Dm);
|
||||
|
||||
for (int k=0; k<Nz; k++){
|
||||
for (int j=0; j<Ny; j++){
|
||||
for (int i=0; i<Nx; i++){
|
||||
double value = Phi(i,j,k);
|
||||
double dist_value = distance(i,j,k);
|
||||
if (dist_value < 2.5 && dist_value > -2.5) {
|
||||
double new_distance = factor*log((1.0+value)/(1.0-value));
|
||||
if (dist_value*new_distance < 0.0 )
|
||||
new_distance = (-1.0)*new_distance;
|
||||
distance(i,j,k) = new_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ComputeScalar(distance,0.0);
|
||||
for (int k = 0; k < Nz; k++) {
|
||||
for (int j = 0; j < Ny; j++) {
|
||||
for (int i = 0; i < Nx; i++) {
|
||||
distance(i, j, k) = 2.0 * double(id(i, j, k)) - 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
CalcDist(distance, id, *Dm);
|
||||
|
||||
for (int k = 0; k < Nz; k++) {
|
||||
for (int j = 0; j < Ny; j++) {
|
||||
for (int i = 0; i < Nx; i++) {
|
||||
double value = Phi(i, j, k);
|
||||
double dist_value = distance(i, j, k);
|
||||
if (dist_value < 2.5 && dist_value > -2.5) {
|
||||
double new_distance =
|
||||
factor * log((1.0 + value) / (1.0 - value));
|
||||
if (dist_value * new_distance < 0.0)
|
||||
new_distance = (-1.0) * new_distance;
|
||||
distance(i, j, k) = new_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ComputeScalar(distance, 0.0);
|
||||
}
|
||||
|
||||
|
||||
int Minkowski::MeasureConnectedPathway(){
|
||||
/*
|
||||
int Minkowski::MeasureConnectedPathway() {
|
||||
/*
|
||||
* compute the connected pathway for object with LABEL in id field
|
||||
* compute the labels for connected components
|
||||
* compute the distance to the connected pathway
|
||||
*
|
||||
* THIS ALGORITHM ASSUMES THAT id() is populated with phase id to distinguish objects
|
||||
*/
|
||||
|
||||
char LABEL = 0;
|
||||
for (int k=0; k<Nz; k++){
|
||||
for (int j=0; j<Ny; j++){
|
||||
for (int i=0; i<Nx; i++){
|
||||
if (id(i,j,k) == LABEL){
|
||||
distance(i,j,k) = 1.0;
|
||||
}
|
||||
else
|
||||
distance(i,j,k) = -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract only the connected part of NWP
|
||||
double vF=0.0;
|
||||
n_connected_components = ComputeGlobalBlobIDs(Nx-2,Ny-2,Nz-2,Dm->rank_info,distance,distance,vF,vF,label,Dm->Comm);
|
||||
// int n_connected_components = ComputeGlobalPhaseComponent(Nx-2,Ny-2,Nz-2,Dm->rank_info,const IntArray &PhaseID, int &VALUE, BlobIDArray &GlobalBlobID, Dm->Comm )
|
||||
Dm->Comm.barrier();
|
||||
|
||||
for (int k=0; k<Nz; k++){
|
||||
for (int j=0; j<Ny; j++){
|
||||
for (int i=0; i<Nx; i++){
|
||||
if ( label(i,j,k) == 0){
|
||||
id(i,j,k) = 0;
|
||||
}
|
||||
else{
|
||||
id(i,j,k) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MeasureObject();
|
||||
return n_connected_components;
|
||||
|
||||
char LABEL = 0;
|
||||
for (int k = 0; k < Nz; k++) {
|
||||
for (int j = 0; j < Ny; j++) {
|
||||
for (int i = 0; i < Nx; i++) {
|
||||
if (id(i, j, k) == LABEL) {
|
||||
distance(i, j, k) = 1.0;
|
||||
} else
|
||||
distance(i, j, k) = -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract only the connected part of NWP
|
||||
double vF = 0.0;
|
||||
n_connected_components =
|
||||
ComputeGlobalBlobIDs(Nx - 2, Ny - 2, Nz - 2, Dm->rank_info, distance,
|
||||
distance, vF, vF, label, Dm->Comm);
|
||||
// int n_connected_components = ComputeGlobalPhaseComponent(Nx-2,Ny-2,Nz-2,Dm->rank_info,const IntArray &PhaseID, int &VALUE, BlobIDArray &GlobalBlobID, Dm->Comm )
|
||||
Dm->Comm.barrier();
|
||||
|
||||
for (int k = 0; k < Nz; k++) {
|
||||
for (int j = 0; j < Ny; j++) {
|
||||
for (int i = 0; i < Nx; i++) {
|
||||
if (label(i, j, k) == 0) {
|
||||
id(i, j, k) = 0;
|
||||
} else {
|
||||
id(i, j, k) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MeasureObject();
|
||||
return n_connected_components;
|
||||
}
|
||||
|
||||
int Minkowski::MeasureConnectedPathway(double factor, const DoubleArray &Phi){
|
||||
/*
|
||||
int Minkowski::MeasureConnectedPathway(double factor, const DoubleArray &Phi) {
|
||||
/*
|
||||
* compute the connected pathway for object with LABEL in id field
|
||||
* compute the labels for connected components
|
||||
* compute the distance to the connected pathway
|
||||
*
|
||||
* THIS ALGORITHM ASSUMES THAT id() is populated with phase id to distinguish objects
|
||||
*/
|
||||
|
||||
char LABEL = 0;
|
||||
for (int k=0; k<Nz; k++){
|
||||
for (int j=0; j<Ny; j++){
|
||||
for (int i=0; i<Nx; i++){
|
||||
if (id(i,j,k) == LABEL){
|
||||
distance(i,j,k) = 1.0;
|
||||
}
|
||||
else
|
||||
distance(i,j,k) = -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract only the connected part of NWP
|
||||
double vF=0.0;
|
||||
n_connected_components = ComputeGlobalBlobIDs(Nx-2,Ny-2,Nz-2,Dm->rank_info,distance,distance,vF,vF,label,Dm->Comm);
|
||||
// int n_connected_components = ComputeGlobalPhaseComponent(Nx-2,Ny-2,Nz-2,Dm->rank_info,const IntArray &PhaseID, int &VALUE, BlobIDArray &GlobalBlobID, Dm->Comm )
|
||||
Dm->Comm.barrier();
|
||||
|
||||
|
||||
for (int k=0; k<Nz; k++){
|
||||
for (int j=0; j<Ny; j++){
|
||||
for (int i=0; i<Nx; i++){
|
||||
if ( label(i,j,k) == 0){
|
||||
id(i,j,k) = 0;
|
||||
}
|
||||
else{
|
||||
id(i,j,k) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MeasureObject(factor,Phi);
|
||||
return n_connected_components;
|
||||
char LABEL = 0;
|
||||
for (int k = 0; k < Nz; k++) {
|
||||
for (int j = 0; j < Ny; j++) {
|
||||
for (int i = 0; i < Nx; i++) {
|
||||
if (id(i, j, k) == LABEL) {
|
||||
distance(i, j, k) = 1.0;
|
||||
} else
|
||||
distance(i, j, k) = -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract only the connected part of NWP
|
||||
double vF = 0.0;
|
||||
n_connected_components =
|
||||
ComputeGlobalBlobIDs(Nx - 2, Ny - 2, Nz - 2, Dm->rank_info, distance,
|
||||
distance, vF, vF, label, Dm->Comm);
|
||||
// int n_connected_components = ComputeGlobalPhaseComponent(Nx-2,Ny-2,Nz-2,Dm->rank_info,const IntArray &PhaseID, int &VALUE, BlobIDArray &GlobalBlobID, Dm->Comm )
|
||||
Dm->Comm.barrier();
|
||||
|
||||
for (int k = 0; k < Nz; k++) {
|
||||
for (int j = 0; j < Ny; j++) {
|
||||
for (int i = 0; i < Nx; i++) {
|
||||
if (label(i, j, k) == 0) {
|
||||
id(i, j, k) = 0;
|
||||
} else {
|
||||
id(i, j, k) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MeasureObject(factor, Phi);
|
||||
return n_connected_components;
|
||||
}
|
||||
|
||||
|
||||
void Minkowski::PrintAll()
|
||||
{
|
||||
if (Dm->rank()==0){
|
||||
fprintf(LOGFILE,"%.5g %.5g %.5g %.5g\n",Vi_global, Ai_global, Ji_global, Xi_global); // minkowski measures
|
||||
fflush(LOGFILE);
|
||||
}
|
||||
void Minkowski::PrintAll() {
|
||||
if (Dm->rank() == 0) {
|
||||
fprintf(LOGFILE, "%.5g %.5g %.5g %.5g\n", Vi_global, Ai_global,
|
||||
Ji_global, Xi_global); // minkowski measures
|
||||
fflush(LOGFILE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Header file for two-phase averaging class
|
||||
#ifndef Minkowski_INC
|
||||
#define Minkowski_INC
|
||||
|
@ -18,59 +34,98 @@
|
|||
#include "IO/Reader.h"
|
||||
#include "IO/Writer.h"
|
||||
|
||||
/**
|
||||
* \class Minkowski
|
||||
*
|
||||
* @brief
|
||||
* The Minkowski class is constructed to analyze the geometric properties of structures based on the Minkowski functionals
|
||||
*
|
||||
*/
|
||||
|
||||
class Minkowski{
|
||||
//...........................................................................
|
||||
int kstart,kfinish;
|
||||
class Minkowski {
|
||||
//...........................................................................
|
||||
int kstart, kfinish;
|
||||
|
||||
double isovalue;
|
||||
double Volume;
|
||||
double isovalue;
|
||||
double Volume;
|
||||
|
||||
// CSV / text file where time history of averages is saved
|
||||
FILE *LOGFILE;
|
||||
// CSV / text file where time history of averages is saved
|
||||
FILE *LOGFILE;
|
||||
|
||||
public:
|
||||
//...........................................................................
|
||||
std::shared_ptr <Domain> Dm;
|
||||
Array <char> id;
|
||||
Array <int> label;
|
||||
Array <double> distance;
|
||||
//...........................................................................
|
||||
// Averaging variables
|
||||
//...........................................................................
|
||||
// local averages (to each MPI process)
|
||||
double Ai,Ji,Xi,Vi;
|
||||
// Global averages (all processes)
|
||||
double Ai_global,Ji_global,Xi_global,Vi_global;
|
||||
int n_connected_components;
|
||||
//...........................................................................
|
||||
int Nx,Ny,Nz;
|
||||
double V(){
|
||||
return Vi;
|
||||
}
|
||||
double A(){
|
||||
return Ai;
|
||||
}
|
||||
double H(){
|
||||
return Ji;
|
||||
}
|
||||
double X(){
|
||||
return Xi;
|
||||
}
|
||||
|
||||
//..........................................................................
|
||||
Minkowski(){};//NULL CONSTRUCTOR
|
||||
Minkowski(std::shared_ptr <Domain> Dm);
|
||||
~Minkowski();
|
||||
void MeasureObject();
|
||||
void MeasureObject(double factor, const DoubleArray &Phi);
|
||||
int MeasureConnectedPathway();
|
||||
int MeasureConnectedPathway(double factor, const DoubleArray &Phi);
|
||||
void ComputeScalar(const DoubleArray& Field, const double isovalue);
|
||||
//...........................................................................
|
||||
std::shared_ptr<Domain> Dm;
|
||||
Array<char> id;
|
||||
Array<int> label;
|
||||
Array<double> distance;
|
||||
//...........................................................................
|
||||
// Averaging variables
|
||||
//...........................................................................
|
||||
// local averages (to each MPI process)
|
||||
double Ai, Ji, Xi, Vi;
|
||||
// Global averages (all processes)
|
||||
double Ai_global, Ji_global, Xi_global, Vi_global;
|
||||
int n_connected_components;
|
||||
//...........................................................................
|
||||
int Nx, Ny, Nz;
|
||||
|
||||
void PrintAll();
|
||||
double V() { return Vi; }
|
||||
double A() { return Ai; }
|
||||
double H() { return Ji; }
|
||||
double X() { return Xi; }
|
||||
|
||||
//..........................................................................
|
||||
/**
|
||||
* \brief Null constructor
|
||||
*/
|
||||
Minkowski(){}; //NULL CONSTRUCTOR
|
||||
|
||||
/**
|
||||
* \brief Constructor based on an existing Domain
|
||||
* @param Dm - Domain structure
|
||||
*/
|
||||
Minkowski(std::shared_ptr<Domain> Dm);
|
||||
~Minkowski();
|
||||
|
||||
/**
|
||||
* \brief Compute scalar minkowski functionals
|
||||
* step 1. compute the distance to an object
|
||||
* step 2. construct dcel to represent the isosurface
|
||||
* step 3. compute the scalar Minkowski functionals
|
||||
* THIS ALGORITHM ASSUMES THAT id() is populated with phase id to distinguish objects
|
||||
* 0 - labels the object
|
||||
* 1 - labels everything else
|
||||
*/
|
||||
void MeasureObject();
|
||||
|
||||
void MeasureObject(double factor, const DoubleArray &Phi);
|
||||
|
||||
/**
|
||||
* \details Compute scalar minkowski functionals for connected part of a structure
|
||||
* step 1. compute connected components and extract largest region by volume
|
||||
* step 2. compute the distance to the connected part of the structure
|
||||
* step 3. construct dcel to represent the isosurface
|
||||
* step 4. compute the scalar Minkowski functionals
|
||||
* THIS ALGORITHM ASSUMES THAT id() is populated with phase id to distinguish objects
|
||||
* 0 - labels the object
|
||||
* 1 - labels everything else
|
||||
*/
|
||||
int MeasureConnectedPathway();
|
||||
|
||||
int MeasureConnectedPathway(double factor, const DoubleArray &Phi);
|
||||
|
||||
/**
|
||||
* \brief Compute scalar minkowski functionals
|
||||
* \details Construct an isosurface and return the geometric invariants based on the triangulated list
|
||||
* @param isovalue - threshold value to use to determine iso-surface
|
||||
* @param Field - DoubleArray containing the field to threshold
|
||||
*/
|
||||
void ComputeScalar(const DoubleArray &Field, const double isovalue);
|
||||
|
||||
/**
|
||||
* \brief print the scalar invariants
|
||||
*/
|
||||
void PrintAll();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef PointList_INC
|
||||
#define PointList_INC
|
||||
|
||||
|
@ -5,25 +21,49 @@
|
|||
|
||||
struct LBPM_Point {
|
||||
LBPM_Point() : x(0.0), y(0.0), z(0.0) {}
|
||||
LBPM_Point(double xv,double yv,double zv) : x(xv), y(yv), z(zv) {}
|
||||
double x,y,z;
|
||||
LBPM_Point(double xv, double yv, double zv) : x(xv), y(yv), z(zv) {}
|
||||
double x, y, z;
|
||||
};
|
||||
typedef LBPM_Point Point;
|
||||
|
||||
inline Point operator+(const Point &A,const Point &B) {return Point(A.x+B.x,A.y+B.y,A.z+B.z);}
|
||||
inline Point operator-(const Point &A,const Point &B) {return Point(A.x-B.x,A.y-B.y,A.z-B.z);}
|
||||
inline Point operator*(const Point &A,double v) {return Point(A.x*v,A.y*v,A.z*v);}
|
||||
inline Point operator*(double v,const Point &A) {return Point(A.x*v,A.y*v,A.z*v);}
|
||||
inline Point operator/(const Point &A,double v) {return Point(A.x/v,A.y/v,A.z/v);}
|
||||
inline Point operator-(const Point &A) {return Point(-A.x,-A.y,-A.z);}
|
||||
inline Point operator+(const Point &A, const Point &B) {
|
||||
return Point(A.x + B.x, A.y + B.y, A.z + B.z);
|
||||
}
|
||||
inline Point operator-(const Point &A, const Point &B) {
|
||||
return Point(A.x - B.x, A.y - B.y, A.z - B.z);
|
||||
}
|
||||
inline Point operator*(const Point &A, double v) {
|
||||
return Point(A.x * v, A.y * v, A.z * v);
|
||||
}
|
||||
inline Point operator*(double v, const Point &A) {
|
||||
return Point(A.x * v, A.y * v, A.z * v);
|
||||
}
|
||||
inline Point operator/(const Point &A, double v) {
|
||||
return Point(A.x / v, A.y / v, A.z / v);
|
||||
}
|
||||
inline Point operator-(const Point &A) { return Point(-A.x, -A.y, -A.z); }
|
||||
|
||||
inline bool operator==(const Point &A,const Point &B) {return (A.x==B.x && A.y==B.y && A.z==B.z);}
|
||||
inline bool operator!=(const Point &A,const Point &B) {return (A.x!=B.x || A.y!=B.y || A.z!=B.z);}
|
||||
inline bool operator==(const Point &A, const Point &B) {
|
||||
return (A.x == B.x && A.y == B.y && A.z == B.z);
|
||||
}
|
||||
inline bool operator!=(const Point &A, const Point &B) {
|
||||
return (A.x != B.x || A.y != B.y || A.z != B.z);
|
||||
}
|
||||
|
||||
inline double Norm(const Point &A) {return sqrt(A.x*A.x+A.y*A.y+A.z*A.z);}
|
||||
inline Point Cross(const Point &A,const Point &B) {return Point(A.y*B.z-A.z*B.y,B.x*A.z-A.x*B.z,A.x*B.y-A.y*B.x);}
|
||||
inline double Dot(const Point &A,const Point &B) {return (A.x*B.x+A.y*B.y+A.z*B.z);}
|
||||
inline double Distance(const Point &A,const Point &B) {return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z));}
|
||||
inline double Norm(const Point &A) {
|
||||
return sqrt(A.x * A.x + A.y * A.y + A.z * A.z);
|
||||
}
|
||||
inline Point Cross(const Point &A, const Point &B) {
|
||||
return Point(A.y * B.z - A.z * B.y, B.x * A.z - A.x * B.z,
|
||||
A.x * B.y - A.y * B.x);
|
||||
}
|
||||
inline double Dot(const Point &A, const Point &B) {
|
||||
return (A.x * B.x + A.y * B.y + A.z * B.z);
|
||||
}
|
||||
inline double Distance(const Point &A, const Point &B) {
|
||||
return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y) +
|
||||
(A.z - B.z) * (A.z - B.z));
|
||||
}
|
||||
|
||||
/*
|
||||
class PointList{
|
||||
|
@ -88,25 +128,38 @@ PointList::~PointList()
|
|||
delete data;
|
||||
}
|
||||
*/
|
||||
template <class T>
|
||||
class DTList {
|
||||
template <class T> class DTList {
|
||||
public:
|
||||
DTList() : Data(0), length(0), refCount(new size_t(1)), outOfRange() {}
|
||||
DTList(const DTList<T> &A) : Data(A.Data), length(A.length), refCount(A.refCount), outOfRange() {++(*refCount);}
|
||||
protected:
|
||||
DTList(size_t len) : Data(len<=0 ? 0 : new T[len]), length(len<=0 ? 0 : len), refCount(new size_t(1)), outOfRange() {}
|
||||
public:
|
||||
|
||||
virtual ~DTList() {
|
||||
--(*refCount);
|
||||
if (*refCount==0) {delete [] Data; delete refCount;}
|
||||
Data = 0; refCount = 0; length=0;
|
||||
DTList(const DTList<T> &A)
|
||||
: Data(A.Data), length(A.length), refCount(A.refCount), outOfRange() {
|
||||
++(*refCount);
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
DTList(size_t len)
|
||||
: Data(len <= 0 ? 0 : new T[len]), length(len <= 0 ? 0 : len),
|
||||
refCount(new size_t(1)), outOfRange() {}
|
||||
|
||||
public:
|
||||
virtual ~DTList() {
|
||||
--(*refCount);
|
||||
if (*refCount == 0) {
|
||||
delete[] Data;
|
||||
delete refCount;
|
||||
}
|
||||
Data = 0;
|
||||
refCount = 0;
|
||||
length = 0;
|
||||
}
|
||||
|
||||
DTList<T> &operator=(const DTList<T> &A) {
|
||||
if (A.refCount!=refCount) { // Otherwise doing A=A.
|
||||
if (A.refCount != refCount) { // Otherwise doing A=A.
|
||||
--(*refCount);
|
||||
if (*refCount==0) {delete [] Data; delete refCount;}
|
||||
if (*refCount == 0) {
|
||||
delete[] Data;
|
||||
delete refCount;
|
||||
}
|
||||
refCount = A.refCount;
|
||||
++(*refCount);
|
||||
length = A.length;
|
||||
|
@ -114,62 +167,69 @@ public:
|
|||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t MemoryUsed(void) const {return length*sizeof(T);}
|
||||
|
||||
const T *Pointer(void) const {return Data;}
|
||||
|
||||
size_t IsEmpty(void) const {return (Data==0);}
|
||||
size_t Length(void) const {return length;}
|
||||
|
||||
const T operator()(size_t i) const {return Data[i];}
|
||||
|
||||
size_t MemoryUsed(void) const { return length * sizeof(T); }
|
||||
|
||||
const T *Pointer(void) const { return Data; }
|
||||
|
||||
size_t IsEmpty(void) const { return (Data == 0); }
|
||||
size_t Length(void) const { return length; }
|
||||
|
||||
const T operator()(size_t i) const { return Data[i]; }
|
||||
|
||||
protected:
|
||||
T *Data;
|
||||
size_t length;
|
||||
size_t *refCount;
|
||||
|
||||
|
||||
// Should be static.
|
||||
T outOfRange;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class DTMutableList : public DTList<T> {
|
||||
template <class T> class DTMutableList : public DTList<T> {
|
||||
public:
|
||||
DTMutableList() : DTList<T>() {}
|
||||
DTMutableList(size_t len) : DTList<T>(len) {}
|
||||
DTMutableList(const DTMutableList<T> &A) : DTList<T>(A) {}
|
||||
|
||||
DTMutableList<T> &operator=(const DTMutableList<T> &A) {DTList<T>::operator=(A); return *this;}
|
||||
|
||||
T *Pointer(void) {return DTList<T>::Data;}
|
||||
const T *Pointer(void) const {return DTList<T>::Data;}
|
||||
T &operator()(size_t i) {return DTList<T>::Data[i];}
|
||||
T operator()(size_t i) const {return DTList<T>::Data[i];}
|
||||
|
||||
DTMutableList<T> &operator=(T v) {for (size_t i=0;i<DTList<T>::length;i++) DTList<T>::Data[i] = v; return *this;}
|
||||
|
||||
DTMutableList<T> &operator=(const DTMutableList<T> &A) {
|
||||
DTList<T>::operator=(A);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T *Pointer(void) { return DTList<T>::Data; }
|
||||
const T *Pointer(void) const { return DTList<T>::Data; }
|
||||
T &operator()(size_t i) { return DTList<T>::Data[i]; }
|
||||
T operator()(size_t i) const { return DTList<T>::Data[i]; }
|
||||
|
||||
DTMutableList<T> &operator=(T v) {
|
||||
for (size_t i = 0; i < DTList<T>::length; i++)
|
||||
DTList<T>::Data[i] = v;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> DTMutableList<T> TruncateSize(const DTList<T> &A,size_t length)
|
||||
{
|
||||
if (length>A.Length()) length = A.Length();
|
||||
template <class T>
|
||||
DTMutableList<T> TruncateSize(const DTList<T> &A, size_t length) {
|
||||
if (length > A.Length())
|
||||
length = A.Length();
|
||||
DTMutableList<T> toReturn(length);
|
||||
const T *fromP = A.Pointer();
|
||||
T *toP = toReturn.Pointer();
|
||||
for (size_t i=0;i<length;i++) toP[i] = fromP[i];
|
||||
for (size_t i = 0; i < length; i++)
|
||||
toP[i] = fromP[i];
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
template <class T> DTMutableList<T> IncreaseSize(const DTList<T> &A,size_t addLength)
|
||||
{
|
||||
DTMutableList<T> toReturn(A.Length()+(addLength>=0 ? addLength : 0));
|
||||
template <class T>
|
||||
DTMutableList<T> IncreaseSize(const DTList<T> &A, size_t addLength) {
|
||||
DTMutableList<T> toReturn(A.Length() + (addLength >= 0 ? addLength : 0));
|
||||
size_t len = A.Length();
|
||||
const T *fromP = A.Pointer();
|
||||
T *toP = toReturn.Pointer();
|
||||
for (size_t i=0;i<len;i++) toP[i] = fromP[i];
|
||||
for (size_t i = 0; i < len; i++)
|
||||
toP[i] = fromP[i];
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -17,48 +17,48 @@
|
|||
#include "IO/Reader.h"
|
||||
#include "IO/Writer.h"
|
||||
|
||||
|
||||
class phase{
|
||||
class phase {
|
||||
public:
|
||||
int Nc;
|
||||
double p;
|
||||
double M,Px,Py,Pz,K;
|
||||
double V,A,H,X;
|
||||
void reset(){
|
||||
p=M=Px=Py=Pz=K=0.0;
|
||||
V=A=H=X=0.0;
|
||||
Nc=1;
|
||||
}
|
||||
int Nc;
|
||||
double p;
|
||||
double M, Px, Py, Pz, K, visc;
|
||||
double V, A, H, X;
|
||||
void reset() {
|
||||
p = M = Px = Py = Pz = K = 0.0;
|
||||
visc = 0.0;
|
||||
V = A = H = X = 0.0;
|
||||
Nc = 1;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class interface{
|
||||
class interface {
|
||||
public:
|
||||
int Nc;
|
||||
double M,Px,Py,Pz,K;
|
||||
double Mw,Mn,Pnx,Pny,Pnz,Pwx,Pwy,Pwz,Kw,Kn;
|
||||
double V,A,H,X;
|
||||
void reset(){
|
||||
Nc = 0;
|
||||
M=Px=Py=Pz=K=0.0;
|
||||
V=A=H=X=0.0;
|
||||
Mw=Mn=Pnx=Pny=Pnz=Pwx=Pwy=Pwz=Kw=Kn=0.0;
|
||||
}
|
||||
int Nc;
|
||||
double M, Px, Py, Pz, K;
|
||||
double Mw, Mn, Pnx, Pny, Pnz, Pwx, Pwy, Pwz, Kw, Kn;
|
||||
double V, A, H, X;
|
||||
void reset() {
|
||||
Nc = 0;
|
||||
M = Px = Py = Pz = K = 0.0;
|
||||
V = A = H = X = 0.0;
|
||||
Mw = Mn = Pnx = Pny = Pnz = Pwx = Pwy = Pwz = Kw = Kn = 0.0;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class SubPhase{
|
||||
class SubPhase {
|
||||
public:
|
||||
std::shared_ptr <Domain> Dm;
|
||||
double Volume;
|
||||
// input variables
|
||||
double rho_n, rho_w;
|
||||
double nu_n, nu_w;
|
||||
double gamma_wn, beta;
|
||||
double Fx, Fy, Fz;
|
||||
/*
|
||||
std::shared_ptr<Domain> Dm;
|
||||
double Volume;
|
||||
// input variables
|
||||
double rho_n, rho_w;
|
||||
double nu_n, nu_w;
|
||||
double gamma_wn, beta;
|
||||
double Fx, Fy, Fz;
|
||||
/*
|
||||
* indices
|
||||
* w - water phase
|
||||
* n - not water phase
|
||||
|
@ -67,50 +67,55 @@ public:
|
|||
* i - interface region
|
||||
* b - bulk (total)
|
||||
*/
|
||||
// local entities
|
||||
phase wc,wd,wb,nc,nd,nb,solid;
|
||||
interface iwn,iwnc;
|
||||
|
||||
// global entities
|
||||
phase gwc,gwd,gwb,gnc,gnd,gnb,gsolid;
|
||||
interface giwn,giwnc;
|
||||
/* fluid-solid wetting interaction */
|
||||
double total_wetting_interaction, count_wetting_interaction;
|
||||
double total_wetting_interaction_global, count_wetting_interaction_global;
|
||||
|
||||
//...........................................................................
|
||||
int Nx,Ny,Nz;
|
||||
IntArray PhaseID; // Phase ID array (solid=0, non-wetting=1, wetting=2)
|
||||
BlobIDArray Label_WP; // Wetting phase label
|
||||
BlobIDArray Label_NWP; // Non-wetting phase label index (0:nblobs-1)
|
||||
std::vector<BlobIDType> Label_NWP_map; // Non-wetting phase label for each index
|
||||
DoubleArray Rho_n; // density field
|
||||
DoubleArray Rho_w; // density field
|
||||
DoubleArray Phi; // phase indicator field
|
||||
DoubleArray DelPhi; // Magnitude of Gradient of the phase indicator field
|
||||
DoubleArray Pressure; // pressure field
|
||||
DoubleArray Vel_x; // velocity field
|
||||
DoubleArray Vel_y;
|
||||
DoubleArray Vel_z;
|
||||
DoubleArray SDs;
|
||||
// local entities
|
||||
phase wc, wd, wb, nc, nd, nb, solid;
|
||||
interface iwn, iwnc;
|
||||
interface ifs;
|
||||
|
||||
std::shared_ptr<Minkowski> morph_w;
|
||||
std::shared_ptr<Minkowski> morph_n;
|
||||
std::shared_ptr<Minkowski> morph_i;
|
||||
// global entities
|
||||
phase gwc, gwd, gwb, gnc, gnd, gnb, gsolid;
|
||||
interface giwn, giwnc;
|
||||
interface gifs;
|
||||
/* fluid-solid wetting interaction */
|
||||
double total_wetting_interaction, count_wetting_interaction;
|
||||
double total_wetting_interaction_global, count_wetting_interaction_global;
|
||||
|
||||
SubPhase(std::shared_ptr <Domain> Dm);
|
||||
~SubPhase();
|
||||
|
||||
void SetParams(double rhoA, double rhoB, double tauA, double tauB, double force_x, double force_y, double force_z, double alpha, double beta);
|
||||
void Basic();
|
||||
void Full();
|
||||
void Write(int time);
|
||||
void AggregateLabels( const std::string& filename );
|
||||
//...........................................................................
|
||||
int Nx, Ny, Nz;
|
||||
IntArray PhaseID; // Phase ID array (solid=0, non-wetting=1, wetting=2)
|
||||
BlobIDArray Label_WP; // Wetting phase label
|
||||
BlobIDArray Label_NWP; // Non-wetting phase label index (0:nblobs-1)
|
||||
std::vector<BlobIDType>
|
||||
Label_NWP_map; // Non-wetting phase label for each index
|
||||
DoubleArray Rho_n; // density field
|
||||
DoubleArray Rho_w; // density field
|
||||
DoubleArray Phi; // phase indicator field
|
||||
DoubleArray DelPhi; // Magnitude of Gradient of the phase indicator field
|
||||
DoubleArray Pressure; // pressure field
|
||||
DoubleArray Vel_x; // velocity field
|
||||
DoubleArray Vel_y;
|
||||
DoubleArray Vel_z;
|
||||
DoubleArray Dissipation;
|
||||
DoubleArray SDs;
|
||||
|
||||
std::shared_ptr<Minkowski> morph_w;
|
||||
std::shared_ptr<Minkowski> morph_n;
|
||||
std::shared_ptr<Minkowski> morph_i;
|
||||
|
||||
SubPhase(std::shared_ptr<Domain> Dm);
|
||||
~SubPhase();
|
||||
|
||||
void SetParams(double rhoA, double rhoB, double tauA, double tauB,
|
||||
double force_x, double force_y, double force_z, double alpha,
|
||||
double beta);
|
||||
void Basic();
|
||||
void Full();
|
||||
void Write(int time);
|
||||
void AggregateLabels(const std::string &filename);
|
||||
|
||||
private:
|
||||
FILE *TIMELOG;
|
||||
FILE *SUBPHASE;
|
||||
FILE *TIMELOG;
|
||||
FILE *SUBPHASE;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Header file for two-phase averaging class
|
||||
#ifndef TwoPhase_INC
|
||||
#define TwoPhase_INC
|
||||
|
@ -17,171 +33,170 @@
|
|||
#include "IO/Reader.h"
|
||||
#include "IO/Writer.h"
|
||||
|
||||
class TwoPhase {
|
||||
|
||||
class TwoPhase{
|
||||
//...........................................................................
|
||||
int n_nw_pts, n_ns_pts, n_ws_pts, n_nws_pts, n_local_sol_pts,
|
||||
n_local_nws_pts;
|
||||
int n_nw_tris, n_ns_tris, n_ws_tris, n_nws_seg, n_local_sol_tris;
|
||||
//...........................................................................
|
||||
int nc;
|
||||
int kstart, kfinish;
|
||||
|
||||
//...........................................................................
|
||||
int n_nw_pts,n_ns_pts,n_ws_pts,n_nws_pts,n_local_sol_pts,n_local_nws_pts;
|
||||
int n_nw_tris,n_ns_tris,n_ws_tris,n_nws_seg,n_local_sol_tris;
|
||||
//...........................................................................
|
||||
int nc;
|
||||
int kstart,kfinish;
|
||||
double fluid_isovalue, solid_isovalue;
|
||||
double Volume;
|
||||
// initialize lists for vertices for surfaces, common line
|
||||
DTMutableList<Point> nw_pts;
|
||||
DTMutableList<Point> ns_pts;
|
||||
DTMutableList<Point> ws_pts;
|
||||
DTMutableList<Point> nws_pts;
|
||||
DTMutableList<Point> local_sol_pts;
|
||||
DTMutableList<Point> local_nws_pts;
|
||||
DTMutableList<Point> tmp;
|
||||
|
||||
double fluid_isovalue, solid_isovalue;
|
||||
double Volume;
|
||||
// initialize lists for vertices for surfaces, common line
|
||||
DTMutableList<Point> nw_pts;
|
||||
DTMutableList<Point> ns_pts;
|
||||
DTMutableList<Point> ws_pts;
|
||||
DTMutableList<Point> nws_pts;
|
||||
DTMutableList<Point> local_sol_pts;
|
||||
DTMutableList<Point> local_nws_pts;
|
||||
DTMutableList<Point> tmp;
|
||||
// initialize triangle lists for surfaces
|
||||
IntArray nw_tris;
|
||||
IntArray ns_tris;
|
||||
IntArray ws_tris;
|
||||
IntArray nws_seg;
|
||||
IntArray local_sol_tris;
|
||||
|
||||
// initialize triangle lists for surfaces
|
||||
IntArray nw_tris;
|
||||
IntArray ns_tris;
|
||||
IntArray ws_tris;
|
||||
IntArray nws_seg;
|
||||
IntArray local_sol_tris;
|
||||
// Temporary storage arrays
|
||||
DoubleArray CubeValues;
|
||||
DoubleArray Values;
|
||||
DoubleArray DistanceValues;
|
||||
DoubleArray KGwns_values;
|
||||
DoubleArray KNwns_values;
|
||||
DoubleArray InterfaceSpeed;
|
||||
DoubleArray NormalVector;
|
||||
|
||||
// Temporary storage arrays
|
||||
DoubleArray CubeValues;
|
||||
DoubleArray Values;
|
||||
DoubleArray DistanceValues;
|
||||
DoubleArray KGwns_values;
|
||||
DoubleArray KNwns_values;
|
||||
DoubleArray InterfaceSpeed;
|
||||
DoubleArray NormalVector;
|
||||
DoubleArray RecvBuffer;
|
||||
|
||||
DoubleArray RecvBuffer;
|
||||
char *TempID;
|
||||
|
||||
char *TempID;
|
||||
|
||||
// CSV / text file where time history of averages is saved
|
||||
FILE *TIMELOG;
|
||||
FILE *NWPLOG;
|
||||
FILE *WPLOG;
|
||||
// CSV / text file where time history of averages is saved
|
||||
FILE *TIMELOG;
|
||||
FILE *NWPLOG;
|
||||
FILE *WPLOG;
|
||||
|
||||
public:
|
||||
//...........................................................................
|
||||
std::shared_ptr <Domain> Dm;
|
||||
int NumberComponents_WP,NumberComponents_NWP;
|
||||
//...........................................................................
|
||||
// Averaging variables
|
||||
//...........................................................................
|
||||
// local averages (to each MPI process)
|
||||
double trimdist; // pixel distance to trim surface for specified averages
|
||||
double porosity,poreVol;
|
||||
double awn,ans,aws,lwns;
|
||||
double wp_volume,nwp_volume;
|
||||
double As, dummy;
|
||||
double vol_w, vol_n; // volumes the exclude the interfacial region
|
||||
double sat_w, sat_w_previous;
|
||||
double pan,paw; // local phase averaged pressure
|
||||
// Global averages (all processes)
|
||||
double pan_global,paw_global; // local phase averaged pressure
|
||||
double vol_w_global, vol_n_global; // volumes the exclude the interfacial region
|
||||
double awn_global,ans_global,aws_global;
|
||||
double lwns_global;
|
||||
double efawns,efawns_global; // averaged contact angle
|
||||
double euler,Kn,Jn,An;
|
||||
double euler_global,Kn_global,Jn_global,An_global;
|
||||
|
||||
double rho_n, rho_w;
|
||||
double nu_n, nu_w;
|
||||
double gamma_wn;
|
||||
double Fx, Fy, Fz;
|
||||
//...........................................................................
|
||||
std::shared_ptr<Domain> Dm;
|
||||
int NumberComponents_WP, NumberComponents_NWP;
|
||||
//...........................................................................
|
||||
// Averaging variables
|
||||
//...........................................................................
|
||||
// local averages (to each MPI process)
|
||||
double trimdist; // pixel distance to trim surface for specified averages
|
||||
double porosity, poreVol;
|
||||
double awn, ans, aws, lwns;
|
||||
double wp_volume, nwp_volume;
|
||||
double As, dummy;
|
||||
double vol_w, vol_n; // volumes the exclude the interfacial region
|
||||
double sat_w, sat_w_previous;
|
||||
double pan, paw; // local phase averaged pressure
|
||||
// Global averages (all processes)
|
||||
double pan_global, paw_global; // local phase averaged pressure
|
||||
double vol_w_global,
|
||||
vol_n_global; // volumes the exclude the interfacial region
|
||||
double awn_global, ans_global, aws_global;
|
||||
double lwns_global;
|
||||
double efawns, efawns_global; // averaged contact angle
|
||||
double euler, Kn, Jn, An;
|
||||
double euler_global, Kn_global, Jn_global, An_global;
|
||||
|
||||
double Jwn,Jwn_global; // average mean curavture - wn interface
|
||||
double Kwn,Kwn_global; // average Gaussian curavture - wn interface
|
||||
double KNwns,KNwns_global; // wns common curve normal curavture
|
||||
double KGwns,KGwns_global; // wns common curve geodesic curavture
|
||||
double trawn,trawn_global; // trimmed interfacial area
|
||||
double trJwn,trJwn_global; // trimmed interfacial area
|
||||
double trRwn,trRwn_global; // trimmed interfacial area
|
||||
double nwp_volume_global; // volume for the non-wetting phase
|
||||
double wp_volume_global; // volume for the wetting phase
|
||||
double As_global;
|
||||
double wwndnw, wwndnw_global;
|
||||
double wwnsdnwn, wwnsdnwn_global;
|
||||
double Jwnwwndnw, Jwnwwndnw_global;
|
||||
double dEs,dAwn,dAns; // Global surface energy (calculated by rank=0)
|
||||
DoubleArray van;
|
||||
DoubleArray vaw;
|
||||
DoubleArray vawn;
|
||||
DoubleArray vawns;
|
||||
DoubleArray Gwn;
|
||||
DoubleArray Gns;
|
||||
DoubleArray Gws;
|
||||
DoubleArray van_global;
|
||||
DoubleArray vaw_global;
|
||||
DoubleArray vawn_global;
|
||||
DoubleArray vawns_global;
|
||||
DoubleArray Gwn_global;
|
||||
DoubleArray Gns_global;
|
||||
DoubleArray Gws_global;
|
||||
//...........................................................................
|
||||
//...........................................................................
|
||||
int Nx,Ny,Nz;
|
||||
IntArray PhaseID; // Phase ID array (solid=0, non-wetting=1, wetting=2)
|
||||
BlobIDArray Label_WP; // Wetting phase label
|
||||
BlobIDArray Label_NWP; // Non-wetting phase label index (0:nblobs-1)
|
||||
std::vector<BlobIDType> Label_NWP_map; // Non-wetting phase label for each index
|
||||
DoubleArray SDn;
|
||||
DoubleArray SDs;
|
||||
DoubleArray Phase;
|
||||
DoubleArray Press;
|
||||
DoubleArray dPdt;
|
||||
DoubleArray MeanCurvature;
|
||||
DoubleArray GaussCurvature;
|
||||
DoubleArray SDs_x; // Gradient of the signed distance
|
||||
DoubleArray SDs_y;
|
||||
DoubleArray SDs_z;
|
||||
DoubleArray SDn_x; // Gradient of the signed distance
|
||||
DoubleArray SDn_y;
|
||||
DoubleArray SDn_z;
|
||||
DoubleArray DelPhi; // Magnitude of Gradient of the phase indicator field
|
||||
DoubleArray Phase_tplus;
|
||||
DoubleArray Phase_tminus;
|
||||
DoubleArray Vel_x; // Velocity
|
||||
DoubleArray Vel_y;
|
||||
DoubleArray Vel_z;
|
||||
DoubleArray PhaseDistance;
|
||||
double rho_n, rho_w;
|
||||
double nu_n, nu_w;
|
||||
double gamma_wn;
|
||||
double Fx, Fy, Fz;
|
||||
|
||||
std::shared_ptr<Minkowski> wet_morph;
|
||||
std::shared_ptr<Minkowski> nonwet_morph;
|
||||
|
||||
// Container for averages;
|
||||
DoubleArray ComponentAverages_WP;
|
||||
DoubleArray ComponentAverages_NWP;
|
||||
//...........................................................................
|
||||
TwoPhase(std::shared_ptr <Domain> Dm);
|
||||
~TwoPhase();
|
||||
void Initialize();
|
||||
// void SetupCubes(Domain &Dm);
|
||||
void UpdateMeshValues();
|
||||
void UpdateSolid();
|
||||
void ComputeDelPhi();
|
||||
void ColorToSignedDistance(double Beta, DoubleArray &ColorData, DoubleArray &DistData);
|
||||
void ComputeLocal();
|
||||
void AssignComponentLabels();
|
||||
void ComponentAverages();
|
||||
void Reduce();
|
||||
void NonDimensionalize(double D, double viscosity, double IFT);
|
||||
void PrintAll(int timestep);
|
||||
int GetCubeLabel(int i, int j, int k, IntArray &BlobLabel);
|
||||
void SortBlobs();
|
||||
void PrintComponents(int timestep);
|
||||
void SetParams(double rhoA, double rhoB, double tauA, double tauB, double force_x, double force_y, double force_z, double alpha);
|
||||
double Volume_w(){
|
||||
return wp_volume_global;
|
||||
}
|
||||
double Volume_n(){
|
||||
return nwp_volume_global;
|
||||
}
|
||||
double Jwn, Jwn_global; // average mean curavture - wn interface
|
||||
double Kwn, Kwn_global; // average Gaussian curavture - wn interface
|
||||
double KNwns, KNwns_global; // wns common curve normal curavture
|
||||
double KGwns, KGwns_global; // wns common curve geodesic curavture
|
||||
double trawn, trawn_global; // trimmed interfacial area
|
||||
double trJwn, trJwn_global; // trimmed interfacial area
|
||||
double trRwn, trRwn_global; // trimmed interfacial area
|
||||
double nwp_volume_global; // volume for the non-wetting phase
|
||||
double wp_volume_global; // volume for the wetting phase
|
||||
double As_global;
|
||||
double wwndnw, wwndnw_global;
|
||||
double wwnsdnwn, wwnsdnwn_global;
|
||||
double Jwnwwndnw, Jwnwwndnw_global;
|
||||
double dEs, dAwn, dAns; // Global surface energy (calculated by rank=0)
|
||||
DoubleArray van;
|
||||
DoubleArray vaw;
|
||||
DoubleArray vawn;
|
||||
DoubleArray vawns;
|
||||
DoubleArray Gwn;
|
||||
DoubleArray Gns;
|
||||
DoubleArray Gws;
|
||||
DoubleArray van_global;
|
||||
DoubleArray vaw_global;
|
||||
DoubleArray vawn_global;
|
||||
DoubleArray vawns_global;
|
||||
DoubleArray Gwn_global;
|
||||
DoubleArray Gns_global;
|
||||
DoubleArray Gws_global;
|
||||
//...........................................................................
|
||||
//...........................................................................
|
||||
int Nx, Ny, Nz;
|
||||
IntArray PhaseID; // Phase ID array (solid=0, non-wetting=1, wetting=2)
|
||||
BlobIDArray Label_WP; // Wetting phase label
|
||||
BlobIDArray Label_NWP; // Non-wetting phase label index (0:nblobs-1)
|
||||
std::vector<BlobIDType>
|
||||
Label_NWP_map; // Non-wetting phase label for each index
|
||||
DoubleArray SDn;
|
||||
DoubleArray SDs;
|
||||
DoubleArray Phase;
|
||||
DoubleArray Press;
|
||||
DoubleArray dPdt;
|
||||
DoubleArray MeanCurvature;
|
||||
DoubleArray GaussCurvature;
|
||||
DoubleArray SDs_x; // Gradient of the signed distance
|
||||
DoubleArray SDs_y;
|
||||
DoubleArray SDs_z;
|
||||
DoubleArray SDn_x; // Gradient of the signed distance
|
||||
DoubleArray SDn_y;
|
||||
DoubleArray SDn_z;
|
||||
DoubleArray DelPhi; // Magnitude of Gradient of the phase indicator field
|
||||
DoubleArray Phase_tplus;
|
||||
DoubleArray Phase_tminus;
|
||||
DoubleArray Vel_x; // Velocity
|
||||
DoubleArray Vel_y;
|
||||
DoubleArray Vel_z;
|
||||
DoubleArray PhaseDistance;
|
||||
|
||||
std::shared_ptr<Minkowski> wet_morph;
|
||||
std::shared_ptr<Minkowski> nonwet_morph;
|
||||
|
||||
// Container for averages;
|
||||
DoubleArray ComponentAverages_WP;
|
||||
DoubleArray ComponentAverages_NWP;
|
||||
//...........................................................................
|
||||
TwoPhase(std::shared_ptr<Domain> Dm);
|
||||
~TwoPhase();
|
||||
void Initialize();
|
||||
// void SetupCubes(Domain &Dm);
|
||||
void UpdateMeshValues();
|
||||
void UpdateSolid();
|
||||
void ComputeDelPhi();
|
||||
void ColorToSignedDistance(double Beta, DoubleArray &ColorData,
|
||||
DoubleArray &DistData);
|
||||
void ComputeLocal();
|
||||
void AssignComponentLabels();
|
||||
void ComponentAverages();
|
||||
void Reduce();
|
||||
void NonDimensionalize(double D, double viscosity, double IFT);
|
||||
void PrintAll(int timestep);
|
||||
int GetCubeLabel(int i, int j, int k, IntArray &BlobLabel);
|
||||
void SortBlobs();
|
||||
void PrintComponents(int timestep);
|
||||
void SetParams(double rhoA, double rhoB, double tauA, double tauB,
|
||||
double force_x, double force_y, double force_z,
|
||||
double alpha);
|
||||
double Volume_w() { return wp_volume_global; }
|
||||
double Volume_n() { return nwp_volume_global; }
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef Analysis_H_INC
|
||||
#define Analysis_H_INC
|
||||
|
||||
|
@ -8,12 +24,10 @@
|
|||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
// Define types to use for blob ids
|
||||
typedef int32_t BlobIDType;
|
||||
typedef Array<BlobIDType> BlobIDArray;
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Compute the blob
|
||||
* @details Compute the blob (F>vf|S>vs) starting from (i,j,k) - oil blob
|
||||
|
@ -22,12 +36,13 @@ typedef Array<BlobIDType> BlobIDArray;
|
|||
* @param[in] SignDist SignDist
|
||||
* @param[in] vF vF
|
||||
* @param[in] vS vS
|
||||
* @param[in] S S
|
||||
* @param[out] LocalBlobID The ids of the blobs
|
||||
* @param[in] periodic Optional value
|
||||
* @return Returns the number of blobs
|
||||
*/
|
||||
int ComputeLocalBlobIDs( const DoubleArray& Phase, const DoubleArray& SignDist,
|
||||
double vF, double vS, BlobIDArray& LocalBlobID, bool periodic=true );
|
||||
int ComputeLocalBlobIDs(const DoubleArray &Phase, const DoubleArray &SignDist,
|
||||
double vF, double vS, BlobIDArray &LocalBlobID,
|
||||
bool periodic = true);
|
||||
|
||||
/*!
|
||||
* @brief Compute blob of an arbitrary phase
|
||||
|
@ -38,8 +53,8 @@ int ComputeLocalBlobIDs( const DoubleArray& Phase, const DoubleArray& SignDist,
|
|||
* @param[out] ComponentLabel
|
||||
* @param[in] periodic
|
||||
*/
|
||||
int ComputeLocalPhaseComponent( const IntArray &PhaseID, int &VALUE, IntArray &ComponentLabel, bool periodic );
|
||||
|
||||
int ComputeLocalPhaseComponent(const IntArray &PhaseID, int &VALUE,
|
||||
IntArray &ComponentLabel, bool periodic);
|
||||
|
||||
/*!
|
||||
* @brief Compute the blob
|
||||
|
@ -48,18 +63,20 @@ int ComputeLocalPhaseComponent( const IntArray &PhaseID, int &VALUE, IntArray &C
|
|||
* @param[in] nx Number of elements in the x-direction
|
||||
* @param[in] ny Number of elements in the y-direction
|
||||
* @param[in] nz Number of elements in the z-direction
|
||||
* @param[in] rank_info MPI communication info
|
||||
* @param[in] Phase Phase
|
||||
* @param[in] SignDist SignDist
|
||||
* @param[in] vF vF
|
||||
* @param[in] vS vS
|
||||
* @param[in] S S
|
||||
* @param[out] LocalBlobID The ids of the blobs
|
||||
* @param[out] GlobalBlobID The ids of the blobs
|
||||
* @param[in] comm MPI communicator
|
||||
* @return Returns the number of blobs
|
||||
*/
|
||||
int ComputeGlobalBlobIDs( int nx, int ny, int nz, const RankInfoStruct& rank_info,
|
||||
const DoubleArray& Phase, const DoubleArray& SignDist, double vF, double vS,
|
||||
BlobIDArray& GlobalBlobID, const Utilities::MPI& comm );
|
||||
|
||||
int ComputeGlobalBlobIDs(int nx, int ny, int nz,
|
||||
const RankInfoStruct &rank_info,
|
||||
const DoubleArray &Phase, const DoubleArray &SignDist,
|
||||
double vF, double vS, BlobIDArray &GlobalBlobID,
|
||||
const Utilities::MPI &comm);
|
||||
|
||||
/*!
|
||||
* @brief Compute component of the specified phase
|
||||
|
@ -68,81 +85,89 @@ int ComputeGlobalBlobIDs( int nx, int ny, int nz, const RankInfoStruct& rank_inf
|
|||
* @param[in] nx Number of elements in the x-direction
|
||||
* @param[in] ny Number of elements in the y-direction
|
||||
* @param[in] nz Number of elements in the z-direction
|
||||
* @param[in] rank_in MPI communication info
|
||||
* @param[in] rank_info MPI communication info
|
||||
* @param[in] PhaseID Array that identifies the phases
|
||||
* @param[in] VALUE Identifier for the phase to decompose
|
||||
* @param[out] GlobalBlobID The ids of the blobs for the phase
|
||||
* @param[in] comm The communicator to use
|
||||
* @return Return the number of components in the specified phase
|
||||
*/
|
||||
int ComputeGlobalPhaseComponent( int nx, int ny, int nz, const RankInfoStruct& rank_info,
|
||||
const IntArray &PhaseID, int &VALUE, BlobIDArray &GlobalBlobID, const Utilities::MPI& comm );
|
||||
|
||||
int ComputeGlobalPhaseComponent(int nx, int ny, int nz,
|
||||
const RankInfoStruct &rank_info,
|
||||
const IntArray &PhaseID, int &VALUE,
|
||||
BlobIDArray &GlobalBlobID,
|
||||
const Utilities::MPI &comm);
|
||||
|
||||
/*!
|
||||
* @brief Reorder the blobs
|
||||
* @details Reorder the blobs based on the number of cells they contain
|
||||
* largest first.
|
||||
* @param[in] nx Number of elements in the x-direction
|
||||
* @param[in] ny Number of elements in the y-direction
|
||||
* @param[in] nz Number of elements in the z-direction
|
||||
* @param[in/out] ID The ids of the blobs
|
||||
* @param[in,out] ID The ids of the blobs
|
||||
* @param[in] comm MPI communicator
|
||||
*/
|
||||
void ReorderBlobIDs( BlobIDArray& ID, const Utilities::MPI& comm );
|
||||
void ReorderBlobIDs(BlobIDArray &ID, const Utilities::MPI &comm);
|
||||
|
||||
|
||||
typedef std::pair<BlobIDType,std::vector<BlobIDType> > BlobIDSplitStruct;
|
||||
typedef std::pair<std::vector<BlobIDType>,BlobIDType> BlobIDMergeStruct;
|
||||
typedef std::pair<std::vector<BlobIDType>,std::vector<BlobIDType> > BlobIDMergeSplitStruct;
|
||||
typedef std::pair<BlobIDType,BlobIDType> OverlapID;
|
||||
typedef std::pair<BlobIDType, std::vector<BlobIDType>> BlobIDSplitStruct;
|
||||
typedef std::pair<std::vector<BlobIDType>, BlobIDType> BlobIDMergeStruct;
|
||||
typedef std::pair<std::vector<BlobIDType>, std::vector<BlobIDType>>
|
||||
BlobIDMergeSplitStruct;
|
||||
typedef std::pair<BlobIDType, BlobIDType> OverlapID;
|
||||
struct ID_map_struct {
|
||||
std::vector<BlobIDType> created; // list of new blobs that were created
|
||||
std::vector<BlobIDType> destroyed; // list of blobs that disappeared
|
||||
std::vector<std::pair<BlobIDType,BlobIDType> > src_dst; // one-one mapping of blobs (first,second timestep id)
|
||||
std::vector<BlobIDSplitStruct> split; // list of blobs that split
|
||||
std::vector<BlobIDMergeStruct> merge; // list of blobs that merged
|
||||
std::vector<BlobIDMergeSplitStruct> merge_split; // list of blobs that both merged and split
|
||||
std::map<OverlapID,int64_t> overlap; // for ids that are not a 1-1 mapping, this is a list of the overlaps <src,dst>
|
||||
std::vector<BlobIDType> created; // list of new blobs that were created
|
||||
std::vector<BlobIDType> destroyed; // list of blobs that disappeared
|
||||
std::vector<std::pair<BlobIDType, BlobIDType>>
|
||||
src_dst; // one-one mapping of blobs (first,second timestep id)
|
||||
std::vector<BlobIDSplitStruct> split; // list of blobs that split
|
||||
std::vector<BlobIDMergeStruct> merge; // list of blobs that merged
|
||||
std::vector<BlobIDMergeSplitStruct>
|
||||
merge_split; // list of blobs that both merged and split
|
||||
std::map<OverlapID, int64_t>
|
||||
overlap; // for ids that are not a 1-1 mapping, this is a list of the overlaps <src,dst>
|
||||
//! Empty constructor
|
||||
ID_map_struct() {}
|
||||
//! Create initial map from N blobs (ordered 1:N-1)
|
||||
ID_map_struct( int N ) {
|
||||
ID_map_struct(int N) {
|
||||
created.resize(N);
|
||||
for (int i=0; i<N; i++) { created[i]=i; }
|
||||
for (int i = 0; i < N; i++) {
|
||||
created[i] = i;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Get the mapping of blob ids between iterations
|
||||
* @details This functions computes the map of blob ids between iterations
|
||||
* @return Returns the map of the blob ids. Each final blob may have no source
|
||||
* ids, one parent, or multiple parents. Each src id may be a parent for multiple blobs.
|
||||
* @param[in] nx Number of elements in the x-direction
|
||||
* @param[in] ny Number of elements in the y-direction
|
||||
* @param[in] nz Number of elements in the z-direction
|
||||
* @param[in] ID1 The blob ids at the first timestep
|
||||
* @param[in] ID2 The blob ids at the second timestep
|
||||
* @param[in] comm The communicator to use
|
||||
*/
|
||||
ID_map_struct computeIDMap( int nx, int ny, int nz, const BlobIDArray& ID1, const BlobIDArray& ID2, const Utilities::MPI& comm );
|
||||
|
||||
ID_map_struct computeIDMap(int nx, int ny, int nz, const BlobIDArray &ID1,
|
||||
const BlobIDArray &ID2, const Utilities::MPI &comm);
|
||||
|
||||
/*!
|
||||
* @brief Compute the new global ids based on the map
|
||||
* @details This functions computes the time-consistent global ids for the
|
||||
* current global id index
|
||||
* @param[in/out] map The timestep mapping for the ids
|
||||
* @param[in,out] map The timestep mapping for the ids
|
||||
* @param[in] id_max The globally largest id used previously
|
||||
* @param[out] new_ids The newly renumbered blob ids (0:ids.max())
|
||||
*/
|
||||
void getNewIDs( ID_map_struct& map, BlobIDType& id_max, std::vector<BlobIDType>& new_ids );
|
||||
|
||||
void getNewIDs(ID_map_struct &map, BlobIDType &id_max,
|
||||
std::vector<BlobIDType> &new_ids);
|
||||
|
||||
/*!
|
||||
* @brief Update the blob ids based on mapping
|
||||
* @details This functions computes the map of blob ids between iterations.
|
||||
* Note: we also update the map to reflect the new ids
|
||||
* @param[out] new_ids The newly renumbered blob ids (0:ids.max())
|
||||
* @param[in/out] IDs The blob ids to renumber
|
||||
* @param[in,out] IDs The blob ids to renumber
|
||||
*/
|
||||
void renumberIDs( const std::vector<BlobIDType>& new_id_list, BlobIDArray& IDs );
|
||||
|
||||
void renumberIDs(const std::vector<BlobIDType> &new_ids, BlobIDArray &IDs);
|
||||
|
||||
/*!
|
||||
* @brief Write the ID map
|
||||
|
@ -153,8 +178,7 @@ void renumberIDs( const std::vector<BlobIDType>& new_id_list, BlobIDArray& IDs )
|
|||
* @param[in] timestep The current timestep (timestep 0 creates the file)
|
||||
* @param[in] filename The filename to write/append
|
||||
*/
|
||||
void writeIDMap( const ID_map_struct& map, long long int timestep, const std::string& filename );
|
||||
|
||||
|
||||
void writeIDMap(const ID_map_struct &map, long long int timestep,
|
||||
const std::string &filename);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,337 +1,377 @@
|
|||
#include "analysis/dcel.h"
|
||||
|
||||
DECL::DECL(){
|
||||
DCEL::DCEL() {}
|
||||
|
||||
DCEL::~DCEL() {
|
||||
TriangleCount = 0;
|
||||
VertexCount = 0;
|
||||
}
|
||||
|
||||
DECL::~DECL(){
|
||||
TriangleCount=0;
|
||||
VertexCount=0;
|
||||
|
||||
int DCEL::Face(int index) { return FaceData[index]; }
|
||||
|
||||
void DCEL::Write() {
|
||||
int e1, e2, e3;
|
||||
FILE *TRIANGLES;
|
||||
TRIANGLES = fopen("triangles.stl", "w");
|
||||
fprintf(TRIANGLES, "solid \n");
|
||||
for (int idx = 0; idx < TriangleCount; idx++) {
|
||||
e1 = Face(idx);
|
||||
e2 = halfedge.next(e1);
|
||||
e3 = halfedge.next(e2);
|
||||
auto P1 = vertex.coords(halfedge.v1(e1));
|
||||
auto P2 = vertex.coords(halfedge.v1(e2));
|
||||
auto P3 = vertex.coords(halfedge.v1(e3));
|
||||
fprintf(TRIANGLES, "vertex %f %f %f\n", P1.x, P1.y, P1.z);
|
||||
fprintf(TRIANGLES, "vertex %f %f %f\n", P2.x, P2.y, P2.z);
|
||||
fprintf(TRIANGLES, "vertex %f %f %f\n", P3.x, P3.y, P3.z);
|
||||
}
|
||||
fclose(TRIANGLES);
|
||||
}
|
||||
|
||||
int DECL::Face(int index){
|
||||
return FaceData[index];
|
||||
void DCEL::LocalIsosurface(const DoubleArray &A, double value, const int i,
|
||||
const int j, const int k) {
|
||||
Point P, Q;
|
||||
Point PlaceHolder;
|
||||
Point C0, C1, C2, C3, C4, C5, C6, C7;
|
||||
|
||||
Point VertexList[12];
|
||||
Point NewVertexList[12];
|
||||
int LocalRemap[12];
|
||||
|
||||
Point cellvertices[20];
|
||||
std::array<std::array<int, 3>, 20> Triangles;
|
||||
|
||||
// Values from array 'A' at the cube corners
|
||||
double CubeValues[8];
|
||||
|
||||
// Points corresponding to cube corners
|
||||
C0.x = 0.0;
|
||||
C0.y = 0.0;
|
||||
C0.z = 0.0;
|
||||
C1.x = 1.0;
|
||||
C1.y = 0.0;
|
||||
C1.z = 0.0;
|
||||
C2.x = 1.0;
|
||||
C2.y = 1.0;
|
||||
C2.z = 0.0;
|
||||
C3.x = 0.0;
|
||||
C3.y = 1.0;
|
||||
C3.z = 0.0;
|
||||
C4.x = 0.0;
|
||||
C4.y = 0.0;
|
||||
C4.z = 1.0;
|
||||
C5.x = 1.0;
|
||||
C5.y = 0.0;
|
||||
C5.z = 1.0;
|
||||
C6.x = 1.0;
|
||||
C6.y = 1.0;
|
||||
C6.z = 1.0;
|
||||
C7.x = 0.0;
|
||||
C7.y = 1.0;
|
||||
C7.z = 1.0;
|
||||
|
||||
CubeValues[0] = A(i, j, k) - value;
|
||||
CubeValues[1] = A(i + 1, j, k) - value;
|
||||
CubeValues[2] = A(i + 1, j + 1, k) - value;
|
||||
CubeValues[3] = A(i, j + 1, k) - value;
|
||||
CubeValues[4] = A(i, j, k + 1) - value;
|
||||
CubeValues[5] = A(i + 1, j, k + 1) - value;
|
||||
CubeValues[6] = A(i + 1, j + 1, k + 1) - value;
|
||||
CubeValues[7] = A(i, j + 1, k + 1) - value;
|
||||
//printf("Set cube values: %i, %i, %i \n",i,j,k);
|
||||
|
||||
//Determine the index into the edge table which
|
||||
//tells us which vertices are inside of the surface
|
||||
int CubeIndex = 0;
|
||||
if (CubeValues[0] < 0.0f)
|
||||
CubeIndex |= 1;
|
||||
if (CubeValues[1] < 0.0f)
|
||||
CubeIndex |= 2;
|
||||
if (CubeValues[2] < 0.0f)
|
||||
CubeIndex |= 4;
|
||||
if (CubeValues[3] < 0.0f)
|
||||
CubeIndex |= 8;
|
||||
if (CubeValues[4] < 0.0f)
|
||||
CubeIndex |= 16;
|
||||
if (CubeValues[5] < 0.0f)
|
||||
CubeIndex |= 32;
|
||||
if (CubeValues[6] < 0.0f)
|
||||
CubeIndex |= 64;
|
||||
if (CubeValues[7] < 0.0f)
|
||||
CubeIndex |= 128;
|
||||
|
||||
//Find the vertices where the surface intersects the cube
|
||||
if (edgeTable[CubeIndex] & 1) {
|
||||
P = VertexInterp(C0, C1, CubeValues[0], CubeValues[1]);
|
||||
VertexList[0] = P;
|
||||
Q = C0;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 2) {
|
||||
P = VertexInterp(C1, C2, CubeValues[1], CubeValues[2]);
|
||||
VertexList[1] = P;
|
||||
Q = C1;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 4) {
|
||||
P = VertexInterp(C2, C3, CubeValues[2], CubeValues[3]);
|
||||
VertexList[2] = P;
|
||||
Q = C2;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 8) {
|
||||
P = VertexInterp(C3, C0, CubeValues[3], CubeValues[0]);
|
||||
VertexList[3] = P;
|
||||
Q = C3;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 16) {
|
||||
P = VertexInterp(C4, C5, CubeValues[4], CubeValues[5]);
|
||||
VertexList[4] = P;
|
||||
Q = C4;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 32) {
|
||||
P = VertexInterp(C5, C6, CubeValues[5], CubeValues[6]);
|
||||
VertexList[5] = P;
|
||||
Q = C5;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 64) {
|
||||
P = VertexInterp(C6, C7, CubeValues[6], CubeValues[7]);
|
||||
VertexList[6] = P;
|
||||
Q = C6;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 128) {
|
||||
P = VertexInterp(C7, C4, CubeValues[7], CubeValues[4]);
|
||||
VertexList[7] = P;
|
||||
Q = C7;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 256) {
|
||||
P = VertexInterp(C0, C4, CubeValues[0], CubeValues[4]);
|
||||
VertexList[8] = P;
|
||||
Q = C0;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 512) {
|
||||
P = VertexInterp(C1, C5, CubeValues[1], CubeValues[5]);
|
||||
VertexList[9] = P;
|
||||
Q = C1;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 1024) {
|
||||
P = VertexInterp(C2, C6, CubeValues[2], CubeValues[6]);
|
||||
VertexList[10] = P;
|
||||
Q = C2;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 2048) {
|
||||
P = VertexInterp(C3, C7, CubeValues[3], CubeValues[7]);
|
||||
VertexList[11] = P;
|
||||
Q = C3;
|
||||
}
|
||||
|
||||
VertexCount = 0;
|
||||
for (int idx = 0; idx < 12; idx++)
|
||||
LocalRemap[idx] = -1;
|
||||
|
||||
for (int idx = 0; triTable[CubeIndex][idx] != -1; idx++) {
|
||||
if (LocalRemap[triTable[CubeIndex][idx]] == -1) {
|
||||
NewVertexList[VertexCount] = VertexList[triTable[CubeIndex][idx]];
|
||||
LocalRemap[triTable[CubeIndex][idx]] = VertexCount;
|
||||
VertexCount++;
|
||||
}
|
||||
}
|
||||
|
||||
//printf("Found %i vertices \n",VertexCount);
|
||||
|
||||
for (int idx = 0; idx < VertexCount; idx++) {
|
||||
P = NewVertexList[idx];
|
||||
//P.x += i;
|
||||
//P.y += j;
|
||||
//P.z += k;
|
||||
cellvertices[idx] = P;
|
||||
}
|
||||
|
||||
TriangleCount = 0;
|
||||
for (int idx = 0; triTable[CubeIndex][idx] != -1; idx += 3) {
|
||||
Triangles[TriangleCount][0] = LocalRemap[triTable[CubeIndex][idx + 0]];
|
||||
Triangles[TriangleCount][1] = LocalRemap[triTable[CubeIndex][idx + 1]];
|
||||
Triangles[TriangleCount][2] = LocalRemap[triTable[CubeIndex][idx + 2]];
|
||||
TriangleCount++;
|
||||
}
|
||||
int nTris = TriangleCount;
|
||||
|
||||
// Now add the local values to the DCEL data structure
|
||||
if (nTris > 0) {
|
||||
FaceData.resize(TriangleCount);
|
||||
//printf("Construct halfedge structure... \n");
|
||||
//printf(" Construct %i triangles \n",nTris);
|
||||
halfedge.resize(nTris * 3);
|
||||
int idx_edge = 0;
|
||||
for (int idx = 0; idx < TriangleCount; idx++) {
|
||||
int V1 = Triangles[idx][0];
|
||||
int V2 = Triangles[idx][1];
|
||||
int V3 = Triangles[idx][2];
|
||||
FaceData[idx] = idx_edge;
|
||||
// first edge: V1->V2
|
||||
halfedge.data(0, idx_edge) = V1; // first vertex
|
||||
halfedge.data(1, idx_edge) = V2; // second vertex
|
||||
halfedge.data(2, idx_edge) = idx; // triangle
|
||||
halfedge.data(3, idx_edge) = -1; // twin
|
||||
halfedge.data(4, idx_edge) = idx_edge + 2; // previous edge
|
||||
halfedge.data(5, idx_edge) = idx_edge + 1; // next edge
|
||||
idx_edge++;
|
||||
// second edge: V2->V3
|
||||
halfedge.data(0, idx_edge) = V2; // first vertex
|
||||
halfedge.data(1, idx_edge) = V3; // second vertex
|
||||
halfedge.data(2, idx_edge) = idx; // triangle
|
||||
halfedge.data(3, idx_edge) = -1; // twin
|
||||
halfedge.data(4, idx_edge) = idx_edge - 1; // previous edge
|
||||
halfedge.data(5, idx_edge) = idx_edge + 1; // next edge
|
||||
idx_edge++;
|
||||
// third edge: V3->V1
|
||||
halfedge.data(0, idx_edge) = V3; // first vertex
|
||||
halfedge.data(1, idx_edge) = V1; // second vertex
|
||||
halfedge.data(2, idx_edge) = idx; // triangle
|
||||
halfedge.data(3, idx_edge) = -1; // twin
|
||||
halfedge.data(4, idx_edge) = idx_edge - 1; // previous edge
|
||||
halfedge.data(5, idx_edge) = idx_edge - 2; // next edge
|
||||
idx_edge++;
|
||||
//printf(" ***tri %i ***edge %i *** \n",idx, idx_edge);
|
||||
}
|
||||
//printf(" parsing halfedge structure\n");
|
||||
int EdgeCount = idx_edge;
|
||||
for (int idx = 0; idx < EdgeCount; idx++) {
|
||||
int V1 = halfedge.data(0, idx);
|
||||
int V2 = halfedge.data(1, idx);
|
||||
// Find all the twins within the cube
|
||||
for (int jdx = 0; jdx < EdgeCount; jdx++) {
|
||||
if (halfedge.data(1, jdx) == V1 &&
|
||||
halfedge.data(0, jdx) == V2) {
|
||||
// this is the pair
|
||||
halfedge.data(3, idx) = jdx;
|
||||
halfedge.data(3, jdx) = idx;
|
||||
}
|
||||
if (halfedge.data(1, jdx) == V2 &&
|
||||
halfedge.data(0, jdx) == V1 && !(idx == jdx)) {
|
||||
std::printf(
|
||||
"WARNING: half edges with identical orientation! \n");
|
||||
}
|
||||
}
|
||||
// Use "ghost" twins if edge is on a cube face
|
||||
P = cellvertices[V1];
|
||||
Q = cellvertices[V2];
|
||||
if (P.x == 0.0 && Q.x == 0.0)
|
||||
halfedge.data(3, idx) = -1; // ghost twin for x=0 face
|
||||
if (P.x == 1.0 && Q.x == 1.0)
|
||||
halfedge.data(3, idx) = -4; // ghost twin for x=1 face
|
||||
if (P.y == 0.0 && Q.y == 0.0)
|
||||
halfedge.data(3, idx) = -2; // ghost twin for y=0 face
|
||||
if (P.y == 1.0 && Q.y == 1.0)
|
||||
halfedge.data(3, idx) = -5; // ghost twin for y=1 face
|
||||
if (P.z == 0.0 && Q.z == 0.0)
|
||||
halfedge.data(3, idx) = -3; // ghost twin for z=0 face
|
||||
if (P.z == 1.0 && Q.z == 1.0)
|
||||
halfedge.data(3, idx) = -6; // ghost twin for z=1 face
|
||||
}
|
||||
}
|
||||
|
||||
// Map vertices to global coordinates
|
||||
for (int idx = 0; idx < VertexCount; idx++) {
|
||||
P = cellvertices[idx];
|
||||
P.x += i;
|
||||
P.y += j;
|
||||
P.z += k;
|
||||
vertex.assign(idx, P);
|
||||
}
|
||||
}
|
||||
|
||||
void DECL::Write(){
|
||||
int e1,e2,e3;
|
||||
FILE *TRIANGLES;
|
||||
TRIANGLES = fopen("triangles.stl","w");
|
||||
fprintf(TRIANGLES,"solid \n");
|
||||
for (int idx=0; idx<TriangleCount; idx++){
|
||||
e1 = Face(idx);
|
||||
e2 = halfedge.next(e1);
|
||||
e3 = halfedge.next(e2);
|
||||
auto P1 = vertex.coords(halfedge.v1(e1));
|
||||
auto P2 = vertex.coords(halfedge.v1(e2));
|
||||
auto P3 = vertex.coords(halfedge.v1(e3));
|
||||
fprintf(TRIANGLES,"vertex %f %f %f\n",P1.x,P1.y,P1.z);
|
||||
fprintf(TRIANGLES,"vertex %f %f %f\n",P2.x,P2.y,P2.z);
|
||||
fprintf(TRIANGLES,"vertex %f %f %f\n",P3.x,P3.y,P3.z);
|
||||
}
|
||||
fclose(TRIANGLES);
|
||||
Point DCEL::TriNormal(int edge) {
|
||||
Point P, Q, R;
|
||||
Point U, V, W;
|
||||
double nx, ny, nz, len;
|
||||
// at cube faces define outward normal to cube
|
||||
if (edge == -1) {
|
||||
W.x = -1.0;
|
||||
W.y = 0.0;
|
||||
W.z = 0.0; // x cube face
|
||||
} else if (edge == -2) {
|
||||
W.x = 0.0;
|
||||
W.y = -1.0;
|
||||
W.z = 0.0; // y cube face
|
||||
} else if (edge == -3) {
|
||||
W.x = 0.0;
|
||||
W.y = 0.0;
|
||||
W.z = -1.0; // z cube face
|
||||
} else if (edge == -4) {
|
||||
W.x = 1.0;
|
||||
W.y = 0.0;
|
||||
W.z = 0.0; // x cube face
|
||||
} else if (edge == -5) {
|
||||
W.x = 0.0;
|
||||
W.y = 1.0;
|
||||
W.z = 0.0; // y cube face
|
||||
} else if (edge == -6) {
|
||||
W.x = 0.0;
|
||||
W.y = 0.0;
|
||||
W.z = 1.0; // z cube face
|
||||
} else {
|
||||
// vertices for triange
|
||||
int e2 = halfedge.next(edge);
|
||||
int e3 = halfedge.next(e2);
|
||||
P = vertex.coords(halfedge.v1(edge));
|
||||
Q = vertex.coords(halfedge.v1(e2));
|
||||
R = vertex.coords(halfedge.v1(e3));
|
||||
// edge vectors
|
||||
U = Q - P;
|
||||
V = R - Q;
|
||||
// normal vector
|
||||
nx = U.y * V.z - U.z * V.y;
|
||||
ny = U.z * V.x - U.x * V.z;
|
||||
nz = U.x * V.y - U.y * V.x;
|
||||
len = sqrt(nx * nx + ny * ny + nz * nz);
|
||||
W.x = nx / len;
|
||||
W.y = ny / len;
|
||||
W.z = nz / len;
|
||||
}
|
||||
return W;
|
||||
}
|
||||
|
||||
void DECL::LocalIsosurface(const DoubleArray& A, double value, const int i, const int j, const int k){
|
||||
Point P,Q;
|
||||
Point PlaceHolder;
|
||||
Point C0,C1,C2,C3,C4,C5,C6,C7;
|
||||
double DCEL::EdgeAngle(int edge) {
|
||||
double angle;
|
||||
double dotprod;
|
||||
Point P, Q, R; // triangle vertices
|
||||
Point U, V, W; // normal vectors
|
||||
int e2 = halfedge.next(edge);
|
||||
int e3 = halfedge.next(e2);
|
||||
P = vertex.coords(halfedge.v1(edge));
|
||||
Q = vertex.coords(halfedge.v1(e2));
|
||||
R = vertex.coords(halfedge.v1(e3));
|
||||
U = TriNormal(edge);
|
||||
V = TriNormal(halfedge.twin(edge));
|
||||
if (halfedge.twin(edge) < 0) {
|
||||
// compute edge normal in plane of cube face
|
||||
W = P - Q; // edge tangent vector
|
||||
double length = sqrt(W.x * W.x + W.y * W.y + W.z * W.z);
|
||||
W.x /= length;
|
||||
W.y /= length;
|
||||
W.z /= length;
|
||||
// edge normal within the plane of the cube face
|
||||
double nx = W.y * V.z - W.z * V.y;
|
||||
double ny = W.z * V.x - W.x * V.z;
|
||||
double nz = W.x * V.y - W.y * V.x;
|
||||
length = sqrt(nx * nx + ny * ny + nz * nz);
|
||||
// new value for V is this normal vector
|
||||
V.x = nx / length;
|
||||
V.y = ny / length;
|
||||
V.z = nz / length;
|
||||
dotprod = U.x * V.x + U.y * V.y + U.z * V.z;
|
||||
if (dotprod < 0.f) {
|
||||
//printf("negative dot product on face\n");
|
||||
dotprod = -dotprod;
|
||||
V.x = -V.x;
|
||||
V.y = -V.y;
|
||||
V.z = -V.z;
|
||||
}
|
||||
|
||||
Point VertexList[12];
|
||||
Point NewVertexList[12];
|
||||
int LocalRemap[12];
|
||||
|
||||
Point cellvertices[20];
|
||||
std::array<std::array<int,3>,20> Triangles;
|
||||
|
||||
// Values from array 'A' at the cube corners
|
||||
double CubeValues[8];
|
||||
|
||||
// Points corresponding to cube corners
|
||||
C0.x = 0.0; C0.y = 0.0; C0.z = 0.0;
|
||||
C1.x = 1.0; C1.y = 0.0; C1.z = 0.0;
|
||||
C2.x = 1.0; C2.y = 1.0; C2.z = 0.0;
|
||||
C3.x = 0.0; C3.y = 1.0; C3.z = 0.0;
|
||||
C4.x = 0.0; C4.y = 0.0; C4.z = 1.0;
|
||||
C5.x = 1.0; C5.y = 0.0; C5.z = 1.0;
|
||||
C6.x = 1.0; C6.y = 1.0; C6.z = 1.0;
|
||||
C7.x = 0.0; C7.y = 1.0; C7.z = 1.0;
|
||||
|
||||
CubeValues[0] = A(i,j,k) - value;
|
||||
CubeValues[1] = A(i+1,j,k) - value;
|
||||
CubeValues[2] = A(i+1,j+1,k) - value;
|
||||
CubeValues[3] = A(i,j+1,k) - value;
|
||||
CubeValues[4] = A(i,j,k+1) - value;
|
||||
CubeValues[5] = A(i+1,j,k+1) - value;
|
||||
CubeValues[6] = A(i+1,j+1,k+1) - value;
|
||||
CubeValues[7] = A(i,j+1,k+1) -value;
|
||||
//printf("Set cube values: %i, %i, %i \n",i,j,k);
|
||||
|
||||
//Determine the index into the edge table which
|
||||
//tells us which vertices are inside of the surface
|
||||
int CubeIndex = 0;
|
||||
if (CubeValues[0] < 0.0f) CubeIndex |= 1;
|
||||
if (CubeValues[1] < 0.0f) CubeIndex |= 2;
|
||||
if (CubeValues[2] < 0.0f) CubeIndex |= 4;
|
||||
if (CubeValues[3] < 0.0f) CubeIndex |= 8;
|
||||
if (CubeValues[4] < 0.0f) CubeIndex |= 16;
|
||||
if (CubeValues[5] < 0.0f) CubeIndex |= 32;
|
||||
if (CubeValues[6] < 0.0f) CubeIndex |= 64;
|
||||
if (CubeValues[7] < 0.0f) CubeIndex |= 128;
|
||||
|
||||
//Find the vertices where the surface intersects the cube
|
||||
if (edgeTable[CubeIndex] & 1){
|
||||
P = VertexInterp(C0,C1,CubeValues[0],CubeValues[1]);
|
||||
VertexList[0] = P;
|
||||
Q = C0;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 2){
|
||||
P = VertexInterp(C1,C2,CubeValues[1],CubeValues[2]);
|
||||
VertexList[1] = P;
|
||||
Q = C1;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 4){
|
||||
P = VertexInterp(C2,C3,CubeValues[2],CubeValues[3]);
|
||||
VertexList[2] = P;
|
||||
Q = C2;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 8){
|
||||
P = VertexInterp(C3,C0,CubeValues[3],CubeValues[0]);
|
||||
VertexList[3] = P;
|
||||
Q = C3;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 16){
|
||||
P = VertexInterp(C4,C5,CubeValues[4],CubeValues[5]);
|
||||
VertexList[4] = P;
|
||||
Q = C4;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 32){
|
||||
P = VertexInterp(C5,C6,CubeValues[5],CubeValues[6]);
|
||||
VertexList[5] = P;
|
||||
Q = C5;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 64){
|
||||
P = VertexInterp(C6,C7,CubeValues[6],CubeValues[7]);
|
||||
VertexList[6] = P;
|
||||
Q = C6;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 128){
|
||||
P = VertexInterp(C7,C4,CubeValues[7],CubeValues[4]);
|
||||
VertexList[7] = P;
|
||||
Q = C7;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 256){
|
||||
P = VertexInterp(C0,C4,CubeValues[0],CubeValues[4]);
|
||||
VertexList[8] = P;
|
||||
Q = C0;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 512){
|
||||
P = VertexInterp(C1,C5,CubeValues[1],CubeValues[5]);
|
||||
VertexList[9] = P;
|
||||
Q = C1;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 1024){
|
||||
P = VertexInterp(C2,C6,CubeValues[2],CubeValues[6]);
|
||||
VertexList[10] = P;
|
||||
Q = C2;
|
||||
}
|
||||
if (edgeTable[CubeIndex] & 2048){
|
||||
P = VertexInterp(C3,C7,CubeValues[3],CubeValues[7]);
|
||||
VertexList[11] = P;
|
||||
Q = C3;
|
||||
}
|
||||
|
||||
VertexCount=0;
|
||||
for (int idx=0;idx<12;idx++)
|
||||
LocalRemap[idx] = -1;
|
||||
|
||||
for (int idx=0;triTable[CubeIndex][idx]!=-1;idx++)
|
||||
{
|
||||
if(LocalRemap[triTable[CubeIndex][idx]] == -1)
|
||||
{
|
||||
NewVertexList[VertexCount] = VertexList[triTable[CubeIndex][idx]];
|
||||
LocalRemap[triTable[CubeIndex][idx]] = VertexCount;
|
||||
VertexCount++;
|
||||
}
|
||||
}
|
||||
|
||||
//printf("Found %i vertices \n",VertexCount);
|
||||
|
||||
for (int idx=0;idx<VertexCount;idx++) {
|
||||
P = NewVertexList[idx];
|
||||
//P.x += i;
|
||||
//P.y += j;
|
||||
//P.z += k;
|
||||
cellvertices[idx] = P;
|
||||
}
|
||||
|
||||
TriangleCount = 0;
|
||||
for (int idx=0;triTable[CubeIndex][idx]!=-1;idx+=3) {
|
||||
Triangles[TriangleCount][0] = LocalRemap[triTable[CubeIndex][idx+0]];
|
||||
Triangles[TriangleCount][1] = LocalRemap[triTable[CubeIndex][idx+1]];
|
||||
Triangles[TriangleCount][2] = LocalRemap[triTable[CubeIndex][idx+2]];
|
||||
TriangleCount++;
|
||||
}
|
||||
int nTris = TriangleCount;
|
||||
|
||||
// Now add the local values to the DECL data structure
|
||||
if (nTris>0){
|
||||
FaceData.resize(TriangleCount);
|
||||
//printf("Construct halfedge structure... \n");
|
||||
//printf(" Construct %i triangles \n",nTris);
|
||||
halfedge.resize(nTris*3);
|
||||
int idx_edge=0;
|
||||
for (int idx=0; idx<TriangleCount; idx++){
|
||||
int V1 = Triangles[idx][0];
|
||||
int V2 = Triangles[idx][1];
|
||||
int V3 = Triangles[idx][2];
|
||||
FaceData[idx] = idx_edge;
|
||||
// first edge: V1->V2
|
||||
halfedge.data(0,idx_edge) = V1; // first vertex
|
||||
halfedge.data(1,idx_edge) = V2; // second vertex
|
||||
halfedge.data(2,idx_edge) = idx; // triangle
|
||||
halfedge.data(3,idx_edge) = -1; // twin
|
||||
halfedge.data(4,idx_edge) = idx_edge+2; // previous edge
|
||||
halfedge.data(5,idx_edge) = idx_edge+1; // next edge
|
||||
idx_edge++;
|
||||
// second edge: V2->V3
|
||||
halfedge.data(0,idx_edge) = V2; // first vertex
|
||||
halfedge.data(1,idx_edge) = V3; // second vertex
|
||||
halfedge.data(2,idx_edge) = idx; // triangle
|
||||
halfedge.data(3,idx_edge) = -1; // twin
|
||||
halfedge.data(4,idx_edge) = idx_edge-1; // previous edge
|
||||
halfedge.data(5,idx_edge) = idx_edge+1; // next edge
|
||||
idx_edge++;
|
||||
// third edge: V3->V1
|
||||
halfedge.data(0,idx_edge) = V3; // first vertex
|
||||
halfedge.data(1,idx_edge) = V1; // second vertex
|
||||
halfedge.data(2,idx_edge) = idx; // triangle
|
||||
halfedge.data(3,idx_edge) = -1; // twin
|
||||
halfedge.data(4,idx_edge) = idx_edge-1; // previous edge
|
||||
halfedge.data(5,idx_edge) = idx_edge-2; // next edge
|
||||
idx_edge++;
|
||||
//printf(" ***tri %i ***edge %i *** \n",idx, idx_edge);
|
||||
}
|
||||
//printf(" parsing halfedge structure\n");
|
||||
int EdgeCount=idx_edge;
|
||||
for (int idx=0; idx<EdgeCount; idx++){
|
||||
int V1=halfedge.data(0,idx);
|
||||
int V2=halfedge.data(1,idx);
|
||||
// Find all the twins within the cube
|
||||
for (int jdx=0; jdx<EdgeCount; jdx++){
|
||||
if (halfedge.data(1,jdx) == V1 && halfedge.data(0,jdx) == V2){
|
||||
// this is the pair
|
||||
halfedge.data(3,idx) = jdx;
|
||||
halfedge.data(3,jdx) = idx;
|
||||
}
|
||||
if (halfedge.data(1,jdx) == V2 && halfedge.data(0,jdx) == V1 && !(idx==jdx)){
|
||||
std::printf("WARNING: half edges with identical orientation! \n");
|
||||
}
|
||||
}
|
||||
// Use "ghost" twins if edge is on a cube face
|
||||
P = cellvertices[V1];
|
||||
Q = cellvertices[V2];
|
||||
if (P.x == 0.0 && Q.x == 0.0) halfedge.data(3,idx) = -1; // ghost twin for x=0 face
|
||||
if (P.x == 1.0 && Q.x == 1.0) halfedge.data(3,idx) = -4; // ghost twin for x=1 face
|
||||
if (P.y == 0.0 && Q.y == 0.0) halfedge.data(3,idx) = -2; // ghost twin for y=0 face
|
||||
if (P.y == 1.0 && Q.y == 1.0) halfedge.data(3,idx) = -5; // ghost twin for y=1 face
|
||||
if (P.z == 0.0 && Q.z == 0.0) halfedge.data(3,idx) = -3; // ghost twin for z=0 face
|
||||
if (P.z == 1.0 && Q.z == 1.0) halfedge.data(3,idx) = -6; // ghost twin for z=1 face
|
||||
}
|
||||
}
|
||||
|
||||
// Map vertices to global coordinates
|
||||
for (int idx=0;idx<VertexCount;idx++) {
|
||||
P = cellvertices[idx];
|
||||
P.x += i;
|
||||
P.y += j;
|
||||
P.z += k;
|
||||
vertex.assign(idx,P);
|
||||
}
|
||||
}
|
||||
|
||||
Point DECL::TriNormal(int edge)
|
||||
{
|
||||
Point P,Q,R;
|
||||
Point U,V,W;
|
||||
double nx,ny,nz,len;
|
||||
// at cube faces define outward normal to cube
|
||||
if (edge == -1){
|
||||
W.x = -1.0; W.y = 0.0; W.z = 0.0; // x cube face
|
||||
}
|
||||
else if (edge == -2){
|
||||
W.x = 0.0; W.y = -1.0; W.z = 0.0; // y cube face
|
||||
}
|
||||
else if (edge == -3){
|
||||
W.x = 0.0; W.y = 0.0; W.z = -1.0; // z cube face
|
||||
}
|
||||
else if (edge == -4){
|
||||
W.x = 1.0; W.y = 0.0; W.z = 0.0; // x cube face
|
||||
}
|
||||
else if (edge == -5){
|
||||
W.x = 0.0; W.y = 1.0; W.z = 0.0; // y cube face
|
||||
}
|
||||
else if (edge == -6){
|
||||
W.x = 0.0; W.y = 0.0; W.z = 1.0; // z cube face
|
||||
}
|
||||
else{
|
||||
// vertices for triange
|
||||
int e2 = halfedge.next(edge);
|
||||
int e3 = halfedge.next(e2);
|
||||
P=vertex.coords(halfedge.v1(edge));
|
||||
Q=vertex.coords(halfedge.v1(e2));
|
||||
R=vertex.coords(halfedge.v1(e3));
|
||||
// edge vectors
|
||||
U = Q-P;
|
||||
V = R-Q;
|
||||
// normal vector
|
||||
nx = U.y*V.z - U.z*V.y;
|
||||
ny = U.z*V.x - U.x*V.z;
|
||||
nz = U.x*V.y - U.y*V.x;
|
||||
len = sqrt(nx*nx+ny*ny+nz*nz);
|
||||
W.x = nx/len; W.y = ny/len; W.z = nz/len;
|
||||
}
|
||||
return W;
|
||||
}
|
||||
|
||||
double DECL::EdgeAngle(int edge)
|
||||
{
|
||||
double angle;
|
||||
double dotprod;
|
||||
Point P,Q,R; // triangle vertices
|
||||
Point U,V,W; // normal vectors
|
||||
int e2 = halfedge.next(edge);
|
||||
int e3 = halfedge.next(e2);
|
||||
P=vertex.coords(halfedge.v1(edge));
|
||||
Q=vertex.coords(halfedge.v1(e2));
|
||||
R=vertex.coords(halfedge.v1(e3));
|
||||
U = TriNormal(edge);
|
||||
V = TriNormal(halfedge.twin(edge));
|
||||
if (halfedge.twin(edge) < 0 ){
|
||||
// compute edge normal in plane of cube face
|
||||
W = P - Q; // edge tangent vector
|
||||
double length = sqrt(W.x*W.x+W.y*W.y+W.z*W.z);
|
||||
W.x /= length;
|
||||
W.y /= length;
|
||||
W.z /= length;
|
||||
// edge normal within the plane of the cube face
|
||||
double nx = W.y*V.z - W.z*V.y;
|
||||
double ny = W.z*V.x - W.x*V.z;
|
||||
double nz = W.x*V.y - W.y*V.x;
|
||||
length = sqrt(nx*nx+ny*ny+nz*nz);
|
||||
// new value for V is this normal vector
|
||||
V.x = nx/length; V.y = ny/length; V.z = nz/length;
|
||||
dotprod = U.x*V.x + U.y*V.y + U.z*V.z;
|
||||
if (dotprod < 0.f){
|
||||
//printf("negative dot product on face\n");
|
||||
dotprod=-dotprod;
|
||||
V.x = -V.x; V.y = -V.y; V.z = -V.z;
|
||||
}
|
||||
|
||||
if (dotprod > 1.f) dotprod=1.f;
|
||||
if (dotprod < -1.f) dotprod=-1.f;
|
||||
angle = acos(dotprod);
|
||||
/* project onto plane of cube face also works
|
||||
if (dotprod > 1.f)
|
||||
dotprod = 1.f;
|
||||
if (dotprod < -1.f)
|
||||
dotprod = -1.f;
|
||||
angle = acos(dotprod);
|
||||
/* project onto plane of cube face also works
|
||||
W = U - dotprod*V;
|
||||
length = sqrt(W.x*W.x+W.y*W.y+W.z*W.z); // for normalization
|
||||
dotprod = (U.x*W.x + U.y*W.y + U.z*W.z)/length;
|
||||
|
@ -339,71 +379,75 @@ double DECL::EdgeAngle(int edge)
|
|||
if (dotprod < -1.f) dotprod=-1.f;
|
||||
angle = acos(dotprod);
|
||||
*/
|
||||
}
|
||||
else{
|
||||
dotprod=U.x*V.x + U.y*V.y + U.z*V.z;
|
||||
if (dotprod > 1.f) dotprod=1.f;
|
||||
if (dotprod < -1.f) dotprod=-1.f;
|
||||
angle = 0.5*acos(dotprod);
|
||||
}
|
||||
// determine if angle is concave or convex based on edge normal
|
||||
W.x = (P.y-Q.y)*U.z - (P.z-Q.z)*U.y;
|
||||
W.y = (P.z-Q.z)*U.x - (P.x-Q.x)*U.z;
|
||||
W.z = (P.x-Q.x)*U.y - (P.y-Q.y)*U.x;
|
||||
//length = sqrt(nx*nx+ny*ny+nz*nz);
|
||||
Point w=0.5*(P+Q)-R;
|
||||
if (W.x*w.x + W.y*w.y + W.z*w.z < 0.f){
|
||||
//printf("flip edge normal \n");
|
||||
W.x = -W.x;
|
||||
W.y = -W.y;
|
||||
W.z = -W.z;
|
||||
}
|
||||
if (W.x*V.x + W.y*V.y + W.z*V.z > 0.f){
|
||||
// concave
|
||||
angle = -angle;
|
||||
}
|
||||
if (angle != angle) angle = 0.0;
|
||||
//printf("angle=%f,dot=%f (Edge=%i, twin=%i): P={%f, %f, %f}, Q={%f, %f, %f} U={%f, %f, %f}, V={%f, %f, %f}\n",angle,dotprod,edge,halfedge.twin(edge),P.x,P.y,P.z,Q.x,Q.y,Q.z,U.x,U.y,U.z,V.x,V.y,V.z);
|
||||
return angle;
|
||||
}
|
||||
|
||||
void iso_surface(const Array<double>&Field, const double isovalue)
|
||||
{
|
||||
DECL object;
|
||||
int e1,e2,e3;
|
||||
FILE *TRIANGLES;
|
||||
TRIANGLES = fopen("isosurface.stl","w");
|
||||
fprintf(TRIANGLES,"solid isosurface\n");
|
||||
int Nx = Field.size(0);
|
||||
int Ny = Field.size(1);
|
||||
int Nz = Field.size(2);
|
||||
for (int k=1; k<Nz-1; k++){
|
||||
for (int j=1; j<Ny-1; j++){
|
||||
for (int i=1; i<Nx-1; i++){
|
||||
object.LocalIsosurface(Field,isovalue,i,j,k);
|
||||
for (int idx=0; idx<object.TriangleCount; idx++){
|
||||
e1 = object.Face(idx);
|
||||
e2 = object.halfedge.next(e1);
|
||||
e3 = object.halfedge.next(e2);
|
||||
auto P1 = object.vertex.coords(object.halfedge.v1(e1));
|
||||
auto P2 = object.vertex.coords(object.halfedge.v1(e2));
|
||||
auto P3 = object.vertex.coords(object.halfedge.v1(e3));
|
||||
auto Normal = object.TriNormal(e1);
|
||||
// P1.x += 1.0*i; P1.y += 1.0*j; P1.z +=1.0*k;
|
||||
//P2.x += 1.0*i; P2.y += 1.0*j; P2.z +=1.0*k;
|
||||
//P3.x += 1.0*i; P3.y += 1.0*j; P3.z +=1.0*k;
|
||||
fprintf(TRIANGLES,"facet normal %f %f %f\n",Normal.x,Normal.y,Normal.z);
|
||||
fprintf(TRIANGLES," outer loop\n");
|
||||
fprintf(TRIANGLES," vertex %f %f %f\n",P1.x,P1.y,P1.z);
|
||||
fprintf(TRIANGLES," vertex %f %f %f\n",P2.x,P2.y,P2.z);
|
||||
fprintf(TRIANGLES," vertex %f %f %f\n",P3.x,P3.y,P3.z);
|
||||
fprintf(TRIANGLES," endloop\n");
|
||||
fprintf(TRIANGLES,"endfacet\n");
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dotprod = U.x * V.x + U.y * V.y + U.z * V.z;
|
||||
if (dotprod > 1.f)
|
||||
dotprod = 1.f;
|
||||
if (dotprod < -1.f)
|
||||
dotprod = -1.f;
|
||||
angle = 0.5 * acos(dotprod);
|
||||
}
|
||||
}
|
||||
fprintf(TRIANGLES,"endsolid isosurface\n");
|
||||
fclose(TRIANGLES);
|
||||
// determine if angle is concave or convex based on edge normal
|
||||
W.x = (P.y - Q.y) * U.z - (P.z - Q.z) * U.y;
|
||||
W.y = (P.z - Q.z) * U.x - (P.x - Q.x) * U.z;
|
||||
W.z = (P.x - Q.x) * U.y - (P.y - Q.y) * U.x;
|
||||
//length = sqrt(nx*nx+ny*ny+nz*nz);
|
||||
Point w = 0.5 * (P + Q) - R;
|
||||
if (W.x * w.x + W.y * w.y + W.z * w.z < 0.f) {
|
||||
//printf("flip edge normal \n");
|
||||
W.x = -W.x;
|
||||
W.y = -W.y;
|
||||
W.z = -W.z;
|
||||
}
|
||||
if (W.x * V.x + W.y * V.y + W.z * V.z > 0.f) {
|
||||
// concave
|
||||
angle = -angle;
|
||||
}
|
||||
if (angle != angle)
|
||||
angle = 0.0;
|
||||
//printf("angle=%f,dot=%f (Edge=%i, twin=%i): P={%f, %f, %f}, Q={%f, %f, %f} U={%f, %f, %f}, V={%f, %f, %f}\n",angle,dotprod,edge,halfedge.twin(edge),P.x,P.y,P.z,Q.x,Q.y,Q.z,U.x,U.y,U.z,V.x,V.y,V.z);
|
||||
return angle;
|
||||
}
|
||||
|
||||
void iso_surface(const Array<double> &Field, const double isovalue) {
|
||||
DCEL object;
|
||||
int e1, e2, e3;
|
||||
FILE *TRIANGLES;
|
||||
TRIANGLES = fopen("isosurface.stl", "w");
|
||||
fprintf(TRIANGLES, "solid isosurface\n");
|
||||
int Nx = Field.size(0);
|
||||
int Ny = Field.size(1);
|
||||
int Nz = Field.size(2);
|
||||
for (int k = 1; k < Nz - 1; k++) {
|
||||
for (int j = 1; j < Ny - 1; j++) {
|
||||
for (int i = 1; i < Nx - 1; i++) {
|
||||
object.LocalIsosurface(Field, isovalue, i, j, k);
|
||||
for (int idx = 0; idx < object.TriangleCount; idx++) {
|
||||
e1 = object.Face(idx);
|
||||
e2 = object.halfedge.next(e1);
|
||||
e3 = object.halfedge.next(e2);
|
||||
auto P1 = object.vertex.coords(object.halfedge.v1(e1));
|
||||
auto P2 = object.vertex.coords(object.halfedge.v1(e2));
|
||||
auto P3 = object.vertex.coords(object.halfedge.v1(e3));
|
||||
auto Normal = object.TriNormal(e1);
|
||||
// P1.x += 1.0*i; P1.y += 1.0*j; P1.z +=1.0*k;
|
||||
//P2.x += 1.0*i; P2.y += 1.0*j; P2.z +=1.0*k;
|
||||
//P3.x += 1.0*i; P3.y += 1.0*j; P3.z +=1.0*k;
|
||||
fprintf(TRIANGLES, "facet normal %f %f %f\n", Normal.x,
|
||||
Normal.y, Normal.z);
|
||||
fprintf(TRIANGLES, " outer loop\n");
|
||||
fprintf(TRIANGLES, " vertex %f %f %f\n", P1.x, P1.y,
|
||||
P1.z);
|
||||
fprintf(TRIANGLES, " vertex %f %f %f\n", P2.x, P2.y,
|
||||
P2.z);
|
||||
fprintf(TRIANGLES, " vertex %f %f %f\n", P3.x, P3.y,
|
||||
P3.z);
|
||||
fprintf(TRIANGLES, " endloop\n");
|
||||
fprintf(TRIANGLES, "endfacet\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(TRIANGLES, "endsolid isosurface\n");
|
||||
fclose(TRIANGLES);
|
||||
}
|
||||
|
|
110
analysis/dcel.h
110
analysis/dcel.h
|
@ -4,85 +4,91 @@
|
|||
#include <vector>
|
||||
#include "analysis/pmmc.h"
|
||||
|
||||
/*
|
||||
Doubly-connected edge list (DECL)
|
||||
/**
|
||||
* \class Vertex
|
||||
* @brief store vertex for DCEL data structure
|
||||
*/
|
||||
|
||||
// Vertex structure
|
||||
class Vertex{
|
||||
class Vertex {
|
||||
public:
|
||||
Vertex() { d_data.resize(12); }
|
||||
~Vertex() = default;
|
||||
Vertex( const Vertex& ) = delete;
|
||||
Vertex operator=( const Vertex& ) = delete;
|
||||
Vertex() { d_data.resize(12); }
|
||||
~Vertex() = default;
|
||||
Vertex(const Vertex &) = delete;
|
||||
Vertex operator=(const Vertex &) = delete;
|
||||
|
||||
// Add/assign a point
|
||||
inline void add( const Point& P ) { d_data.push_back( P ); }
|
||||
inline void assign( int idx, const Point& P ) { d_data[idx] = P; }
|
||||
inline void add(const Point &P) { d_data.push_back(P); }
|
||||
inline void assign(int idx, const Point &P) { d_data[idx] = P; }
|
||||
|
||||
// Get a point
|
||||
inline Point& coords( int idx ) { return d_data[idx]; }
|
||||
inline const Point& coords( int idx ) const { return d_data[idx]; }
|
||||
inline Point &coords(int idx) { return d_data[idx]; }
|
||||
inline const Point &coords(int idx) const { return d_data[idx]; }
|
||||
|
||||
int IncidentEdge();
|
||||
int IncidentEdge();
|
||||
|
||||
// Return the number of points
|
||||
inline int size() const { return d_data.size(); }
|
||||
inline int size() const { return d_data.size(); }
|
||||
|
||||
private:
|
||||
std::vector<Point> d_data;
|
||||
std::vector<Point> d_data;
|
||||
};
|
||||
|
||||
|
||||
// Halfedge structure
|
||||
// Face
|
||||
class Halfedge{
|
||||
/**
|
||||
* \class Halfedge
|
||||
* @brief store half edge for DCEL data structure
|
||||
*/
|
||||
class Halfedge {
|
||||
public:
|
||||
Halfedge() = default;
|
||||
~Halfedge() = default;
|
||||
Halfedge( const Halfedge& ) = delete;
|
||||
Halfedge operator=( const Halfedge& ) = delete;
|
||||
Halfedge() = default;
|
||||
~Halfedge() = default;
|
||||
Halfedge(const Halfedge &) = delete;
|
||||
Halfedge operator=(const Halfedge &) = delete;
|
||||
|
||||
inline int v1(int edge) const { return d_data[edge][0]; }
|
||||
inline int v2(int edge) const { return d_data[edge][1]; }
|
||||
inline int face(int edge) const { return d_data[edge][2]; }
|
||||
inline int twin(int edge) const { return d_data[edge][3]; }
|
||||
inline int prev(int edge) const { return d_data[edge][4]; }
|
||||
inline int next(int edge) const { return d_data[edge][5]; }
|
||||
inline int v1(int edge) const { return d_data[edge][0]; }
|
||||
inline int v2(int edge) const { return d_data[edge][1]; }
|
||||
inline int face(int edge) const { return d_data[edge][2]; }
|
||||
inline int twin(int edge) const { return d_data[edge][3]; }
|
||||
inline int prev(int edge) const { return d_data[edge][4]; }
|
||||
inline int next(int edge) const { return d_data[edge][5]; }
|
||||
|
||||
inline int size() const { return d_data.size(); }
|
||||
inline void resize( int N ) { d_data.resize( N ); }
|
||||
inline int size() const { return d_data.size(); }
|
||||
inline void resize(int N) { d_data.resize(N); }
|
||||
|
||||
inline int& data( int i, int j ) { return d_data[j][i]; }
|
||||
inline const int& data( int i, int j ) const { return d_data[j][i]; }
|
||||
inline int &data(int i, int j) { return d_data[j][i]; }
|
||||
inline const int &data(int i, int j) const { return d_data[j][i]; }
|
||||
|
||||
private:
|
||||
std::vector<std::array<int,6>> d_data;
|
||||
std::vector<std::array<int, 6>> d_data;
|
||||
};
|
||||
|
||||
// DECL
|
||||
class DECL{
|
||||
/**
|
||||
* \class DCEL
|
||||
* @details doubly connected edge list data structure
|
||||
*/
|
||||
class DCEL {
|
||||
public:
|
||||
DECL();
|
||||
~DECL();
|
||||
|
||||
int face();
|
||||
Vertex vertex;
|
||||
Halfedge halfedge;
|
||||
void LocalIsosurface(const DoubleArray& A, double value, int i, int j, int k);
|
||||
void Write();
|
||||
int Face(int index);
|
||||
|
||||
double origin(int edge);
|
||||
double EdgeAngle(int edge);
|
||||
Point TriNormal(int edge);
|
||||
int TriangleCount;
|
||||
int VertexCount;
|
||||
DCEL();
|
||||
~DCEL();
|
||||
|
||||
int face();
|
||||
Vertex vertex;
|
||||
Halfedge halfedge;
|
||||
void LocalIsosurface(const DoubleArray &A, double value, int i, int j,
|
||||
int k);
|
||||
void Write();
|
||||
int Face(int index);
|
||||
|
||||
double origin(int edge);
|
||||
double EdgeAngle(int edge);
|
||||
Point TriNormal(int edge);
|
||||
int TriangleCount;
|
||||
int VertexCount;
|
||||
|
||||
private:
|
||||
std::vector<int> FaceData;
|
||||
std::vector<int> FaceData;
|
||||
};
|
||||
|
||||
void iso_surface(const Array<double>&Field, const double isovalue);
|
||||
void iso_surface(const Array<double> &Field, const double isovalue);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,38 +1,52 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "analysis/distance.h"
|
||||
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* A fast distance calculation *
|
||||
******************************************************************/
|
||||
template<class TYPE>
|
||||
void CalcDist( Array<TYPE> &Distance, const Array<char> &ID, const Domain &Dm,
|
||||
const std::array<bool,3>& periodic, const std::array<double,3>& dx )
|
||||
{
|
||||
ASSERT( Distance.size() == ID.size() );
|
||||
std::array<int,3> n = { Dm.Nx-2, Dm.Ny-2, Dm.Nz-2 };
|
||||
fillHalo<int> fillData( Dm.Comm, Dm.rank_info, n, {1,1,1}, 50, 1, {true,false,false}, periodic );
|
||||
template <class TYPE>
|
||||
void CalcDist(Array<TYPE> &Distance, const Array<char> &ID, const Domain &Dm,
|
||||
const std::array<bool, 3> &periodic,
|
||||
const std::array<double, 3> &dx) {
|
||||
ASSERT(Distance.size() == ID.size());
|
||||
std::array<int, 3> n = {Dm.Nx - 2, Dm.Ny - 2, Dm.Nz - 2};
|
||||
fillHalo<int> fillData(Dm.Comm, Dm.rank_info, n, {1, 1, 1}, 50, 1,
|
||||
{true, false, false}, periodic);
|
||||
Array<int> id(ID.size());
|
||||
Array<Vec> vecDist(Distance.size());
|
||||
for (size_t i=0; i<ID.length(); i++)
|
||||
id(i) = ID(i) == 0 ? -1:1;
|
||||
fillData.fill( id );
|
||||
CalcVecDist( vecDist, id, Dm, periodic, dx );
|
||||
for (size_t i=0; i<Distance.length(); i++)
|
||||
Distance(i) = id(i)*vecDist(i).norm();
|
||||
for (size_t i = 0; i < ID.length(); i++)
|
||||
id(i) = ID(i) == 0 ? -1 : 1;
|
||||
fillData.fill(id);
|
||||
CalcVecDist(vecDist, id, Dm, periodic, dx);
|
||||
for (size_t i = 0; i < Distance.length(); i++)
|
||||
Distance(i) = id(i) * vecDist(i).norm();
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Vector-based distance calculation *
|
||||
* Initialize cells adjacent to boundaries *
|
||||
******************************************************************/
|
||||
static void calcVecInitialize( Array<Vec> &d, const Array<int> &ID, double dx, double dy, double dz )
|
||||
{
|
||||
d.fill( Vec( 1e50, 1e50, 1e50 ) );
|
||||
const double dx0 = 0.5*dx;
|
||||
const double dy0 = 0.5*dy;
|
||||
const double dz0 = 0.5*dz;
|
||||
static void calcVecInitialize(Array<Vec> &d, const Array<int> &ID, double dx,
|
||||
double dy, double dz) {
|
||||
d.fill(Vec(1e50, 1e50, 1e50));
|
||||
const double dx0 = 0.5 * dx;
|
||||
const double dy0 = 0.5 * dy;
|
||||
const double dz0 = 0.5 * dz;
|
||||
//const double dxy0 = 0.25*sqrt( dx*dx + dy*dy );
|
||||
//const double dxz0 = 0.25*sqrt( dx*dx + dz*dz );
|
||||
//const double dyz0 = 0.25*sqrt( dy*dy + dz*dz );
|
||||
|
@ -40,19 +54,25 @@ static void calcVecInitialize( Array<Vec> &d, const Array<int> &ID, double dx, d
|
|||
int Nx = d.size(0);
|
||||
int Ny = d.size(1);
|
||||
int Nz = d.size(2);
|
||||
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 id = ID(i,j,k);
|
||||
bool x[2] = { id != ID(i-1,j,k), id != ID(i+1,j,k) };
|
||||
bool y[2] = { id != ID(i,j-1,k), id != ID(i,j+1,k) };
|
||||
bool z[2] = { id != ID(i,j,k-1), id != ID(i,j,k+1) };
|
||||
if ( x[0] ) d(i,j,k) = Vec( dx0, 0, 0 );
|
||||
if ( x[1] ) d(i,j,k) = Vec( -dx0, 0, 0 );
|
||||
if ( y[0] ) d(i,j,k) = Vec( 0, dy0, 0 );
|
||||
if ( y[1] ) d(i,j,k) = Vec( 0, -dy0, 0 );
|
||||
if ( z[0] ) d(i,j,k) = Vec( 0, 0, dz0 );
|
||||
if ( z[1] ) d(i,j,k) = Vec( 0, 0, -dz0 );
|
||||
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 id = ID(i, j, k);
|
||||
bool x[2] = {id != ID(i - 1, j, k), id != ID(i + 1, j, k)};
|
||||
bool y[2] = {id != ID(i, j - 1, k), id != ID(i, j + 1, k)};
|
||||
bool z[2] = {id != ID(i, j, k - 1), id != ID(i, j, k + 1)};
|
||||
if (x[0])
|
||||
d(i, j, k) = Vec(dx0, 0, 0);
|
||||
if (x[1])
|
||||
d(i, j, k) = Vec(-dx0, 0, 0);
|
||||
if (y[0])
|
||||
d(i, j, k) = Vec(0, dy0, 0);
|
||||
if (y[1])
|
||||
d(i, j, k) = Vec(0, -dy0, 0);
|
||||
if (z[0])
|
||||
d(i, j, k) = Vec(0, 0, dz0);
|
||||
if (z[1])
|
||||
d(i, j, k) = Vec(0, 0, -dz0);
|
||||
/*if ( x[0] && y[0] ) d(i,j,k) = Vec( dxy0, dxy0, 0 );
|
||||
if ( x[0] && y[1] ) d(i,j,k) = Vec( dxy0, -dxy0, 0 );
|
||||
if ( x[1] && y[0] ) d(i,j,k) = Vec( -dxy0, dxy0, 0 );
|
||||
|
@ -68,56 +88,54 @@ static void calcVecInitialize( Array<Vec> &d, const Array<int> &ID, double dx, d
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Vector-based distance calculation *
|
||||
* Update interior cells *
|
||||
******************************************************************/
|
||||
static double calcVecUpdateInterior( Array<Vec> &d, double dx, double dy, double dz )
|
||||
{
|
||||
static double calcVecUpdateInterior(Array<Vec> &d, double dx, double dy,
|
||||
double dz) {
|
||||
double err = 0;
|
||||
int Nx = d.size(0);
|
||||
int Ny = d.size(1);
|
||||
int Nz = d.size(2);
|
||||
// Propagate (+,+,+)
|
||||
for (int k=1; k<Nz; k++) {
|
||||
for (int j=1; j<Ny; j++) {
|
||||
for (int i=1; i<Nx; i++) {
|
||||
auto vx = d(i-1,j,k);
|
||||
auto vy = d(i,j-1,k);
|
||||
auto vz = d(i,j,k-1);
|
||||
for (int k = 1; k < Nz; k++) {
|
||||
for (int j = 1; j < Ny; j++) {
|
||||
for (int i = 1; i < Nx; i++) {
|
||||
auto vx = d(i - 1, j, k);
|
||||
auto vy = d(i, j - 1, k);
|
||||
auto vz = d(i, j, k - 1);
|
||||
vx.x += dx;
|
||||
vy.y += dy;
|
||||
vz.z += dz;
|
||||
auto v = std::min( std::min(vx,vy), vz );
|
||||
auto v = std::min(std::min(vx, vy), vz);
|
||||
double d1 = v.norm2();
|
||||
double d2 = d(i,j,k).norm2();
|
||||
if ( d1 < d2 ) {
|
||||
d(i,j,k) = v;
|
||||
err = std::max( err, sqrt(d2)-sqrt(d1) );
|
||||
double d2 = d(i, j, k).norm2();
|
||||
if (d1 < d2) {
|
||||
d(i, j, k) = v;
|
||||
err = std::max(err, sqrt(d2) - sqrt(d1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Propagate (-,-,-)
|
||||
for (int k=Nz-2; k>=0; k--) {
|
||||
for (int j=Ny-2; j>=0; j--) {
|
||||
for (int i=Nx-2; i>=0; i--) {
|
||||
auto vx = d(i+1,j,k);
|
||||
auto vy = d(i,j+1,k);
|
||||
auto vz = d(i,j,k+1);
|
||||
for (int k = Nz - 2; k >= 0; k--) {
|
||||
for (int j = Ny - 2; j >= 0; j--) {
|
||||
for (int i = Nx - 2; i >= 0; i--) {
|
||||
auto vx = d(i + 1, j, k);
|
||||
auto vy = d(i, j + 1, k);
|
||||
auto vz = d(i, j, k + 1);
|
||||
vx.x -= dx;
|
||||
vy.y -= dy;
|
||||
vz.z -= dz;
|
||||
auto v = std::min( std::min(vx,vy), vz );
|
||||
auto v = std::min(std::min(vx, vy), vz);
|
||||
double d1 = v.norm2();
|
||||
double d2 = d(i,j,k).norm2();
|
||||
if ( d1 < d2 ) {
|
||||
d(i,j,k) = v;
|
||||
err = std::max( err, sqrt(d2)-sqrt(d1) );
|
||||
double d2 = d(i, j, k).norm2();
|
||||
if (d1 < d2) {
|
||||
d(i, j, k) = v;
|
||||
err = std::max(err, sqrt(d2) - sqrt(d1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,66 +143,68 @@ static double calcVecUpdateInterior( Array<Vec> &d, double dx, double dy, double
|
|||
return err;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Vector-based distance calculation *
|
||||
******************************************************************/
|
||||
void CalcVecDist( Array<Vec> &d, const Array<int> &ID0, const Domain &Dm,
|
||||
const std::array<bool,3>& periodic, const std::array<double,3>& dx )
|
||||
{
|
||||
std::array<int,3> N = { Dm.Nx, Dm.Ny, Dm.Nz };
|
||||
std::array<int,3> n = { Dm.Nx-2, Dm.Ny-2, Dm.Nz-2 };
|
||||
void CalcVecDist(Array<Vec> &d, const Array<int> &ID0, const Domain &Dm,
|
||||
const std::array<bool, 3> &periodic,
|
||||
const std::array<double, 3> &dx) {
|
||||
std::array<int, 3> N = {Dm.Nx, Dm.Ny, Dm.Nz};
|
||||
std::array<int, 3> n = {Dm.Nx - 2, Dm.Ny - 2, Dm.Nz - 2};
|
||||
// Create ID with ghosts
|
||||
Array<int> ID(N[0],N[1],N[2]);
|
||||
fillHalo<int> fillDataID( Dm.Comm, Dm.rank_info, n, {1,1,1}, 50, 1, {true,true,true}, periodic );
|
||||
fillDataID.copy( ID0, ID );
|
||||
Array<int> ID(N[0], N[1], N[2]);
|
||||
fillHalo<int> fillDataID(Dm.Comm, Dm.rank_info, n, {1, 1, 1}, 50, 1,
|
||||
{true, true, true}, periodic);
|
||||
fillDataID.copy(ID0, ID);
|
||||
// Fill ghosts with nearest neighbor
|
||||
for (int k=1; k<N[2]-1; k++) {
|
||||
for (int j=1; j<N[1]-1; j++) {
|
||||
ID(0,j,k) = ID(1,j,k);
|
||||
ID(N[0]-1,j,k) = ID(N[0]-2,j,k);
|
||||
for (int k = 1; k < N[2] - 1; k++) {
|
||||
for (int j = 1; j < N[1] - 1; j++) {
|
||||
ID(0, j, k) = ID(1, j, k);
|
||||
ID(N[0] - 1, j, k) = ID(N[0] - 2, j, k);
|
||||
}
|
||||
}
|
||||
for (int k=1; k<N[2]-1; k++) {
|
||||
for (int i=0; i<N[0]; i++) {
|
||||
ID(i,0,k) = ID(i,1,k);
|
||||
ID(i,N[1]-1,k) = ID(i,N[1]-2,k);
|
||||
for (int k = 1; k < N[2] - 1; k++) {
|
||||
for (int i = 0; i < N[0]; i++) {
|
||||
ID(i, 0, k) = ID(i, 1, k);
|
||||
ID(i, N[1] - 1, k) = ID(i, N[1] - 2, k);
|
||||
}
|
||||
}
|
||||
for (int i=0; i<N[0]; i++) {
|
||||
for (int j=0; j<N[1]; j++) {
|
||||
ID(i,j,0) = ID(i,j,1);
|
||||
ID(i,j,N[2]-1) = ID(i,j,N[2]-2);
|
||||
for (int i = 0; i < N[0]; i++) {
|
||||
for (int j = 0; j < N[1]; j++) {
|
||||
ID(i, j, 0) = ID(i, j, 1);
|
||||
ID(i, j, N[2] - 1) = ID(i, j, N[2] - 2);
|
||||
}
|
||||
}
|
||||
// Communicate ghosts
|
||||
fillDataID.fill( ID );
|
||||
fillDataID.fill(ID);
|
||||
// Create communicator for distance
|
||||
fillHalo<Vec> fillData( Dm.Comm, Dm.rank_info, n, {1,1,1}, 50, 1, {true,false,false}, periodic );
|
||||
fillHalo<Vec> fillData(Dm.Comm, Dm.rank_info, n, {1, 1, 1}, 50, 1,
|
||||
{true, false, false}, periodic);
|
||||
// Calculate the local distances
|
||||
calcVecInitialize( d, ID, dx[0], dx[1], dx[2] );
|
||||
calcVecInitialize(d, ID, dx[0], dx[1], dx[2]);
|
||||
double err = 1e100;
|
||||
double tol = 0.5 * std::min( std::min(dx[0],dx[1]), dx[2] );
|
||||
for (int it=0; it<=50 && err>tol; it++) {
|
||||
err = calcVecUpdateInterior( d, dx[0], dx[1], dx[2] );
|
||||
double tol = 0.5 * std::min(std::min(dx[0], dx[1]), dx[2]);
|
||||
for (int it = 0; it <= 50 && err > tol; it++) {
|
||||
err = calcVecUpdateInterior(d, dx[0], dx[1], dx[2]);
|
||||
}
|
||||
// Calculate the global distances
|
||||
int N_it = Dm.nprocx() + Dm.nprocy() + Dm.nprocz() + 100;
|
||||
for ( int it=0; it<N_it; it++ ) {
|
||||
for (int it = 0; it < N_it; it++) {
|
||||
// Update ghosts
|
||||
fillData.fill( d );
|
||||
fillData.fill(d);
|
||||
// Update distance
|
||||
double err = calcVecUpdateInterior( d, dx[0], dx[1], dx[2] );
|
||||
double err = calcVecUpdateInterior(d, dx[0], dx[1], dx[2]);
|
||||
// Check if we are finished
|
||||
err = Dm.Comm.maxReduce( err );
|
||||
if ( err < tol )
|
||||
err = Dm.Comm.maxReduce(err);
|
||||
if (err < tol)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Explicit instantiations
|
||||
template void CalcDist<float>( Array<float>&, const Array<char>&, const Domain&, const std::array<bool,3>&, const std::array<double,3>& );
|
||||
template void CalcDist<double>( Array<double>&, const Array<char>&, const Domain&, const std::array<bool,3>&, const std::array<double,3>& );
|
||||
|
||||
|
||||
template void CalcDist<float>(Array<float> &, const Array<char> &,
|
||||
const Domain &, const std::array<bool, 3> &,
|
||||
const std::array<double, 3> &);
|
||||
template void CalcDist<double>(Array<double> &, const Array<char> &,
|
||||
const Domain &, const std::array<bool, 3> &,
|
||||
const std::array<double, 3> &);
|
||||
|
|
|
@ -1,21 +1,38 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef Distance_H_INC
|
||||
#define Distance_H_INC
|
||||
|
||||
#include "common/Domain.h"
|
||||
#include "common/Array.hpp"
|
||||
|
||||
|
||||
struct Vec {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
inline Vec(): x(0), y(0), z(0) {}
|
||||
inline Vec( double x_, double y_, double z_ ): x(x_), y(y_), z(z_) {}
|
||||
inline double norm() const { return sqrt(x*x+y*y+z*z); }
|
||||
inline double norm2() const { return x*x+y*y+z*z; }
|
||||
inline Vec() : x(0), y(0), z(0) {}
|
||||
inline Vec(double x_, double y_, double z_) : x(x_), y(y_), z(z_) {}
|
||||
inline double norm() const { return sqrt(x * x + y * y + z * z); }
|
||||
inline double norm2() const { return x * x + y * y + z * z; }
|
||||
};
|
||||
inline bool operator<(const Vec& l, const Vec& r){ return l.x*l.x+l.y*l.y+l.z*l.z < r.x*r.x+r.y*r.y+r.z*r.z; }
|
||||
|
||||
inline bool operator<(const Vec &l, const Vec &r) {
|
||||
return l.x * l.x + l.y * l.y + l.z * l.z <
|
||||
r.x * r.x + r.y * r.y + r.z * r.z;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Calculate the distance using a simple method
|
||||
|
@ -24,10 +41,12 @@ inline bool operator<(const Vec& l, const Vec& r){ return l.x*l.x+l.y*l.y+l.z*l.
|
|||
* @param[in] ID Segmentation id
|
||||
* @param[in] Dm Domain information
|
||||
* @param[in] periodic Directions that are periodic
|
||||
* @param[in] dx Cell size
|
||||
*/
|
||||
template<class TYPE>
|
||||
void CalcDist( Array<TYPE> &Distance, const Array<char> &ID, const Domain &Dm,
|
||||
const std::array<bool,3>& periodic = {true,true,true}, const std::array<double,3>& dx = {1,1,1} );
|
||||
template <class TYPE>
|
||||
void CalcDist(Array<TYPE> &Distance, const Array<char> &ID, const Domain &Dm,
|
||||
const std::array<bool, 3> &periodic = {true, true, true},
|
||||
const std::array<double, 3> &dx = {1, 1, 1});
|
||||
|
||||
/*!
|
||||
* @brief Calculate the distance using a simple method
|
||||
|
@ -36,8 +55,10 @@ void CalcDist( Array<TYPE> &Distance, const Array<char> &ID, const Domain &Dm,
|
|||
* @param[in] ID Domain id
|
||||
* @param[in] Dm Domain information
|
||||
* @param[in] periodic Directions that are periodic
|
||||
* @param[in] dx Cell size
|
||||
*/
|
||||
void CalcVecDist( Array<Vec> &Distance, const Array<int> &ID, const Domain &Dm,
|
||||
const std::array<bool,3>& periodic = {true,true,true}, const std::array<double,3>& dx = {1,1,1} );
|
||||
void CalcVecDist(Array<Vec> &Distance, const Array<int> &ID, const Domain &Dm,
|
||||
const std::array<bool, 3> &periodic = {true, true, true},
|
||||
const std::array<double, 3> &dx = {1, 1, 1});
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,176 +1,198 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "analysis/filters.h"
|
||||
#include "math.h"
|
||||
#include "ProfilerApp.h"
|
||||
|
||||
void Mean3D( const Array<double> &Input, Array<double> &Output )
|
||||
{
|
||||
PROFILE_START("Mean3D");
|
||||
// Perform a 3D Mean filter on Input array
|
||||
int i,j,k;
|
||||
void Mean3D(const Array<double> &Input, Array<double> &Output) {
|
||||
PROFILE_START("Mean3D");
|
||||
// Perform a 3D Mean filter on Input array
|
||||
int i, j, k;
|
||||
|
||||
int Nx = int(Input.size(0));
|
||||
int Ny = int(Input.size(1));
|
||||
int Nz = int(Input.size(2));
|
||||
int Nx = int(Input.size(0));
|
||||
int Ny = int(Input.size(1));
|
||||
int Nz = int(Input.size(2));
|
||||
|
||||
for (k=1; k<Nz-1; k++){
|
||||
for (j=1; j<Ny-1; j++){
|
||||
for (i=1; i<Nx-1; i++){
|
||||
double MeanValue = Input(i,j,k);
|
||||
// next neighbors
|
||||
MeanValue += Input(i+1,j,k)+Input(i,j+1,k)+Input(i,j,k+1)+Input(i-1,j,k)+Input(i,j-1,k)+Input(i,j,k-1);
|
||||
MeanValue += Input(i+1,j+1,k)+Input(i-1,j+1,k)+Input(i+1,j-1,k)+Input(i-1,j-1,k);
|
||||
MeanValue += Input(i+1,j,k+1)+Input(i-1,j,k+1)+Input(i+1,j,k-1)+Input(i-1,j,k-1);
|
||||
MeanValue += Input(i,j+1,k+1)+Input(i,j-1,k+1)+Input(i,j+1,k-1)+Input(i,j-1,k-1);
|
||||
MeanValue += Input(i+1,j+1,k+1)+Input(i-1,j+1,k+1)+Input(i+1,j-1,k+1)+Input(i-1,j-1,k+1);
|
||||
MeanValue += Input(i+1,j+1,k-1)+Input(i-1,j+1,k-1)+Input(i+1,j-1,k-1)+Input(i-1,j-1,k-1);
|
||||
Output(i,j,k) = MeanValue/27.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
PROFILE_STOP("Mean3D");
|
||||
for (k = 1; k < Nz - 1; k++) {
|
||||
for (j = 1; j < Ny - 1; j++) {
|
||||
for (i = 1; i < Nx - 1; i++) {
|
||||
double MeanValue = Input(i, j, k);
|
||||
// next neighbors
|
||||
MeanValue += Input(i + 1, j, k) + Input(i, j + 1, k) +
|
||||
Input(i, j, k + 1) + Input(i - 1, j, k) +
|
||||
Input(i, j - 1, k) + Input(i, j, k - 1);
|
||||
MeanValue += Input(i + 1, j + 1, k) + Input(i - 1, j + 1, k) +
|
||||
Input(i + 1, j - 1, k) + Input(i - 1, j - 1, k);
|
||||
MeanValue += Input(i + 1, j, k + 1) + Input(i - 1, j, k + 1) +
|
||||
Input(i + 1, j, k - 1) + Input(i - 1, j, k - 1);
|
||||
MeanValue += Input(i, j + 1, k + 1) + Input(i, j - 1, k + 1) +
|
||||
Input(i, j + 1, k - 1) + Input(i, j - 1, k - 1);
|
||||
MeanValue +=
|
||||
Input(i + 1, j + 1, k + 1) + Input(i - 1, j + 1, k + 1) +
|
||||
Input(i + 1, j - 1, k + 1) + Input(i - 1, j - 1, k + 1);
|
||||
MeanValue +=
|
||||
Input(i + 1, j + 1, k - 1) + Input(i - 1, j + 1, k - 1) +
|
||||
Input(i + 1, j - 1, k - 1) + Input(i - 1, j - 1, k - 1);
|
||||
Output(i, j, k) = MeanValue / 27.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
PROFILE_STOP("Mean3D");
|
||||
}
|
||||
|
||||
void Med3D( const Array<float> &Input, Array<float> &Output )
|
||||
{
|
||||
PROFILE_START("Med3D");
|
||||
// Perform a 3D Median filter on Input array with specified width
|
||||
int i,j,k,ii,jj,kk;
|
||||
int imin,jmin,kmin,imax,jmax,kmax;
|
||||
void Med3D(const Array<float> &Input, Array<float> &Output) {
|
||||
PROFILE_START("Med3D");
|
||||
// Perform a 3D Median filter on Input array with specified width
|
||||
int i, j, k, ii, jj, kk;
|
||||
int imin, jmin, kmin, imax, jmax, kmax;
|
||||
|
||||
float *List;
|
||||
List=new float[27];
|
||||
float *List;
|
||||
List = new float[27];
|
||||
|
||||
int Nx = int(Input.size(0));
|
||||
int Ny = int(Input.size(1));
|
||||
int Nz = int(Input.size(2));
|
||||
int Nx = int(Input.size(0));
|
||||
int Ny = int(Input.size(1));
|
||||
int Nz = int(Input.size(2));
|
||||
|
||||
for (k=1; k<Nz-1; k++){
|
||||
for (j=1; j<Ny-1; j++){
|
||||
for (i=1; i<Nx-1; i++){
|
||||
for (k = 1; k < Nz - 1; k++) {
|
||||
for (j = 1; j < Ny - 1; j++) {
|
||||
for (i = 1; i < Nx - 1; i++) {
|
||||
|
||||
// Just use a 3x3x3 window (hit recursively if needed)
|
||||
imin = i-1;
|
||||
jmin = j-1;
|
||||
kmin = k-1;
|
||||
imax = i+2;
|
||||
jmax = j+2;
|
||||
kmax = k+2;
|
||||
// Just use a 3x3x3 window (hit recursively if needed)
|
||||
imin = i - 1;
|
||||
jmin = j - 1;
|
||||
kmin = k - 1;
|
||||
imax = i + 2;
|
||||
jmax = j + 2;
|
||||
kmax = k + 2;
|
||||
|
||||
// Populate the list with values in the window
|
||||
int Number=0;
|
||||
for (kk=kmin; kk<kmax; kk++){
|
||||
for (jj=jmin; jj<jmax; jj++){
|
||||
for (ii=imin; ii<imax; ii++){
|
||||
List[Number++] = Input(ii,jj,kk);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort the first 5 entries and return the median
|
||||
for (ii=0; ii<14; ii++){
|
||||
for (jj=ii+1; jj<27; jj++){
|
||||
if (List[jj] < List[ii]){
|
||||
float tmp = List[ii];
|
||||
List[ii] = List[jj];
|
||||
List[jj] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the median
|
||||
Output(i,j,k) = List[13];
|
||||
}
|
||||
}
|
||||
}
|
||||
PROFILE_STOP("Med3D");
|
||||
// Populate the list with values in the window
|
||||
int Number = 0;
|
||||
for (kk = kmin; kk < kmax; kk++) {
|
||||
for (jj = jmin; jj < jmax; jj++) {
|
||||
for (ii = imin; ii < imax; ii++) {
|
||||
List[Number++] = Input(ii, jj, kk);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort the first 5 entries and return the median
|
||||
for (ii = 0; ii < 14; ii++) {
|
||||
for (jj = ii + 1; jj < 27; jj++) {
|
||||
if (List[jj] < List[ii]) {
|
||||
float tmp = List[ii];
|
||||
List[ii] = List[jj];
|
||||
List[jj] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the median
|
||||
Output(i, j, k) = List[13];
|
||||
}
|
||||
}
|
||||
}
|
||||
PROFILE_STOP("Med3D");
|
||||
}
|
||||
|
||||
int NLM3D(const Array<float> &Input, Array<float> &Mean,
|
||||
const Array<float> &Distance, Array<float> &Output, const int d,
|
||||
const float h) {
|
||||
PROFILE_START("NLM3D");
|
||||
// Implemenation of 3D non-local means filter
|
||||
// d determines the width of the search volume
|
||||
// h is a free parameter for non-local means (i.e. 1/sigma^2)
|
||||
// Distance is the signed distance function
|
||||
// If Distance(i,j,k) > THRESHOLD_DIST then don't compute NLM
|
||||
|
||||
int NLM3D( const Array<float> &Input, Array<float> &Mean,
|
||||
const Array<float> &Distance, Array<float> &Output, const int d, const float h)
|
||||
{
|
||||
PROFILE_START("NLM3D");
|
||||
// Implemenation of 3D non-local means filter
|
||||
// d determines the width of the search volume
|
||||
// h is a free parameter for non-local means (i.e. 1/sigma^2)
|
||||
// Distance is the signed distance function
|
||||
// If Distance(i,j,k) > THRESHOLD_DIST then don't compute NLM
|
||||
float THRESHOLD_DIST = float(d);
|
||||
float weight, sum;
|
||||
int i, j, k, ii, jj, kk;
|
||||
int imin, jmin, kmin, imax, jmax, kmax;
|
||||
int returnCount = 0;
|
||||
|
||||
float THRESHOLD_DIST = float(d);
|
||||
float weight, sum;
|
||||
int i,j,k,ii,jj,kk;
|
||||
int imin,jmin,kmin,imax,jmax,kmax;
|
||||
int returnCount=0;
|
||||
int Nx = int(Input.size(0));
|
||||
int Ny = int(Input.size(1));
|
||||
int Nz = int(Input.size(2));
|
||||
|
||||
int Nx = int(Input.size(0));
|
||||
int Ny = int(Input.size(1));
|
||||
int Nz = int(Input.size(2));
|
||||
// Compute the local means
|
||||
for (k = 1; k < Nz - 1; k++) {
|
||||
for (j = 1; j < Ny - 1; j++) {
|
||||
for (i = 1; i < Nx - 1; i++) {
|
||||
|
||||
// Compute the local means
|
||||
for (k=1; k<Nz-1; k++){
|
||||
for (j=1; j<Ny-1; j++){
|
||||
for (i=1; i<Nx-1; i++){
|
||||
imin = std::max(0, i - d);
|
||||
jmin = std::max(0, j - d);
|
||||
kmin = std::max(0, k - d);
|
||||
imax = std::min(Nx - 1, i + d);
|
||||
jmax = std::min(Ny - 1, j + d);
|
||||
kmax = std::min(Nz - 1, k + d);
|
||||
|
||||
imin = std::max(0,i-d);
|
||||
jmin = std::max(0,j-d);
|
||||
kmin = std::max(0,k-d);
|
||||
imax = std::min(Nx-1,i+d);
|
||||
jmax = std::min(Ny-1,j+d);
|
||||
kmax = std::min(Nz-1,k+d);
|
||||
// Populate the list with values in the window
|
||||
sum = 0;
|
||||
weight = 0;
|
||||
for (kk = kmin; kk < kmax; kk++) {
|
||||
for (jj = jmin; jj < jmax; jj++) {
|
||||
for (ii = imin; ii < imax; ii++) {
|
||||
sum += Input(ii, jj, kk);
|
||||
weight++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Populate the list with values in the window
|
||||
sum = 0; weight=0;
|
||||
for (kk=kmin; kk<kmax; kk++){
|
||||
for (jj=jmin; jj<jmax; jj++){
|
||||
for (ii=imin; ii<imax; ii++){
|
||||
sum += Input(ii,jj,kk);
|
||||
weight++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Mean(i, j, k) = sum / weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mean(i,j,k) = sum / weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Compute the non-local means
|
||||
for (k = 1; k < Nz - 1; k++) {
|
||||
for (j = 1; j < Ny - 1; j++) {
|
||||
for (i = 1; i < Nx - 1; i++) {
|
||||
|
||||
// Compute the non-local means
|
||||
for (k=1; k<Nz-1; k++){
|
||||
for (j=1; j<Ny-1; j++){
|
||||
for (i=1; i<Nx-1; i++){
|
||||
if (fabs(Distance(i, j, k)) < THRESHOLD_DIST) {
|
||||
// compute the expensive non-local means
|
||||
sum = 0;
|
||||
weight = 0;
|
||||
|
||||
imin = std::max(0, i - d);
|
||||
jmin = std::max(0, j - d);
|
||||
kmin = std::max(0, k - d);
|
||||
imax = std::min(Nx - 1, i + d);
|
||||
jmax = std::min(Ny - 1, j + d);
|
||||
kmax = std::min(Nz - 1, k + d);
|
||||
|
||||
if (fabs(Distance(i,j,k)) < THRESHOLD_DIST){
|
||||
// compute the expensive non-local means
|
||||
sum = 0; weight=0;
|
||||
for (kk = kmin; kk < kmax; kk++) {
|
||||
for (jj = jmin; jj < jmax; jj++) {
|
||||
for (ii = imin; ii < imax; ii++) {
|
||||
float tmp = Mean(i, j, k) - Mean(ii, jj, kk);
|
||||
sum += exp(-tmp * tmp * h) * Input(ii, jj, kk);
|
||||
weight += exp(-tmp * tmp * h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
imin = std::max(0,i-d);
|
||||
jmin = std::max(0,j-d);
|
||||
kmin = std::max(0,k-d);
|
||||
imax = std::min(Nx-1,i+d);
|
||||
jmax = std::min(Ny-1,j+d);
|
||||
kmax = std::min(Nz-1,k+d);
|
||||
|
||||
for (kk=kmin; kk<kmax; kk++){
|
||||
for (jj=jmin; jj<jmax; jj++){
|
||||
for (ii=imin; ii<imax; ii++){
|
||||
float tmp = Mean(i,j,k) - Mean(ii,jj,kk);
|
||||
sum += exp(-tmp*tmp*h)*Input(ii,jj,kk);
|
||||
weight += exp(-tmp*tmp*h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
returnCount++;
|
||||
//Output(i,j,k) = Mean(i,j,k);
|
||||
Output(i,j,k) = sum / weight;
|
||||
}
|
||||
else{
|
||||
// Just return the mean
|
||||
Output(i,j,k) = Mean(i,j,k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the number of sites where NLM was applied
|
||||
PROFILE_STOP("NLM3D");
|
||||
return returnCount;
|
||||
returnCount++;
|
||||
//Output(i,j,k) = Mean(i,j,k);
|
||||
Output(i, j, k) = sum / weight;
|
||||
} else {
|
||||
// Just return the mean
|
||||
Output(i, j, k) = Mean(i, j, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return the number of sites where NLM was applied
|
||||
PROFILE_STOP("NLM3D");
|
||||
return returnCount;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,22 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef Filters_H_INC
|
||||
#define Filters_H_INC
|
||||
|
||||
|
||||
#include "common/Array.h"
|
||||
|
||||
/*!
|
||||
|
@ -10,7 +25,7 @@
|
|||
* @param[in] Input Input image
|
||||
* @param[out] Output Output image
|
||||
*/
|
||||
void Mean3D( const Array<double> &Input, Array<double> &Output );
|
||||
void Mean3D(const Array<double> &Input, Array<double> &Output);
|
||||
|
||||
/*!
|
||||
* @brief Filter image
|
||||
|
@ -18,17 +33,20 @@ void Mean3D( const Array<double> &Input, Array<double> &Output );
|
|||
* @param[in] Input Input image
|
||||
* @param[out] Output Output image
|
||||
*/
|
||||
void Med3D( const Array<float> &Input, Array<float> &Output );
|
||||
void Med3D(const Array<float> &Input, Array<float> &Output);
|
||||
|
||||
/*!
|
||||
* @brief Filter image
|
||||
* @details This routine performs a non-linear local means filter
|
||||
* @param[in] Input Input image
|
||||
* @param[in] Mean Mean value
|
||||
* @param[in] Distance Distance
|
||||
* @param[out] Output Output image
|
||||
* @param[in] d
|
||||
* @param[in] h
|
||||
*/
|
||||
int NLM3D( const Array<float> &Input, Array<float> &Mean,
|
||||
const Array<float> &Distance, Array<float> &Output, const int d, const float h);
|
||||
|
||||
int NLM3D(const Array<float> &Input, Array<float> &Mean,
|
||||
const Array<float> &Distance, Array<float> &Output, const int d,
|
||||
const float h);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
* Generate a histogram for volumetric, interfacial and common curve properties
|
||||
* copyright 2014, James E. McClure
|
||||
|
@ -5,43 +21,45 @@
|
|||
|
||||
#define HISTOGRAM_RESOLUTION 1000
|
||||
|
||||
struct Histogram{
|
||||
Histogram(double v1, double v2){
|
||||
data = new double[HISTOGRAM_RESOLUTION];
|
||||
minimum = v1;
|
||||
maximum = v2;
|
||||
delta = (maximum-minimum)/HISTOGRAM_RESOLUTION;
|
||||
}
|
||||
~Histogram{
|
||||
delete *data;
|
||||
}
|
||||
double *data;
|
||||
double minimum,maximum,delta;
|
||||
|
||||
// Adds value into the histogram
|
||||
void IncludeValue(double value, double weight){
|
||||
idx = floor((value-min)/delta);
|
||||
if (idx > HISTOGRAM_RESOLUTION) ;
|
||||
else if (idx < 0) ;
|
||||
else data[idx] += weight;
|
||||
}
|
||||
|
||||
// Returns the maximum value in the histogram
|
||||
void GetMax(){
|
||||
max = minimum;
|
||||
for (idx=1; idx<HISTOGRAM_RESOLUTION; idx++){
|
||||
if (data[idx] > max){
|
||||
max = minimum+idx*delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resets the histogram to zero
|
||||
void Reset(){
|
||||
for (idx=0; idx<HISTOGRAM_RESOLUTION; idx++) data[idx] = 0.0;
|
||||
}
|
||||
|
||||
struct Histogram {
|
||||
Histogram(double v1, double v2) {
|
||||
data = new double[HISTOGRAM_RESOLUTION];
|
||||
minimum = v1;
|
||||
maximum = v2;
|
||||
delta = (maximum - minimum) / HISTOGRAM_RESOLUTION;
|
||||
}
|
||||
~Histogram { delete *data; }
|
||||
double *data;
|
||||
double minimum, maximum, delta;
|
||||
|
||||
// Adds value into the histogram
|
||||
void IncludeValue(double value, double weight) {
|
||||
idx = floor((value - min) / delta);
|
||||
if (idx > HISTOGRAM_RESOLUTION)
|
||||
;
|
||||
else if (idx < 0)
|
||||
;
|
||||
else
|
||||
data[idx] += weight;
|
||||
}
|
||||
|
||||
// Returns the maximum value in the histogram
|
||||
void GetMax() {
|
||||
max = minimum;
|
||||
for (idx = 1; idx < HISTOGRAM_RESOLUTION; idx++) {
|
||||
if (data[idx] > max) {
|
||||
max = minimum + idx * delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resets the histogram to zero
|
||||
void Reset() {
|
||||
for (idx = 0; idx < HISTOGRAM_RESOLUTION; idx++)
|
||||
data[idx] = 0.0;
|
||||
}
|
||||
|
||||
private:
|
||||
int idx;
|
||||
double max,min;
|
||||
int idx;
|
||||
double max, min;
|
||||
};
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// These functions mimic the behavior of imfilter in MATLAB
|
||||
#ifndef included_imfilter
|
||||
#define included_imfilter
|
||||
|
@ -6,13 +22,10 @@
|
|||
#include "common/Array.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace imfilter {
|
||||
|
||||
|
||||
//! enum to store the BC type
|
||||
enum class BC { fixed=0, symmetric=1, replicate=2, circular=3 };
|
||||
|
||||
enum class BC { fixed = 0, symmetric = 1, replicate = 2, circular = 3 };
|
||||
|
||||
/*!
|
||||
* @brief N-D filtering of multidimensional images
|
||||
|
@ -31,9 +44,10 @@ enum class BC { fixed=0, symmetric=1, replicate=2, circular=3 };
|
|||
* computed by implicitly assuming the input array is periodic.
|
||||
* @param[in] X The value to use for boundary conditions (only used if boundary==fixed)
|
||||
*/
|
||||
template<class TYPE>
|
||||
Array<TYPE> imfilter( const Array<TYPE>& A, const Array<TYPE>& H, const std::vector<imfilter::BC>& boundary, const TYPE X=0 );
|
||||
|
||||
template <class TYPE>
|
||||
Array<TYPE> imfilter(const Array<TYPE> &A, const Array<TYPE> &H,
|
||||
const std::vector<imfilter::BC> &boundary,
|
||||
const TYPE X = 0);
|
||||
|
||||
/*!
|
||||
* @brief N-D filtering of multidimensional images
|
||||
|
@ -54,11 +68,11 @@ Array<TYPE> imfilter( const Array<TYPE>& A, const Array<TYPE>& H, const std::vec
|
|||
* computed by implicitly assuming the input array is periodic.
|
||||
* @param[in] X The value to use for boundary conditions (only used if boundary==fixed)
|
||||
*/
|
||||
template<class TYPE>
|
||||
Array<TYPE> imfilter( const Array<TYPE>& A, const std::vector<int>& Nh,
|
||||
std::function<TYPE(const Array<TYPE>&)> H,
|
||||
const std::vector<imfilter::BC>& boundary, const TYPE X=0 );
|
||||
|
||||
template <class TYPE>
|
||||
Array<TYPE> imfilter(const Array<TYPE> &A, const std::vector<int> &Nh,
|
||||
std::function<TYPE(const Array<TYPE> &)> H,
|
||||
const std::vector<imfilter::BC> &boundary,
|
||||
const TYPE X = 0);
|
||||
|
||||
/*!
|
||||
* @brief N-D filtering of multidimensional images
|
||||
|
@ -78,10 +92,10 @@ Array<TYPE> imfilter( const Array<TYPE>& A, const std::vector<int>& Nh,
|
|||
* computed by implicitly assuming the input array is periodic.
|
||||
* @param[in] X The value to use for boundary conditions (only used if boundary==fixed)
|
||||
*/
|
||||
template<class TYPE>
|
||||
Array<TYPE> imfilter_separable( const Array<TYPE>& A, const std::vector<Array<TYPE>>& H,
|
||||
const std::vector<imfilter::BC>& boundary, const TYPE X=0 );
|
||||
|
||||
template <class TYPE>
|
||||
Array<TYPE>
|
||||
imfilter_separable(const Array<TYPE> &A, const std::vector<Array<TYPE>> &H,
|
||||
const std::vector<imfilter::BC> &boundary, const TYPE X = 0);
|
||||
|
||||
/*!
|
||||
* @brief N-D filtering of multidimensional images
|
||||
|
@ -89,7 +103,7 @@ Array<TYPE> imfilter_separable( const Array<TYPE>& A, const std::vector<Array<TY
|
|||
* multidimensional filter H. The result B has the same size and class as A.
|
||||
* This version works with separable filters and is more efficient than a single filter.
|
||||
* @param[in] A The input array (Nx,Ny,Nz)
|
||||
* @param[in] H The filter [2*Nhx+1,2*Nhy+1,...]
|
||||
* @param[in] Nh The filter size
|
||||
* @param[in] boundary The boundary conditions to apply (ndim):
|
||||
* fixed - Input array values outside the bounds of the array are
|
||||
* implicitly assumed to have the value X
|
||||
|
@ -101,11 +115,11 @@ Array<TYPE> imfilter_separable( const Array<TYPE>& A, const std::vector<Array<TY
|
|||
* computed by implicitly assuming the input array is periodic.
|
||||
* @param[in] X The value to use for boundary conditions (only used if boundary==fixed)
|
||||
*/
|
||||
template<class TYPE>
|
||||
Array<TYPE> imfilter_separable( const Array<TYPE>& A, const std::vector<int>& Nh,
|
||||
std::vector<std::function<TYPE(const Array<TYPE>&)>> H,
|
||||
const std::vector<imfilter::BC>& boundary, const TYPE X=0 );
|
||||
|
||||
template <class TYPE>
|
||||
Array<TYPE>
|
||||
imfilter_separable(const Array<TYPE> &A, const std::vector<int> &Nh,
|
||||
std::vector<std::function<TYPE(const Array<TYPE> &)>> H,
|
||||
const std::vector<imfilter::BC> &boundary, const TYPE X = 0);
|
||||
|
||||
/*!
|
||||
* @brief N-D filtering of multidimensional images
|
||||
|
@ -114,6 +128,7 @@ Array<TYPE> imfilter_separable( const Array<TYPE>& A, const std::vector<int>& Nh
|
|||
* This version works with separable filters and is more efficient than a single filter.
|
||||
* @param[in] A The input array (Nx,Ny,Nz)
|
||||
* @param[in] H The filter [2*Nhx+1,2*Nhy+1,...]
|
||||
* @param[in] Nh The filter size
|
||||
* @param[in] boundary The boundary conditions to apply (ndim):
|
||||
* fixed - Input array values outside the bounds of the array are
|
||||
* implicitly assumed to have the value X
|
||||
|
@ -125,11 +140,11 @@ Array<TYPE> imfilter_separable( const Array<TYPE>& A, const std::vector<int>& Nh
|
|||
* computed by implicitly assuming the input array is periodic.
|
||||
* @param[in] X The value to use for boundary conditions (only used if boundary==fixed)
|
||||
*/
|
||||
template<class TYPE>
|
||||
Array<TYPE> imfilter_separable( const Array<TYPE>& A, const std::vector<int>& Nh,
|
||||
std::vector<std::function<TYPE(int, const TYPE*)>> H,
|
||||
const std::vector<imfilter::BC>& boundary, const TYPE X=0 );
|
||||
|
||||
template <class TYPE>
|
||||
Array<TYPE>
|
||||
imfilter_separable(const Array<TYPE> &A, const std::vector<int> &Nh,
|
||||
std::vector<std::function<TYPE(int, const TYPE *)>> H,
|
||||
const std::vector<imfilter::BC> &boundary, const TYPE X = 0);
|
||||
|
||||
/**
|
||||
* @brief Create a filter to use with imfilter
|
||||
|
@ -146,14 +161,12 @@ Array<TYPE> imfilter_separable( const Array<TYPE>& A, const std::vector<int>& Nh
|
|||
* A default value of 0.5 is used if not provided.
|
||||
* \param[in] args An optional argument that some of the filters use
|
||||
*/
|
||||
template<class TYPE>
|
||||
Array<TYPE> create_filter( const std::vector<int>& N, const std::string &type, const void *args = NULL );
|
||||
|
||||
|
||||
}
|
||||
template <class TYPE>
|
||||
Array<TYPE> create_filter(const std::vector<int> &N, const std::string &type,
|
||||
const void *args = NULL);
|
||||
|
||||
} // namespace imfilter
|
||||
|
||||
#include "analysis/imfilter.hpp"
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,187 +1,210 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "analysis/imfilter.h"
|
||||
#include "ProfilerApp.h"
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define IMFILTER_INSIST INSIST
|
||||
#define IMFILTER_ASSERT ASSERT
|
||||
#define IMFILTER_ERROR ERROR
|
||||
|
||||
#define IMFILTER_ERROR ERROR
|
||||
|
||||
// Function to convert an index
|
||||
static inline int imfilter_index( int index, const int N, const imfilter::BC bc )
|
||||
{
|
||||
if ( index < 0 || index >= N ) {
|
||||
if ( bc == imfilter::BC::symmetric ) {
|
||||
index = ( 2 * N - index ) % N;
|
||||
} else if ( bc == imfilter::BC::replicate ) {
|
||||
static inline int imfilter_index(int index, const int N,
|
||||
const imfilter::BC bc) {
|
||||
if (index < 0 || index >= N) {
|
||||
if (bc == imfilter::BC::symmetric) {
|
||||
index = (2 * N - index) % N;
|
||||
} else if (bc == imfilter::BC::replicate) {
|
||||
index = index < 0 ? 0 : N - 1;
|
||||
} else if ( bc == imfilter::BC::circular ) {
|
||||
index = ( index + N ) % N;
|
||||
} else if ( bc == imfilter::BC::fixed ) {
|
||||
} else if (bc == imfilter::BC::circular) {
|
||||
index = (index + N) % N;
|
||||
} else if (bc == imfilter::BC::fixed) {
|
||||
index = -1;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
// Function to copy a 1D array and pad with the appropriate BC
|
||||
template<class TYPE>
|
||||
static inline void copy_array( const int N, const int Ns, const int Nh,
|
||||
const TYPE *A, const imfilter::BC BC, const TYPE X, TYPE *B )
|
||||
{
|
||||
template <class TYPE>
|
||||
static inline void copy_array(const int N, const int Ns, const int Nh,
|
||||
const TYPE *A, const imfilter::BC BC,
|
||||
const TYPE X, TYPE *B) {
|
||||
// Fill the center with a memcpy
|
||||
for (int i=0; i<N; i++ )
|
||||
B[i+Nh] = A[i*Ns];
|
||||
for (int i = 0; i < N; i++)
|
||||
B[i + Nh] = A[i * Ns];
|
||||
// Fill the boundaries
|
||||
for (int i=0; i<Nh; i++ ) {
|
||||
int j1 = imfilter_index( -(i+1), N, BC );
|
||||
int j2 = imfilter_index( N+i, N, BC );
|
||||
B[Nh-i-1] = j1==-1 ? X : B[Nh+j1];
|
||||
B[N+Nh+i] = j2==-1 ? X : B[Nh+j2];
|
||||
for (int i = 0; i < Nh; i++) {
|
||||
int j1 = imfilter_index(-(i + 1), N, BC);
|
||||
int j2 = imfilter_index(N + i, N, BC);
|
||||
B[Nh - i - 1] = j1 == -1 ? X : B[Nh + j1];
|
||||
B[N + Nh + i] = j2 == -1 ? X : B[Nh + j2];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* Perform a 1D filter in a single direction *
|
||||
********************************************************/
|
||||
template<class TYPE>
|
||||
static void filter_direction( int Ns, int N, int Ne, int Nh, const TYPE *H,
|
||||
imfilter::BC boundary, TYPE X, TYPE *A )
|
||||
{
|
||||
if ( Nh < 0 )
|
||||
template <class TYPE>
|
||||
static void filter_direction(int Ns, int N, int Ne, int Nh, const TYPE *H,
|
||||
imfilter::BC boundary, TYPE X, TYPE *A) {
|
||||
if (Nh < 0)
|
||||
IMFILTER_ERROR("Invalid filter size");
|
||||
if ( Nh == 0 ) {
|
||||
for (int i=0; i<Ns*N*Ne; i++)
|
||||
if (Nh == 0) {
|
||||
for (int i = 0; i < Ns * N * Ne; i++)
|
||||
A[i] *= H[0];
|
||||
return;
|
||||
}
|
||||
TYPE *tmp = new TYPE[N+2*Nh];
|
||||
for (int j=0; j<Ne; j++) {
|
||||
for (int i=0; i<Ns; i++) {
|
||||
copy_array( N, Ns, Nh, &A[i+j*Ns*N], boundary, X, tmp );
|
||||
for (int k=0; k<N; k++) {
|
||||
TYPE *tmp = new TYPE[N + 2 * Nh];
|
||||
for (int j = 0; j < Ne; j++) {
|
||||
for (int i = 0; i < Ns; i++) {
|
||||
copy_array(N, Ns, Nh, &A[i + j * Ns * N], boundary, X, tmp);
|
||||
for (int k = 0; k < N; k++) {
|
||||
TYPE tmp2 = 0;
|
||||
for (int m=0; m<=2*Nh; m++)
|
||||
tmp2 += H[m] * tmp[k+m];
|
||||
A[i+k*Ns+j*Ns*N] = tmp2;
|
||||
for (int m = 0; m <= 2 * Nh; m++)
|
||||
tmp2 += H[m] * tmp[k + m];
|
||||
A[i + k * Ns + j * Ns * N] = tmp2;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] tmp;
|
||||
}
|
||||
template<class TYPE>
|
||||
static void filter_direction( int Ns, int N, int Ne, int Nh,
|
||||
std::function<TYPE(const Array<TYPE>&)> H, imfilter::BC boundary, TYPE X, TYPE *A )
|
||||
{
|
||||
if ( Nh < 0 )
|
||||
template <class TYPE>
|
||||
static void filter_direction(int Ns, int N, int Ne, int Nh,
|
||||
std::function<TYPE(const Array<TYPE> &)> H,
|
||||
imfilter::BC boundary, TYPE X, TYPE *A) {
|
||||
if (Nh < 0)
|
||||
IMFILTER_ERROR("Invalid filter size");
|
||||
TYPE *tmp = new TYPE[N+2*Nh];
|
||||
Array<TYPE> tmp2(2*Nh+1);
|
||||
for (int j=0; j<Ne; j++) {
|
||||
for (int i=0; i<Ns; i++) {
|
||||
copy_array( N, Ns, Nh, &A[i+j*Ns*N], boundary, X, tmp );
|
||||
for (int k=0; k<N; k++) {
|
||||
for (int m=0; m<=2*Nh; m++)
|
||||
tmp2(m) = tmp[k+m];
|
||||
A[i+k*Ns+j*Ns*N] = H(tmp2);
|
||||
TYPE *tmp = new TYPE[N + 2 * Nh];
|
||||
Array<TYPE> tmp2(2 * Nh + 1);
|
||||
for (int j = 0; j < Ne; j++) {
|
||||
for (int i = 0; i < Ns; i++) {
|
||||
copy_array(N, Ns, Nh, &A[i + j * Ns * N], boundary, X, tmp);
|
||||
for (int k = 0; k < N; k++) {
|
||||
for (int m = 0; m <= 2 * Nh; m++)
|
||||
tmp2(m) = tmp[k + m];
|
||||
A[i + k * Ns + j * Ns * N] = H(tmp2);
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] tmp;
|
||||
}
|
||||
template<class TYPE>
|
||||
static void filter_direction( int Ns, int N, int Ne, int Nh,
|
||||
std::function<TYPE(int, const TYPE*)> H, imfilter::BC boundary, TYPE X, TYPE *A )
|
||||
{
|
||||
if ( Nh < 0 )
|
||||
template <class TYPE>
|
||||
static void filter_direction(int Ns, int N, int Ne, int Nh,
|
||||
std::function<TYPE(int, const TYPE *)> H,
|
||||
imfilter::BC boundary, TYPE X, TYPE *A) {
|
||||
if (Nh < 0)
|
||||
IMFILTER_ERROR("Invalid filter size");
|
||||
TYPE *tmp = new TYPE[N+2*Nh];
|
||||
int Nh2 = 2*Nh+1;
|
||||
for (int j=0; j<Ne; j++) {
|
||||
for (int i=0; i<Ns; i++) {
|
||||
copy_array( N, Ns, Nh, &A[i+j*Ns*N], boundary, X, tmp );
|
||||
for (int k=0; k<N; k++)
|
||||
A[i+k*Ns+j*Ns*N] = H(Nh2,&tmp[k]);
|
||||
TYPE *tmp = new TYPE[N + 2 * Nh];
|
||||
int Nh2 = 2 * Nh + 1;
|
||||
for (int j = 0; j < Ne; j++) {
|
||||
for (int i = 0; i < Ns; i++) {
|
||||
copy_array(N, Ns, Nh, &A[i + j * Ns * N], boundary, X, tmp);
|
||||
for (int k = 0; k < N; k++)
|
||||
A[i + k * Ns + j * Ns * N] = H(Nh2, &tmp[k]);
|
||||
}
|
||||
}
|
||||
delete[] tmp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* Create a filter *
|
||||
********************************************************/
|
||||
template<class TYPE>
|
||||
Array<TYPE> imfilter::create_filter( const std::vector<int>& N0, const std::string &type, const void *args )
|
||||
{
|
||||
template <class TYPE>
|
||||
Array<TYPE> imfilter::create_filter(const std::vector<int> &N0,
|
||||
const std::string &type, const void *args) {
|
||||
std::vector<size_t> N2(N0.size());
|
||||
for (size_t i=0; i<N2.size(); i++)
|
||||
N2[i] = 2*N0[i]+1;
|
||||
for (size_t i = 0; i < N2.size(); i++)
|
||||
N2[i] = 2 * N0[i] + 1;
|
||||
Array<TYPE> h(N2);
|
||||
h.fill(0);
|
||||
if ( type == "average" ) {
|
||||
if (type == "average") {
|
||||
// average
|
||||
h.fill( 1.0 / static_cast<TYPE>( h.length() ) );
|
||||
} else if ( type == "gaussian" ) {
|
||||
h.fill(1.0 / static_cast<TYPE>(h.length()));
|
||||
} else if (type == "gaussian") {
|
||||
// gaussian
|
||||
if ( N0.size() > 3 )
|
||||
IMFILTER_ERROR( "Not implimented for dimensions > 3" );
|
||||
TYPE std[3] = { 0.5, 0.5, 0.5 };
|
||||
if ( args != NULL ) {
|
||||
const TYPE *args2 = reinterpret_cast<const TYPE*>( args );
|
||||
for ( size_t d = 0; d < N0.size(); d++ )
|
||||
std[d] = args2[d];
|
||||
if (N0.size() > 3)
|
||||
IMFILTER_ERROR("Not implimented for dimensions > 3");
|
||||
TYPE std[3] = {0.5, 0.5, 0.5};
|
||||
if (args != NULL) {
|
||||
const TYPE *args2 = reinterpret_cast<const TYPE *>(args);
|
||||
for (size_t d = 0; d < N0.size(); d++)
|
||||
std[d] = args2[d];
|
||||
}
|
||||
auto N = N0;
|
||||
N.resize(3,0);
|
||||
for ( int k = -N[2]; k <= N[2]; k++ ) {
|
||||
for ( int j = -N[1]; j <= N[1]; j++ ) {
|
||||
for ( int i = -N[0]; i <= N[0]; i++ ) {
|
||||
h(i+N[0],j+N[1],k+N[2]) =
|
||||
exp( -i * i / ( 2 * std[0] * std[0] ) ) *
|
||||
exp( -j * j / ( 2 * std[1] * std[1] ) ) *
|
||||
exp( -k * k / ( 2 * std[2] * std[2] ) );
|
||||
N.resize(3, 0);
|
||||
for (int k = -N[2]; k <= N[2]; k++) {
|
||||
for (int j = -N[1]; j <= N[1]; j++) {
|
||||
for (int i = -N[0]; i <= N[0]; i++) {
|
||||
h(i + N[0], j + N[1], k + N[2]) =
|
||||
exp(-i * i / (2 * std[0] * std[0])) *
|
||||
exp(-j * j / (2 * std[1] * std[1])) *
|
||||
exp(-k * k / (2 * std[2] * std[2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
h.scale( 1.0/h.sum() );
|
||||
h.scale(1.0 / h.sum());
|
||||
} else {
|
||||
IMFILTER_ERROR( "Unknown filter" );
|
||||
IMFILTER_ERROR("Unknown filter");
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
// Perform 2-D filtering
|
||||
template<class TYPE>
|
||||
void imfilter_2D( int Nx, int Ny, const TYPE *A, int Nhx, int Nhy, const TYPE *H,
|
||||
imfilter::BC BCx, imfilter::BC BCy, const TYPE X, TYPE *B )
|
||||
{
|
||||
IMFILTER_ASSERT( A != B );
|
||||
PROFILE_START( "imfilter_2D" );
|
||||
memset( B, 0, Nx * Ny * sizeof( TYPE ) );
|
||||
for ( int j1 = 0; j1 < Ny; j1++ ) {
|
||||
for ( int i1 = 0; i1 < Nx; i1++ ) {
|
||||
template <class TYPE>
|
||||
void imfilter_2D(int Nx, int Ny, const TYPE *A, int Nhx, int Nhy, const TYPE *H,
|
||||
imfilter::BC BCx, imfilter::BC BCy, const TYPE X, TYPE *B) {
|
||||
IMFILTER_ASSERT(A != B);
|
||||
PROFILE_START("imfilter_2D");
|
||||
memset(B, 0, Nx * Ny * sizeof(TYPE));
|
||||
for (int j1 = 0; j1 < Ny; j1++) {
|
||||
for (int i1 = 0; i1 < Nx; i1++) {
|
||||
TYPE tmp = 0;
|
||||
if ( i1 >= Nhx && i1 < Nx - Nhx && j1 >= Nhy && j1 < Ny - Nhy ) {
|
||||
if (i1 >= Nhx && i1 < Nx - Nhx && j1 >= Nhy && j1 < Ny - Nhy) {
|
||||
int ijkh = 0;
|
||||
for ( int j2 = j1 - Nhy; j2 <= j1 + Nhy; j2++ ) {
|
||||
for ( int i2 = i1 - Nhx; i2 <= i1 + Nhx; i2++, ijkh++ )
|
||||
for (int j2 = j1 - Nhy; j2 <= j1 + Nhy; j2++) {
|
||||
for (int i2 = i1 - Nhx; i2 <= i1 + Nhx; i2++, ijkh++)
|
||||
tmp += H[ijkh] * A[i2 + j2 * Nx];
|
||||
}
|
||||
} else {
|
||||
int ijkh = 0;
|
||||
for ( int jh = -Nhy; jh <= Nhy; jh++ ) {
|
||||
int j2 = imfilter_index( j1+jh, Ny, BCy );
|
||||
for ( int ih = -Nhx; ih <= Nhx; ih++ ) {
|
||||
int i2 = imfilter_index( i1+ih, Nx, BCx );
|
||||
for (int jh = -Nhy; jh <= Nhy; jh++) {
|
||||
int j2 = imfilter_index(j1 + jh, Ny, BCy);
|
||||
for (int ih = -Nhx; ih <= Nhx; ih++) {
|
||||
int i2 = imfilter_index(i1 + ih, Nx, BCx);
|
||||
bool fixed = i2 == -1 || j2 == -1;
|
||||
TYPE A2 = fixed ? X : A[i2 + j2 * Nx];
|
||||
TYPE A2 = fixed ? X : A[i2 + j2 * Nx];
|
||||
tmp += H[ijkh] * A2;
|
||||
ijkh++;
|
||||
}
|
||||
|
@ -190,32 +213,31 @@ void imfilter_2D( int Nx, int Ny, const TYPE *A, int Nhx, int Nhy, const TYPE *H
|
|||
B[i1 + j1 * Nx] = tmp;
|
||||
}
|
||||
}
|
||||
PROFILE_STOP( "imfilter_2D" );
|
||||
PROFILE_STOP("imfilter_2D");
|
||||
}
|
||||
|
||||
|
||||
// Perform 3-D filtering
|
||||
template<class TYPE>
|
||||
void imfilter_3D( int Nx, int Ny, int Nz, const TYPE *A, int Nhx, int Nhy, int Nhz,
|
||||
const TYPE *H, imfilter::BC BCx, imfilter::BC BCy, imfilter::BC BCz,
|
||||
const TYPE X, TYPE *B )
|
||||
{
|
||||
IMFILTER_ASSERT( A != B );
|
||||
PROFILE_START( "imfilter_3D" );
|
||||
memset( B, 0, Nx * Ny * Nz * sizeof( TYPE ) );
|
||||
for ( int k1 = 0; k1 < Nz; k1++ ) {
|
||||
for ( int j1 = 0; j1 < Ny; j1++ ) {
|
||||
for ( int i1 = 0; i1 < Nx; i1++ ) {
|
||||
template <class TYPE>
|
||||
void imfilter_3D(int Nx, int Ny, int Nz, const TYPE *A, int Nhx, int Nhy,
|
||||
int Nhz, const TYPE *H, imfilter::BC BCx, imfilter::BC BCy,
|
||||
imfilter::BC BCz, const TYPE X, TYPE *B) {
|
||||
IMFILTER_ASSERT(A != B);
|
||||
PROFILE_START("imfilter_3D");
|
||||
memset(B, 0, Nx * Ny * Nz * sizeof(TYPE));
|
||||
for (int k1 = 0; k1 < Nz; k1++) {
|
||||
for (int j1 = 0; j1 < Ny; j1++) {
|
||||
for (int i1 = 0; i1 < Nx; i1++) {
|
||||
TYPE tmp = 0;
|
||||
int ijkh = 0;
|
||||
for ( int kh = -Nhz; kh <= Nhz; kh++ ) {
|
||||
int k2 = imfilter_index( k1+kh, Nz, BCz );
|
||||
for ( int jh = -Nhy; jh <= Nhy; jh++ ) {
|
||||
int j2 = imfilter_index( j1+jh, Ny, BCy );
|
||||
for ( int ih = -Nhx; ih <= Nhx; ih++ ) {
|
||||
int i2 = imfilter_index( i1+ih, Nx, BCx );
|
||||
int ijkh = 0;
|
||||
for (int kh = -Nhz; kh <= Nhz; kh++) {
|
||||
int k2 = imfilter_index(k1 + kh, Nz, BCz);
|
||||
for (int jh = -Nhy; jh <= Nhy; jh++) {
|
||||
int j2 = imfilter_index(j1 + jh, Ny, BCy);
|
||||
for (int ih = -Nhx; ih <= Nhx; ih++) {
|
||||
int i2 = imfilter_index(i1 + ih, Nx, BCx);
|
||||
bool fixed = i2 == -1 || j2 == -1 || k2 == -1;
|
||||
TYPE A2 = fixed ? X : A[i2 + j2 * Nx + k2 * Nx * Ny];
|
||||
TYPE A2 =
|
||||
fixed ? X : A[i2 + j2 * Nx + k2 * Nx * Ny];
|
||||
tmp += H[ijkh] * A2;
|
||||
ijkh++;
|
||||
}
|
||||
|
@ -225,154 +247,155 @@ void imfilter_3D( int Nx, int Ny, int Nz, const TYPE *A, int Nhx, int Nhy, int N
|
|||
}
|
||||
}
|
||||
}
|
||||
PROFILE_STOP( "imfilter_3D" );
|
||||
PROFILE_STOP("imfilter_3D");
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* Perform N-D filtering *
|
||||
********************************************************/
|
||||
template<class TYPE>
|
||||
Array<TYPE> imfilter::imfilter( const Array<TYPE>& A,
|
||||
const Array<TYPE>& H, const std::vector<imfilter::BC>& BC, const TYPE X )
|
||||
{
|
||||
IMFILTER_ASSERT( A.ndim() == H.ndim() );
|
||||
IMFILTER_ASSERT( A.ndim() == BC.size() );
|
||||
template <class TYPE>
|
||||
Array<TYPE> imfilter::imfilter(const Array<TYPE> &A, const Array<TYPE> &H,
|
||||
const std::vector<imfilter::BC> &BC,
|
||||
const TYPE X) {
|
||||
IMFILTER_ASSERT(A.ndim() == H.ndim());
|
||||
IMFILTER_ASSERT(A.ndim() == BC.size());
|
||||
std::vector<size_t> Nh = H.size();
|
||||
for (int d=0; d<A.ndim(); d++) {
|
||||
Nh[d] = (H.size(d)-1)/2;
|
||||
IMFILTER_INSIST(2*Nh[d]+1==H.size(d),"Filter must be of size 2*N+1");
|
||||
for (int d = 0; d < A.ndim(); d++) {
|
||||
Nh[d] = (H.size(d) - 1) / 2;
|
||||
IMFILTER_INSIST(2 * Nh[d] + 1 == H.size(d),
|
||||
"Filter must be of size 2*N+1");
|
||||
}
|
||||
auto B = A;
|
||||
if ( A.ndim() == 1 ) {
|
||||
PROFILE_START( "imfilter_1D" );
|
||||
filter_direction( 1, A.size(0), 1, Nh[0], H.data(), BC[0], X, B.data() );
|
||||
PROFILE_STOP( "imfilter_1D" );
|
||||
} else if ( A.ndim() == 2 ) {
|
||||
imfilter_2D( A.size(0), A.size(1), A.data(), Nh[0], Nh[1], H.data(), BC[0], BC[1], X, B.data() );
|
||||
} else if ( A.ndim() == 3 ) {
|
||||
imfilter_3D( A.size(0), A.size(1), A.size(2), A.data(),
|
||||
Nh[0], Nh[1], Nh[2], H.data(), BC[0], BC[1], BC[2], X, B.data() );
|
||||
if (A.ndim() == 1) {
|
||||
PROFILE_START("imfilter_1D");
|
||||
filter_direction(1, A.size(0), 1, Nh[0], H.data(), BC[0], X, B.data());
|
||||
PROFILE_STOP("imfilter_1D");
|
||||
} else if (A.ndim() == 2) {
|
||||
imfilter_2D(A.size(0), A.size(1), A.data(), Nh[0], Nh[1], H.data(),
|
||||
BC[0], BC[1], X, B.data());
|
||||
} else if (A.ndim() == 3) {
|
||||
imfilter_3D(A.size(0), A.size(1), A.size(2), A.data(), Nh[0], Nh[1],
|
||||
Nh[2], H.data(), BC[0], BC[1], BC[2], X, B.data());
|
||||
} else {
|
||||
IMFILTER_ERROR( "Arbitrary dimension not yet supported" );
|
||||
IMFILTER_ERROR("Arbitrary dimension not yet supported");
|
||||
}
|
||||
return B;
|
||||
}
|
||||
template<class TYPE>
|
||||
Array<TYPE> imfilter::imfilter( const Array<TYPE>& A, const std::vector<int>& Nh0,
|
||||
std::function<TYPE(const Array<TYPE>&)> H,
|
||||
const std::vector<imfilter::BC>& BC0, const TYPE X )
|
||||
{
|
||||
PROFILE_START( "imfilter (lambda)" );
|
||||
IMFILTER_ASSERT( A.ndim() == Nh0.size() );
|
||||
IMFILTER_ASSERT( A.ndim() == BC0.size() );
|
||||
std::vector<size_t> Nh2( A.size() );
|
||||
for (int d=0; d<A.ndim(); d++)
|
||||
Nh2[d] = 2*Nh0[d]+1;
|
||||
template <class TYPE>
|
||||
Array<TYPE>
|
||||
imfilter::imfilter(const Array<TYPE> &A, const std::vector<int> &Nh0,
|
||||
std::function<TYPE(const Array<TYPE> &)> H,
|
||||
const std::vector<imfilter::BC> &BC0, const TYPE X) {
|
||||
PROFILE_START("imfilter (lambda)");
|
||||
IMFILTER_ASSERT(A.ndim() == Nh0.size());
|
||||
IMFILTER_ASSERT(A.ndim() == BC0.size());
|
||||
std::vector<size_t> Nh2(A.size());
|
||||
for (int d = 0; d < A.ndim(); d++)
|
||||
Nh2[d] = 2 * Nh0[d] + 1;
|
||||
auto B = A;
|
||||
Array<TYPE> data(Nh2);
|
||||
IMFILTER_INSIST(A.ndim()<=3,"Not programmed for more than 3 dimensions yet");
|
||||
IMFILTER_INSIST(A.ndim() <= 3,
|
||||
"Not programmed for more than 3 dimensions yet");
|
||||
auto N = A.size();
|
||||
auto Nh = Nh0;
|
||||
auto BC = BC0;
|
||||
N.resize(3,1);
|
||||
Nh.resize(3,0);
|
||||
BC.resize(3,imfilter::BC::fixed);
|
||||
for ( int k1 = 0; k1 < N[2]; k1++ ) {
|
||||
for ( int j1 = 0; j1 < N[1]; j1++ ) {
|
||||
for ( int i1 = 0; i1 < N[0]; i1++ ) {
|
||||
for ( int kh = -Nh[2]; kh <= Nh[2]; kh++ ) {
|
||||
int k2 = imfilter_index( k1+kh, N[2], BC[2] );
|
||||
for ( int jh = -Nh[1]; jh <= Nh[1]; jh++ ) {
|
||||
int j2 = imfilter_index( j1+jh, N[1], BC[1] );
|
||||
for ( int ih = -Nh[0]; ih <= Nh[0]; ih++ ) {
|
||||
int i2 = imfilter_index( i1+ih, N[0], BC[0] );
|
||||
N.resize(3, 1);
|
||||
Nh.resize(3, 0);
|
||||
BC.resize(3, imfilter::BC::fixed);
|
||||
for (int k1 = 0; k1 < N[2]; k1++) {
|
||||
for (int j1 = 0; j1 < N[1]; j1++) {
|
||||
for (int i1 = 0; i1 < N[0]; i1++) {
|
||||
for (int kh = -Nh[2]; kh <= Nh[2]; kh++) {
|
||||
int k2 = imfilter_index(k1 + kh, N[2], BC[2]);
|
||||
for (int jh = -Nh[1]; jh <= Nh[1]; jh++) {
|
||||
int j2 = imfilter_index(j1 + jh, N[1], BC[1]);
|
||||
for (int ih = -Nh[0]; ih <= Nh[0]; ih++) {
|
||||
int i2 = imfilter_index(i1 + ih, N[0], BC[0]);
|
||||
bool fixed = i2 == -1 || j2 == -1 || k2 == -1;
|
||||
data(ih+Nh[0],jh+Nh[1],kh+Nh[2]) = fixed ? X : A(i2,j2,k2);
|
||||
data(ih + Nh[0], jh + Nh[1], kh + Nh[2]) =
|
||||
fixed ? X : A(i2, j2, k2);
|
||||
}
|
||||
}
|
||||
}
|
||||
B(i1,j1,k1) = H( data );
|
||||
B(i1, j1, k1) = H(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
PROFILE_STOP( "imfilter (lambda)" );
|
||||
PROFILE_STOP("imfilter (lambda)");
|
||||
return B;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* imfilter with separable filter functions *
|
||||
********************************************************/
|
||||
template<class TYPE>
|
||||
Array<TYPE> imfilter::imfilter_separable( const Array<TYPE>& A,
|
||||
const std::vector<Array<TYPE>>& H,
|
||||
const std::vector<imfilter::BC>& boundary, const TYPE X )
|
||||
{
|
||||
PROFILE_START( "imfilter_separable" );
|
||||
IMFILTER_ASSERT( A.ndim() == (int) H.size() );
|
||||
IMFILTER_ASSERT( A.ndim() == (int) boundary.size() );
|
||||
std::vector<size_t> Nh( H.size() );
|
||||
for (int d=0; d<A.ndim(); d++) {
|
||||
IMFILTER_ASSERT(H[d].ndim()==1);
|
||||
Nh[d] = (H[d].length()-1)/2;
|
||||
IMFILTER_INSIST(2*Nh[d]+1==H[d].length(),"Filter must be of size 2*N+1");
|
||||
template <class TYPE>
|
||||
Array<TYPE> imfilter::imfilter_separable(
|
||||
const Array<TYPE> &A, const std::vector<Array<TYPE>> &H,
|
||||
const std::vector<imfilter::BC> &boundary, const TYPE X) {
|
||||
PROFILE_START("imfilter_separable");
|
||||
IMFILTER_ASSERT(A.ndim() == (int)H.size());
|
||||
IMFILTER_ASSERT(A.ndim() == (int)boundary.size());
|
||||
std::vector<size_t> Nh(H.size());
|
||||
for (int d = 0; d < A.ndim(); d++) {
|
||||
IMFILTER_ASSERT(H[d].ndim() == 1);
|
||||
Nh[d] = (H[d].length() - 1) / 2;
|
||||
IMFILTER_INSIST(2 * Nh[d] + 1 == H[d].length(),
|
||||
"Filter must be of size 2*N+1");
|
||||
}
|
||||
auto B = A;
|
||||
for ( int d = 0; d < A.ndim(); d++ ) {
|
||||
for (int d = 0; d < A.ndim(); d++) {
|
||||
int N = A.size(d);
|
||||
int Ns = 1;
|
||||
int Ne = 1;
|
||||
for ( int d2 = 0; d2 < d; d2++ )
|
||||
for (int d2 = 0; d2 < d; d2++)
|
||||
Ns *= A.size(d2);
|
||||
for ( int d2 = d+1; d2 < A.ndim(); d2++ )
|
||||
for (int d2 = d + 1; d2 < A.ndim(); d2++)
|
||||
Ne *= A.size(d2);
|
||||
filter_direction( Ns, N, Ne, Nh[d], H[d].data(), boundary[d], X, B.data() );
|
||||
filter_direction(Ns, N, Ne, Nh[d], H[d].data(), boundary[d], X,
|
||||
B.data());
|
||||
}
|
||||
PROFILE_STOP( "imfilter_separable" );
|
||||
PROFILE_STOP("imfilter_separable");
|
||||
return B;
|
||||
}
|
||||
template<class TYPE>
|
||||
Array<TYPE> imfilter::imfilter_separable( const Array<TYPE>& A, const std::vector<int>& Nh,
|
||||
std::vector<std::function<TYPE(const Array<TYPE>&)>> H,
|
||||
const std::vector<imfilter::BC>& boundary, const TYPE X )
|
||||
{
|
||||
PROFILE_START( "imfilter_separable (lambda)" );
|
||||
IMFILTER_ASSERT( A.ndim() == (int) boundary.size() );
|
||||
template <class TYPE>
|
||||
Array<TYPE> imfilter::imfilter_separable(
|
||||
const Array<TYPE> &A, const std::vector<int> &Nh,
|
||||
std::vector<std::function<TYPE(const Array<TYPE> &)>> H,
|
||||
const std::vector<imfilter::BC> &boundary, const TYPE X) {
|
||||
PROFILE_START("imfilter_separable (lambda)");
|
||||
IMFILTER_ASSERT(A.ndim() == (int)boundary.size());
|
||||
auto B = A;
|
||||
for ( int d = 0; d < A.ndim(); d++ ) {
|
||||
for (int d = 0; d < A.ndim(); d++) {
|
||||
int N = A.size(d);
|
||||
int Ns = 1;
|
||||
int Ne = 1;
|
||||
for ( int d2 = 0; d2 < d; d2++ )
|
||||
for (int d2 = 0; d2 < d; d2++)
|
||||
Ns *= A.size(d2);
|
||||
for ( int d2 = d+1; d2 < A.ndim(); d2++ )
|
||||
for (int d2 = d + 1; d2 < A.ndim(); d2++)
|
||||
Ne *= A.size(d2);
|
||||
filter_direction( Ns, N, Ne, Nh[d], H[d], boundary[d], X, B.data() );
|
||||
filter_direction(Ns, N, Ne, Nh[d], H[d], boundary[d], X, B.data());
|
||||
}
|
||||
PROFILE_STOP( "imfilter_separable (lambda)" );
|
||||
PROFILE_STOP("imfilter_separable (lambda)");
|
||||
return B;
|
||||
}
|
||||
template<class TYPE>
|
||||
Array<TYPE> imfilter::imfilter_separable( const Array<TYPE>& A, const std::vector<int>& Nh,
|
||||
std::vector<std::function<TYPE(int, const TYPE*)>> H,
|
||||
const std::vector<imfilter::BC>& boundary, const TYPE X )
|
||||
{
|
||||
PROFILE_START( "imfilter_separable (function)" );
|
||||
IMFILTER_ASSERT( A.ndim() == (int) boundary.size() );
|
||||
template <class TYPE>
|
||||
Array<TYPE> imfilter::imfilter_separable(
|
||||
const Array<TYPE> &A, const std::vector<int> &Nh,
|
||||
std::vector<std::function<TYPE(int, const TYPE *)>> H,
|
||||
const std::vector<imfilter::BC> &boundary, const TYPE X) {
|
||||
PROFILE_START("imfilter_separable (function)");
|
||||
IMFILTER_ASSERT(A.ndim() == (int)boundary.size());
|
||||
auto B = A;
|
||||
for ( int d = 0; d < A.ndim(); d++ ) {
|
||||
for (int d = 0; d < A.ndim(); d++) {
|
||||
int N = A.size(d);
|
||||
int Ns = 1;
|
||||
int Ne = 1;
|
||||
for ( int d2 = 0; d2 < d; d2++ )
|
||||
for (int d2 = 0; d2 < d; d2++)
|
||||
Ns *= A.size(d2);
|
||||
for ( int d2 = d+1; d2 < A.ndim(); d2++ )
|
||||
for (int d2 = d + 1; d2 < A.ndim(); d2++)
|
||||
Ne *= A.size(d2);
|
||||
filter_direction( Ns, N, Ne, Nh[d], H[d], boundary[d], X, B.data() );
|
||||
filter_direction(Ns, N, Ne, Nh[d], H[d], boundary[d], X, B.data());
|
||||
}
|
||||
PROFILE_STOP( "imfilter_separable (function)" );
|
||||
PROFILE_STOP("imfilter_separable (function)");
|
||||
return B;
|
||||
}
|
||||
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,6 +3,120 @@
|
|||
#include "common/Domain.h"
|
||||
#include "analysis/runAnalysis.h"
|
||||
|
||||
double MorphOpen(DoubleArray &SignDist, signed char *id, std::shared_ptr<Domain> Dm, double VoidFraction, signed char ErodeLabel, signed char ReplaceLabel);
|
||||
double MorphDrain(DoubleArray &SignDist, signed char *id, std::shared_ptr<Domain> Dm, double VoidFraction);
|
||||
double MorphGrow(DoubleArray &BoundaryDist, DoubleArray &Dist, Array<char> &id, std::shared_ptr<Domain> Dm, double TargetVol, double WallFactor);
|
||||
double MorphOpen(DoubleArray &SignDist, signed char *id,
|
||||
std::shared_ptr<Domain> Dm, double VoidFraction,
|
||||
signed char ErodeLabel, signed char ReplaceLabel);
|
||||
double MorphDrain(DoubleArray &SignDist, signed char *id,
|
||||
std::shared_ptr<Domain> Dm, double VoidFraction);
|
||||
double MorphGrow(DoubleArray &BoundaryDist, DoubleArray &Dist, Array<char> &id,
|
||||
std::shared_ptr<Domain> Dm, double TargetVol,
|
||||
double WallFactor);
|
||||
|
||||
#ifndef MORPHOLOGY_INC
|
||||
#define MORPHOLOGY_INC
|
||||
/**
|
||||
* \class Morphology
|
||||
* @brief
|
||||
* The Morphology class supports morphological operations on complex structures
|
||||
*
|
||||
*/
|
||||
class Morphology {
|
||||
public:
|
||||
/**
|
||||
* \brief Create a flow adaptor to operate on the LB model
|
||||
*/
|
||||
Morphology();
|
||||
|
||||
/**
|
||||
* \brief Destructor
|
||||
*/
|
||||
~Morphology();
|
||||
|
||||
/**
|
||||
* \brief Initialize morphology structure from distance map
|
||||
* @param Dm Domain structure
|
||||
* @param Distance Signed distance to boundary of structure
|
||||
*/
|
||||
void Initialize(std::shared_ptr<Domain> Dm, DoubleArray &Distance);
|
||||
|
||||
/**
|
||||
* \brief Find all sites such that the reach of the signed distance at the site overlaps with a sub-domain boundary
|
||||
* @param Dm Domain structure
|
||||
* @param id image labels
|
||||
* @param ErodeLabel label to erode based on morphological operation
|
||||
* @param NewLabel label to assign based on morphological operation
|
||||
*/
|
||||
int GetOverlaps(std::shared_ptr<Domain> Dm, signed char *id,
|
||||
const signed char ErodeLabel, const signed char NewLabel);
|
||||
|
||||
/*
|
||||
* data structures to store non-local morphological information
|
||||
*/
|
||||
std::vector<int> xShift, yShift, zShift;
|
||||
std::vector<int> sendID;
|
||||
std::vector<double> morphRadius;
|
||||
std::vector<unsigned char> localID;
|
||||
std::vector<unsigned char> nonlocalID;
|
||||
|
||||
private:
|
||||
int sendtag, recvtag;
|
||||
|
||||
//......................................................................................
|
||||
int sendCount, recvCount;
|
||||
//......................................................................................
|
||||
int sendOffset_x, sendOffset_y, sendOffset_z, sendOffset_X, sendOffset_Y,
|
||||
sendOffset_Z;
|
||||
int sendOffset_xy, sendOffset_yz, sendOffset_xz, sendOffset_Xy,
|
||||
sendOffset_Yz, sendOffset_xZ;
|
||||
int sendOffset_xY, sendOffset_yZ, sendOffset_Xz, sendOffset_XY,
|
||||
sendOffset_YZ, sendOffset_XZ;
|
||||
int sendOffset_xyz, sendOffset_XYZ, sendOffset_xYz, sendOffset_XyZ;
|
||||
int sendOffset_Xyz, sendOffset_xYZ, sendOffset_xyZ, sendOffset_XYz;
|
||||
//......................................................................................
|
||||
int recvOffset_x, recvOffset_y, recvOffset_z, recvOffset_X, recvOffset_Y,
|
||||
recvOffset_Z;
|
||||
int recvOffset_xy, recvOffset_yz, recvOffset_xz, recvOffset_Xy,
|
||||
recvOffset_Yz, recvOffset_xZ;
|
||||
int recvOffset_xY, recvOffset_yZ, recvOffset_Xz, recvOffset_XY,
|
||||
recvOffset_YZ, recvOffset_XZ;
|
||||
int recvOffset_xyz, recvOffset_XYZ, recvOffset_xYz, recvOffset_XyZ;
|
||||
int recvOffset_Xyz, recvOffset_xYZ, recvOffset_xyZ, recvOffset_XYz;
|
||||
//......................................................................................
|
||||
int sendCount_x, sendCount_y, sendCount_z, sendCount_X, sendCount_Y,
|
||||
sendCount_Z;
|
||||
int sendCount_xy, sendCount_yz, sendCount_xz, sendCount_Xy, sendCount_Yz,
|
||||
sendCount_xZ;
|
||||
int sendCount_xY, sendCount_yZ, sendCount_Xz, sendCount_XY, sendCount_YZ,
|
||||
sendCount_XZ;
|
||||
int sendCount_xyz, sendCount_XYZ, sendCount_xYz, sendCount_XyZ;
|
||||
int sendCount_Xyz, sendCount_xYZ, sendCount_xyZ, sendCount_XYz;
|
||||
//......................................................................................
|
||||
int recvCount_x, recvCount_y, recvCount_z, recvCount_X, recvCount_Y,
|
||||
recvCount_Z;
|
||||
int recvCount_xy, recvCount_yz, recvCount_xz, recvCount_Xy, recvCount_Yz,
|
||||
recvCount_xZ;
|
||||
int recvCount_xY, recvCount_yZ, recvCount_Xz, recvCount_XY, recvCount_YZ,
|
||||
recvCount_XZ;
|
||||
int recvCount_xyz, recvCount_XYZ, recvCount_xYz, recvCount_XyZ;
|
||||
int recvCount_Xyz, recvCount_xYZ, recvCount_xyZ, recvCount_XYz;
|
||||
//......................................................................................
|
||||
std::vector<char> sendList;
|
||||
std::vector<char> recvList;
|
||||
//......................................................................................
|
||||
|
||||
// Communication buffers
|
||||
signed char *sendID_x, *sendID_y, *sendID_z, *sendID_X, *sendID_Y,
|
||||
*sendID_Z;
|
||||
signed char *sendID_xy, *sendID_yz, *sendID_xz, *sendID_Xy, *sendID_Yz,
|
||||
*sendID_xZ;
|
||||
signed char *sendID_xY, *sendID_yZ, *sendID_Xz, *sendID_XY, *sendID_YZ,
|
||||
*sendID_XZ;
|
||||
signed char *recvID_x, *recvID_y, *recvID_z, *recvID_X, *recvID_Y,
|
||||
*recvID_Z;
|
||||
signed char *recvID_xy, *recvID_yz, *recvID_xz, *recvID_Xy, *recvID_Yz,
|
||||
*recvID_xZ;
|
||||
signed char *recvID_xY, *recvID_yZ, *recvID_Xz, *recvID_XY, *recvID_YZ,
|
||||
*recvID_XZ;
|
||||
};
|
||||
|
||||
#endif
|
7605
analysis/pmmc.h
7605
analysis/pmmc.h
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef RunAnalysis_H_INC
|
||||
#define RunAnalysis_H_INC
|
||||
|
||||
|
@ -10,42 +26,42 @@
|
|||
#include "models/ColorModel.h"
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
// Types of analysis
|
||||
enum class AnalysisType : uint64_t {
|
||||
AnalyzeNone = 0,
|
||||
IdentifyBlobs = 0x01,
|
||||
AnalyzeNone = 0,
|
||||
IdentifyBlobs = 0x01,
|
||||
CopyPhaseIndicator = 0x02,
|
||||
CopySimState = 0x04,
|
||||
ComputeAverages = 0x08,
|
||||
CreateRestart = 0x10,
|
||||
WriteVis = 0x20,
|
||||
ComputeSubphase = 0x40
|
||||
CopySimState = 0x04,
|
||||
ComputeAverages = 0x08,
|
||||
CreateRestart = 0x10,
|
||||
WriteVis = 0x20,
|
||||
ComputeSubphase = 0x40
|
||||
};
|
||||
|
||||
|
||||
//! Class to run the analysis in multiple threads
|
||||
class runAnalysis
|
||||
{
|
||||
class runAnalysis {
|
||||
public:
|
||||
//! Constructor
|
||||
runAnalysis( std::shared_ptr<Database> db, const RankInfoStruct &rank_info,
|
||||
std::shared_ptr<ScaLBL_Communicator> ScaLBL_Comm, std::shared_ptr<Domain> dm, int Np,
|
||||
bool Regular, IntArray Map );
|
||||
|
||||
runAnalysis( ScaLBL_ColorModel &ColorModel);
|
||||
runAnalysis(std::shared_ptr<Database> db, const RankInfoStruct &rank_info,
|
||||
std::shared_ptr<ScaLBL_Communicator> ScaLBL_Comm,
|
||||
std::shared_ptr<Domain> dm, int Np, bool Regular, IntArray Map);
|
||||
|
||||
runAnalysis(ScaLBL_ColorModel &ColorModel);
|
||||
|
||||
//! Destructor
|
||||
~runAnalysis();
|
||||
|
||||
//! Run the next analysis
|
||||
void run( int timestep, std::shared_ptr<Database> db, TwoPhase &Averages, const double *Phi,
|
||||
double *Pressure, double *Velocity, double *fq, double *Den );
|
||||
void run(int timestep, std::shared_ptr<Database> db, TwoPhase &Averages,
|
||||
const double *Phi, double *Pressure, double *Velocity, double *fq,
|
||||
double *Den);
|
||||
|
||||
void basic( int timestep, std::shared_ptr<Database> db, SubPhase &Averages, const double *Phi,
|
||||
double *Pressure, double *Velocity, double *fq, double *Den );
|
||||
void WriteVisData( int timestep, std::shared_ptr<Database> vis_db, SubPhase &Averages,
|
||||
const double *Phi, double *Pressure, double *Velocity, double *fq, double *Den );
|
||||
void basic(int timestep, std::shared_ptr<Database> db, SubPhase &Averages,
|
||||
const double *Phi, double *Pressure, double *Velocity,
|
||||
double *fq, double *Den);
|
||||
void WriteVisData(int timestep, std::shared_ptr<Database> vis_db,
|
||||
SubPhase &Averages, const double *Phi, double *Pressure,
|
||||
double *Velocity, double *fq, double *Den);
|
||||
|
||||
//! Finish all active analysis
|
||||
void finish();
|
||||
|
@ -64,27 +80,26 @@ public:
|
|||
* that all threads run on independent cores
|
||||
* @param[in] N_threads Number of threads, only used by some of the methods
|
||||
*/
|
||||
void createThreads( const std::string &method = "default", int N_threads = 4 );
|
||||
|
||||
void createThreads(const std::string &method = "default",
|
||||
int N_threads = 4);
|
||||
|
||||
private:
|
||||
runAnalysis();
|
||||
|
||||
// Determine the analysis to perform
|
||||
AnalysisType computeAnalysisType( int timestep );
|
||||
AnalysisType computeAnalysisType(int timestep);
|
||||
|
||||
public:
|
||||
class commWrapper
|
||||
{
|
||||
class commWrapper {
|
||||
public:
|
||||
Utilities::MPI comm;
|
||||
int tag;
|
||||
runAnalysis *analysis;
|
||||
commWrapper( int tag, const Utilities::MPI &comm, runAnalysis *analysis );
|
||||
commWrapper() = delete;
|
||||
commWrapper( const commWrapper &rhs ) = delete;
|
||||
commWrapper &operator=( const commWrapper &rhs ) = delete;
|
||||
commWrapper( commWrapper &&rhs );
|
||||
commWrapper(int tag, const Utilities::MPI &comm, runAnalysis *analysis);
|
||||
commWrapper() = delete;
|
||||
commWrapper(const commWrapper &rhs) = delete;
|
||||
commWrapper &operator=(const commWrapper &rhs) = delete;
|
||||
commWrapper(commWrapper &&rhs);
|
||||
~commWrapper();
|
||||
};
|
||||
|
||||
|
@ -96,10 +111,13 @@ private:
|
|||
std::array<int, 3> d_N; // Number of local cells with ghosts
|
||||
int d_Np;
|
||||
int d_rank;
|
||||
int d_restart_interval, d_analysis_interval, d_blobid_interval, d_visualization_interval;
|
||||
int d_restart_interval, d_analysis_interval, d_blobid_interval,
|
||||
d_visualization_interval;
|
||||
int d_subphase_analysis_interval;
|
||||
double d_beta;
|
||||
bool d_regular;
|
||||
std::string format; // IO format string "silo" or "hdf5"
|
||||
|
||||
ThreadPool d_tpool;
|
||||
RankInfoStruct d_rank_info;
|
||||
IntArray d_Map;
|
||||
|
|
515
analysis/uCT.cpp
515
analysis/uCT.cpp
|
@ -1,319 +1,331 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "analysis/uCT.h"
|
||||
#include "analysis/analysis.h"
|
||||
#include "analysis/distance.h"
|
||||
#include "analysis/filters.h"
|
||||
#include "analysis/imfilter.h"
|
||||
|
||||
|
||||
template<class T>
|
||||
inline int sign( T x )
|
||||
{
|
||||
if ( x==0 )
|
||||
template <class T> inline int sign(T x) {
|
||||
if (x == 0)
|
||||
return 0;
|
||||
return x>0 ? 1:-1;
|
||||
return x > 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
|
||||
inline float trilinear( float dx, float dy, float dz, float f1, float f2,
|
||||
float f3, float f4, float f5, float f6, float f7, float f8 )
|
||||
{
|
||||
inline float trilinear(float dx, float dy, float dz, float f1, float f2,
|
||||
float f3, float f4, float f5, float f6, float f7,
|
||||
float f8) {
|
||||
double f, dx2, dy2, dz2, h0, h1;
|
||||
dx2 = 1.0 - dx;
|
||||
dy2 = 1.0 - dy;
|
||||
dz2 = 1.0 - dz;
|
||||
h0 = ( dx * f2 + dx2 * f1 ) * dy2 + ( dx * f4 + dx2 * f3 ) * dy;
|
||||
h1 = ( dx * f6 + dx2 * f5 ) * dy2 + ( dx * f8 + dx2 * f7 ) * dy;
|
||||
f = h0 * dz2 + h1 * dz;
|
||||
return ( f );
|
||||
h0 = (dx * f2 + dx2 * f1) * dy2 + (dx * f4 + dx2 * f3) * dy;
|
||||
h1 = (dx * f6 + dx2 * f5) * dy2 + (dx * f8 + dx2 * f7) * dy;
|
||||
f = h0 * dz2 + h1 * dz;
|
||||
return (f);
|
||||
}
|
||||
|
||||
void InterpolateMesh(const Array<float> &Coarse, Array<float> &Fine) {
|
||||
PROFILE_START("InterpolateMesh");
|
||||
|
||||
void InterpolateMesh( const Array<float> &Coarse, Array<float> &Fine )
|
||||
{
|
||||
PROFILE_START("InterpolateMesh");
|
||||
// Interpolate values from a Coarse mesh to a fine one
|
||||
// This routine assumes cell-centered meshes with 1 ghost cell
|
||||
|
||||
// Interpolate values from a Coarse mesh to a fine one
|
||||
// This routine assumes cell-centered meshes with 1 ghost cell
|
||||
// Fine mesh
|
||||
int Nx = int(Fine.size(0)) - 2;
|
||||
int Ny = int(Fine.size(1)) - 2;
|
||||
int Nz = int(Fine.size(2)) - 2;
|
||||
|
||||
// Fine mesh
|
||||
int Nx = int(Fine.size(0))-2;
|
||||
int Ny = int(Fine.size(1))-2;
|
||||
int Nz = int(Fine.size(2))-2;
|
||||
// Coarse mesh
|
||||
int nx = int(Coarse.size(0)) - 2;
|
||||
int ny = int(Coarse.size(1)) - 2;
|
||||
int nz = int(Coarse.size(2)) - 2;
|
||||
|
||||
// Coarse mesh
|
||||
int nx = int(Coarse.size(0))-2;
|
||||
int ny = int(Coarse.size(1))-2;
|
||||
int nz = int(Coarse.size(2))-2;
|
||||
// compute the stride
|
||||
int hx = Nx / nx;
|
||||
int hy = Ny / ny;
|
||||
int hz = Nz / nz;
|
||||
ASSERT(nx * hx == Nx);
|
||||
ASSERT(ny * hy == Ny);
|
||||
ASSERT(nz * hz == Nz);
|
||||
|
||||
// compute the stride
|
||||
int hx = Nx/nx;
|
||||
int hy = Ny/ny;
|
||||
int hz = Nz/nz;
|
||||
ASSERT(nx*hx==Nx);
|
||||
ASSERT(ny*hy==Ny);
|
||||
ASSERT(nz*hz==Nz);
|
||||
// value to map distance between meshes (since distance is in voxels)
|
||||
// usually hx=hy=hz (or something very close)
|
||||
// the mapping is not exact
|
||||
// however, it's assumed the coarse solution will be refined
|
||||
// a good guess is the goal here!
|
||||
float mapvalue = sqrt(hx * hx + hy * hy + hz * hz);
|
||||
|
||||
// value to map distance between meshes (since distance is in voxels)
|
||||
// usually hx=hy=hz (or something very close)
|
||||
// the mapping is not exact
|
||||
// however, it's assumed the coarse solution will be refined
|
||||
// a good guess is the goal here!
|
||||
float mapvalue = sqrt(hx*hx+hy*hy+hz*hz);
|
||||
|
||||
// Interpolate to the fine mesh
|
||||
for (int k=-1; k<Nz+1; k++){
|
||||
int k0 = floor((k-0.5*hz)/hz);
|
||||
int k1 = k0+1;
|
||||
int k2 = k0+2;
|
||||
float dz = ( (k+0.5) - (k0+0.5)*hz ) / hz;
|
||||
ASSERT(k0>=-1&&k0<nz+1&&dz>=0&&dz<=1);
|
||||
for (int j=-1; j<Ny+1; j++){
|
||||
int j0 = floor((j-0.5*hy)/hy);
|
||||
int j1 = j0+1;
|
||||
int j2 = j0+2;
|
||||
float dy = ( (j+0.5) - (j0+0.5)*hy ) / hy;
|
||||
ASSERT(j0>=-1&&j0<ny+1&&dy>=0&&dy<=1);
|
||||
for (int i=-1; i<Nx+1; i++){
|
||||
int i0 = floor((i-0.5*hx)/hx);
|
||||
int i1 = i0+1;
|
||||
int i2 = i0+2;
|
||||
float dx = ( (i+0.5) - (i0+0.5)*hx ) / hx;
|
||||
ASSERT(i0>=-1&&i0<nx+1&&dx>=0&&dx<=1);
|
||||
float val = trilinear( dx, dy, dz,
|
||||
Coarse(i1,j1,k1), Coarse(i2,j1,k1), Coarse(i1,j2,k1), Coarse(i2,j2,k1),
|
||||
Coarse(i1,j1,k2), Coarse(i2,j1,k2), Coarse(i1,j2,k2), Coarse(i2,j2,k2) );
|
||||
Fine(i+1,j+1,k+1) = mapvalue*val;
|
||||
}
|
||||
}
|
||||
}
|
||||
PROFILE_STOP("InterpolateMesh");
|
||||
// Interpolate to the fine mesh
|
||||
for (int k = -1; k < Nz + 1; k++) {
|
||||
int k0 = floor((k - 0.5 * hz) / hz);
|
||||
int k1 = k0 + 1;
|
||||
int k2 = k0 + 2;
|
||||
float dz = ((k + 0.5) - (k0 + 0.5) * hz) / hz;
|
||||
ASSERT(k0 >= -1 && k0 < nz + 1 && dz >= 0 && dz <= 1);
|
||||
for (int j = -1; j < Ny + 1; j++) {
|
||||
int j0 = floor((j - 0.5 * hy) / hy);
|
||||
int j1 = j0 + 1;
|
||||
int j2 = j0 + 2;
|
||||
float dy = ((j + 0.5) - (j0 + 0.5) * hy) / hy;
|
||||
ASSERT(j0 >= -1 && j0 < ny + 1 && dy >= 0 && dy <= 1);
|
||||
for (int i = -1; i < Nx + 1; i++) {
|
||||
int i0 = floor((i - 0.5 * hx) / hx);
|
||||
int i1 = i0 + 1;
|
||||
int i2 = i0 + 2;
|
||||
float dx = ((i + 0.5) - (i0 + 0.5) * hx) / hx;
|
||||
ASSERT(i0 >= -1 && i0 < nx + 1 && dx >= 0 && dx <= 1);
|
||||
float val = trilinear(
|
||||
dx, dy, dz, Coarse(i1, j1, k1), Coarse(i2, j1, k1),
|
||||
Coarse(i1, j2, k1), Coarse(i2, j2, k1), Coarse(i1, j1, k2),
|
||||
Coarse(i2, j1, k2), Coarse(i1, j2, k2), Coarse(i2, j2, k2));
|
||||
Fine(i + 1, j + 1, k + 1) = mapvalue * val;
|
||||
}
|
||||
}
|
||||
}
|
||||
PROFILE_STOP("InterpolateMesh");
|
||||
}
|
||||
|
||||
|
||||
// Smooth the data using the distance
|
||||
void smooth( const Array<float>& VOL, const Array<float>& Dist, float sigma, Array<float>& MultiScaleSmooth, fillHalo<float>& fillFloat )
|
||||
{
|
||||
for (size_t i=0; i<VOL.length(); i++) {
|
||||
// use exponential weight based on the distance
|
||||
float dst = Dist(i);
|
||||
float tmp = exp(-(dst*dst)/(sigma*sigma));
|
||||
float value = dst>0 ? -1:1;
|
||||
MultiScaleSmooth(i) = tmp*VOL(i) + (1-tmp)*value;
|
||||
}
|
||||
fillFloat.fill(MultiScaleSmooth);
|
||||
void smooth(const Array<float> &VOL, const Array<float> &Dist, float sigma,
|
||||
Array<float> &MultiScaleSmooth, fillHalo<float> &fillFloat) {
|
||||
for (size_t i = 0; i < VOL.length(); i++) {
|
||||
// use exponential weight based on the distance
|
||||
float dst = Dist(i);
|
||||
float tmp = exp(-(dst * dst) / (sigma * sigma));
|
||||
float value = dst > 0 ? -1 : 1;
|
||||
MultiScaleSmooth(i) = tmp * VOL(i) + (1 - tmp) * value;
|
||||
}
|
||||
fillFloat.fill(MultiScaleSmooth);
|
||||
}
|
||||
|
||||
|
||||
// Segment the data
|
||||
void segment( const Array<float>& data, Array<char>& ID, float tol )
|
||||
{
|
||||
ASSERT(data.size()==ID.size());
|
||||
for (size_t i=0; i<data.length(); i++) {
|
||||
if ( data(i) > tol )
|
||||
void segment(const Array<float> &data, Array<char> &ID, float tol) {
|
||||
ASSERT(data.size() == ID.size());
|
||||
for (size_t i = 0; i < data.length(); i++) {
|
||||
if (data(i) > tol)
|
||||
ID(i) = 0;
|
||||
else
|
||||
ID(i) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Remove disconnected phases
|
||||
void removeDisconnected( Array<char>& ID, const Domain& Dm )
|
||||
{
|
||||
void removeDisconnected(Array<char> &ID, const Domain &Dm) {
|
||||
// Run blob identification to remove disconnected volumes
|
||||
BlobIDArray GlobalBlobID;
|
||||
DoubleArray SignDist(ID.size());
|
||||
DoubleArray Phase(ID.size());
|
||||
for (size_t i=0; i<ID.length(); i++) {
|
||||
SignDist(i) = (2*ID(i)-1);
|
||||
for (size_t i = 0; i < ID.length(); i++) {
|
||||
SignDist(i) = (2 * ID(i) - 1);
|
||||
Phase(i) = 1;
|
||||
}
|
||||
ComputeGlobalBlobIDs( ID.size(0)-2, ID.size(1)-2, ID.size(2)-2,
|
||||
Dm.rank_info, Phase, SignDist, 0, 0, GlobalBlobID, Dm.Comm );
|
||||
for (size_t i=0; i<ID.length(); i++) {
|
||||
if ( GlobalBlobID(i) > 0 )
|
||||
ComputeGlobalBlobIDs(ID.size(0) - 2, ID.size(1) - 2, ID.size(2) - 2,
|
||||
Dm.rank_info, Phase, SignDist, 0, 0, GlobalBlobID,
|
||||
Dm.Comm);
|
||||
for (size_t i = 0; i < ID.length(); i++) {
|
||||
if (GlobalBlobID(i) > 0)
|
||||
ID(i) = 0;
|
||||
ID(i) = GlobalBlobID(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Solve a level (without any coarse level information)
|
||||
void solve( const Array<float>& VOL, Array<float>& Mean, Array<char>& ID,
|
||||
Array<float>& Dist, Array<float>& MultiScaleSmooth, Array<float>& NonLocalMean,
|
||||
fillHalo<float>& fillFloat, const Domain& Dm, int nprocx,
|
||||
float threshold, float lamda, float sigsq, int depth)
|
||||
{
|
||||
PROFILE_SCOPED(timer,"solve");
|
||||
void solve(const Array<float> &VOL, Array<float> &Mean, Array<char> &ID,
|
||||
Array<float> &Dist, Array<float> &MultiScaleSmooth,
|
||||
Array<float> &NonLocalMean, fillHalo<float> &fillFloat,
|
||||
const Domain &Dm, int nprocx, float threshold, float lamda,
|
||||
float sigsq, int depth) {
|
||||
PROFILE_SCOPED(timer, "solve");
|
||||
// Compute the median filter on the sparse array
|
||||
Med3D( VOL, Mean );
|
||||
fillFloat.fill( Mean );
|
||||
segment( Mean, ID, threshold );
|
||||
Med3D(VOL, Mean);
|
||||
fillFloat.fill(Mean);
|
||||
segment(Mean, ID, threshold);
|
||||
// Compute the distance using the segmented volume
|
||||
CalcDist( Dist, ID, Dm );
|
||||
fillFloat.fill(Dist);
|
||||
smooth( VOL, Dist, 2.0, MultiScaleSmooth, fillFloat );
|
||||
CalcDist(Dist, ID, Dm);
|
||||
fillFloat.fill(Dist);
|
||||
smooth(VOL, Dist, 2.0, MultiScaleSmooth, fillFloat);
|
||||
// Compute non-local mean
|
||||
// int depth = 5;
|
||||
// float sigsq=0.1;
|
||||
int nlm_count = NLM3D( MultiScaleSmooth, Mean, Dist, NonLocalMean, depth, sigsq);
|
||||
NULL_USE( nlm_count );
|
||||
fillFloat.fill(NonLocalMean);
|
||||
int nlm_count =
|
||||
NLM3D(MultiScaleSmooth, Mean, Dist, NonLocalMean, depth, sigsq);
|
||||
NULL_USE(nlm_count);
|
||||
fillFloat.fill(NonLocalMean);
|
||||
}
|
||||
|
||||
|
||||
// Refine a solution from a coarse grid to a fine grid
|
||||
void refine( const Array<float>& Dist_coarse,
|
||||
const Array<float>& VOL, Array<float>& Mean, Array<char>& ID,
|
||||
Array<float>& Dist, Array<float>& MultiScaleSmooth, Array<float>& NonLocalMean,
|
||||
fillHalo<float>& fillFloat, const Domain& Dm, int nprocx, int level,
|
||||
float threshold, float lamda, float sigsq, int depth)
|
||||
{
|
||||
PROFILE_SCOPED(timer,"refine");
|
||||
int ratio[3] = { int(Dist.size(0)/Dist_coarse.size(0)),
|
||||
int(Dist.size(1)/Dist_coarse.size(1)),
|
||||
int(Dist.size(2)/Dist_coarse.size(2)) };
|
||||
void refine(const Array<float> &Dist_coarse, const Array<float> &VOL,
|
||||
Array<float> &Mean, Array<char> &ID, Array<float> &Dist,
|
||||
Array<float> &MultiScaleSmooth, Array<float> &NonLocalMean,
|
||||
fillHalo<float> &fillFloat, const Domain &Dm, int nprocx, int level,
|
||||
float threshold, float lamda, float sigsq, int depth) {
|
||||
PROFILE_SCOPED(timer, "refine");
|
||||
int ratio[3] = {int(Dist.size(0) / Dist_coarse.size(0)),
|
||||
int(Dist.size(1) / Dist_coarse.size(1)),
|
||||
int(Dist.size(2) / Dist_coarse.size(2))};
|
||||
// Interpolate the distance from the coarse to fine grid
|
||||
InterpolateMesh( Dist_coarse, Dist );
|
||||
InterpolateMesh(Dist_coarse, Dist);
|
||||
// Compute the median filter on the array and segment
|
||||
Med3D( VOL, Mean );
|
||||
fillFloat.fill( Mean );
|
||||
segment( Mean, ID, threshold );
|
||||
Med3D(VOL, Mean);
|
||||
fillFloat.fill(Mean);
|
||||
segment(Mean, ID, threshold);
|
||||
// If the ID has the wrong distance, set the distance to 0 and run a simple filter to set neighbors to 0
|
||||
for (size_t i=0; i<ID.length(); i++) {
|
||||
char id = Dist(i)>0 ? 1:0;
|
||||
if ( id != ID(i) )
|
||||
for (size_t i = 0; i < ID.length(); i++) {
|
||||
char id = Dist(i) > 0 ? 1 : 0;
|
||||
if (id != ID(i))
|
||||
Dist(i) = 0;
|
||||
}
|
||||
fillFloat.fill( Dist );
|
||||
std::function<float(int,const float*)> filter_1D = []( int N, const float* data )
|
||||
{
|
||||
bool zero = data[0]==0 || data[2]==0;
|
||||
return zero ? data[1]*1e-12 : data[1];
|
||||
fillFloat.fill(Dist);
|
||||
std::function<float(int, const float *)> filter_1D = [](int N,
|
||||
const float *data) {
|
||||
bool zero = data[0] == 0 || data[2] == 0;
|
||||
return zero ? data[1] * 1e-12 : data[1];
|
||||
};
|
||||
std::vector<imfilter::BC> BC(3,imfilter::BC::replicate);
|
||||
std::vector<std::function<float(int,const float*)>> filter_set(3,filter_1D);
|
||||
Dist = imfilter::imfilter_separable<float>( Dist, {1,1,1}, filter_set, BC );
|
||||
fillFloat.fill( Dist );
|
||||
std::vector<imfilter::BC> BC(3, imfilter::BC::replicate);
|
||||
std::vector<std::function<float(int, const float *)>> filter_set(3,
|
||||
filter_1D);
|
||||
Dist = imfilter::imfilter_separable<float>(Dist, {1, 1, 1}, filter_set, BC);
|
||||
fillFloat.fill(Dist);
|
||||
// Smooth the volume data
|
||||
float h = 2*lamda*sqrt(double(ratio[0]*ratio[0]+ratio[1]*ratio[1]+ratio[2]*ratio[2]));
|
||||
smooth( VOL, Dist, h, MultiScaleSmooth, fillFloat );
|
||||
float h = 2 * lamda *
|
||||
sqrt(double(ratio[0] * ratio[0] + ratio[1] * ratio[1] +
|
||||
ratio[2] * ratio[2]));
|
||||
smooth(VOL, Dist, h, MultiScaleSmooth, fillFloat);
|
||||
// Compute non-local mean
|
||||
// int depth = 3;
|
||||
// float sigsq = 0.1;
|
||||
int nlm_count = NLM3D( MultiScaleSmooth, Mean, Dist, NonLocalMean, depth, sigsq);
|
||||
NULL_USE( nlm_count );
|
||||
fillFloat.fill(NonLocalMean);
|
||||
segment( NonLocalMean, ID, 0.001 );
|
||||
for (size_t i=0; i<ID.length(); i++) {
|
||||
char id = Dist(i)>0 ? 1:0;
|
||||
if ( id!=ID(i) || fabs(Dist(i))<1 )
|
||||
Dist(i) = 2.0*ID(i)-1.0;
|
||||
// int depth = 3;
|
||||
// float sigsq = 0.1;
|
||||
int nlm_count =
|
||||
NLM3D(MultiScaleSmooth, Mean, Dist, NonLocalMean, depth, sigsq);
|
||||
NULL_USE(nlm_count);
|
||||
fillFloat.fill(NonLocalMean);
|
||||
segment(NonLocalMean, ID, 0.001);
|
||||
for (size_t i = 0; i < ID.length(); i++) {
|
||||
char id = Dist(i) > 0 ? 1 : 0;
|
||||
if (id != ID(i) || fabs(Dist(i)) < 1)
|
||||
Dist(i) = 2.0 * ID(i) - 1.0;
|
||||
}
|
||||
// Remove disconnected domains
|
||||
//removeDisconnected( ID, Dm );
|
||||
// Compute the distance using the segmented volume
|
||||
if ( level > 0 ) {
|
||||
CalcDist( Dist, ID, Dm );
|
||||
fillFloat.fill(Dist);
|
||||
if (level > 0) {
|
||||
CalcDist(Dist, ID, Dm);
|
||||
fillFloat.fill(Dist);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Remove regions that are likely noise by shrinking the volumes by dx,
|
||||
// removing all values that are more than dx+delta from the surface, and then
|
||||
// growing by dx+delta and intersecting with the original data
|
||||
void filter_final( Array<char>& ID, Array<float>& Dist,
|
||||
fillHalo<float>& fillFloat, const Domain& Dm,
|
||||
Array<float>& Mean, Array<float>& Dist1, Array<float>& Dist2 )
|
||||
{
|
||||
PROFILE_SCOPED(timer,"filter_final");
|
||||
int rank = Dm.Comm.getRank();
|
||||
int Nx = Dm.Nx-2;
|
||||
int Ny = Dm.Ny-2;
|
||||
int Nz = Dm.Nz-2;
|
||||
void filter_final(Array<char> &ID, Array<float> &Dist,
|
||||
fillHalo<float> &fillFloat, const Domain &Dm,
|
||||
Array<float> &Mean, Array<float> &Dist1,
|
||||
Array<float> &Dist2) {
|
||||
PROFILE_SCOPED(timer, "filter_final");
|
||||
int rank = Dm.Comm.getRank();
|
||||
int Nx = Dm.Nx - 2;
|
||||
int Ny = Dm.Ny - 2;
|
||||
int Nz = Dm.Nz - 2;
|
||||
// Calculate the distance
|
||||
CalcDist( Dist, ID, Dm );
|
||||
CalcDist(Dist, ID, Dm);
|
||||
fillFloat.fill(Dist);
|
||||
// Compute the range to shrink the volume based on the L2 norm of the distance
|
||||
Array<float> Dist0(Nx,Ny,Nz);
|
||||
fillFloat.copy(Dist,Dist0);
|
||||
Array<float> Dist0(Nx, Ny, Nz);
|
||||
fillFloat.copy(Dist, Dist0);
|
||||
float tmp = 0;
|
||||
for (size_t i=0; i<Dist0.length(); i++)
|
||||
tmp += Dist0(i)*Dist0(i);
|
||||
tmp = sqrt( Dm.Comm.sumReduce(tmp) / Dm.Comm.sumReduce<float>(Dist0.length()) );
|
||||
const float dx1 = 0.3*tmp;
|
||||
const float dx2 = 1.05*dx1;
|
||||
if (rank==0)
|
||||
printf(" %0.1f %0.1f %0.1f\n",tmp,dx1,dx2);
|
||||
for (size_t i = 0; i < Dist0.length(); i++)
|
||||
tmp += Dist0(i) * Dist0(i);
|
||||
tmp =
|
||||
sqrt(Dm.Comm.sumReduce(tmp) / Dm.Comm.sumReduce<float>(Dist0.length()));
|
||||
const float dx1 = 0.3 * tmp;
|
||||
const float dx2 = 1.05 * dx1;
|
||||
if (rank == 0)
|
||||
printf(" %0.1f %0.1f %0.1f\n", tmp, dx1, dx2);
|
||||
// Update the IDs/Distance removing regions that are < dx of the range
|
||||
Dist1 = Dist;
|
||||
Dist2 = Dist;
|
||||
Array<char> ID1 = ID;
|
||||
Array<char> ID2 = ID;
|
||||
for (size_t i=0; i<ID.length(); i++) {
|
||||
ID1(i) = Dist(i)<-dx1 ? 1:0;
|
||||
ID2(i) = Dist(i)> dx1 ? 1:0;
|
||||
for (size_t i = 0; i < ID.length(); i++) {
|
||||
ID1(i) = Dist(i) < -dx1 ? 1 : 0;
|
||||
ID2(i) = Dist(i) > dx1 ? 1 : 0;
|
||||
}
|
||||
//Array<float> Dist1 = Dist;
|
||||
//Array<float> Dist2 = Dist;
|
||||
CalcDist( Dist1, ID1, Dm );
|
||||
CalcDist( Dist2, ID2, Dm );
|
||||
CalcDist(Dist1, ID1, Dm);
|
||||
CalcDist(Dist2, ID2, Dm);
|
||||
fillFloat.fill(Dist1);
|
||||
fillFloat.fill(Dist2);
|
||||
// Keep those regions that are within dx2 of the new volumes
|
||||
Mean = Dist;
|
||||
for (size_t i=0; i<ID.length(); i++) {
|
||||
if ( Dist1(i)+dx2>0 && ID(i)<=0 ) {
|
||||
for (size_t i = 0; i < ID.length(); i++) {
|
||||
if (Dist1(i) + dx2 > 0 && ID(i) <= 0) {
|
||||
Mean(i) = -1;
|
||||
} else if ( Dist2(i)+dx2>0 && ID(i)>0 ) {
|
||||
} else if (Dist2(i) + dx2 > 0 && ID(i) > 0) {
|
||||
Mean(i) = 1;
|
||||
} else {
|
||||
Mean(i) = Dist(i)>0 ? 0.5:-0.5;
|
||||
Mean(i) = Dist(i) > 0 ? 0.5 : -0.5;
|
||||
}
|
||||
}
|
||||
// Find regions of uncertainty that are entirely contained within another region
|
||||
fillHalo<double> fillDouble(Dm.Comm,Dm.rank_info,{Nx,Ny,Nz},{1,1,1},0,1);
|
||||
fillHalo<BlobIDType> fillInt(Dm.Comm,Dm.rank_info,{Nx,Ny,Nz},{1,1,1},0,1);
|
||||
fillHalo<double> fillDouble(Dm.Comm, Dm.rank_info, {Nx, Ny, Nz}, {1, 1, 1},
|
||||
0, 1);
|
||||
fillHalo<BlobIDType> fillInt(Dm.Comm, Dm.rank_info, {Nx, Ny, Nz}, {1, 1, 1},
|
||||
0, 1);
|
||||
BlobIDArray GlobalBlobID;
|
||||
DoubleArray SignDist(ID.size());
|
||||
for (size_t i=0; i<ID.length(); i++)
|
||||
SignDist(i) = fabs(Mean(i))==1 ? -1:1;
|
||||
for (size_t i = 0; i < ID.length(); i++)
|
||||
SignDist(i) = fabs(Mean(i)) == 1 ? -1 : 1;
|
||||
fillDouble.fill(SignDist);
|
||||
DoubleArray Phase(ID.size());
|
||||
Phase.fill(1);
|
||||
ComputeGlobalBlobIDs( Nx, Ny, Nz, Dm.rank_info, Phase, SignDist, 0, 0, GlobalBlobID, Dm.Comm );
|
||||
ComputeGlobalBlobIDs(Nx, Ny, Nz, Dm.rank_info, Phase, SignDist, 0, 0,
|
||||
GlobalBlobID, Dm.Comm);
|
||||
fillInt.fill(GlobalBlobID);
|
||||
int N_blobs = Dm.Comm.maxReduce(GlobalBlobID.max()+1);
|
||||
std::vector<float> mean(N_blobs,0);
|
||||
std::vector<int> count(N_blobs,0);
|
||||
for (int k=1; k<=Nz; k++) {
|
||||
for (int j=1; j<=Ny; j++) {
|
||||
for (int i=1; i<=Nx; i++) {
|
||||
int id = GlobalBlobID(i,j,k);
|
||||
if ( id >= 0 ) {
|
||||
if ( GlobalBlobID(i-1,j,k)<0 ) {
|
||||
mean[id] += Mean(i-1,j,k);
|
||||
int N_blobs = Dm.Comm.maxReduce(GlobalBlobID.max() + 1);
|
||||
std::vector<float> mean(N_blobs, 0);
|
||||
std::vector<int> count(N_blobs, 0);
|
||||
for (int k = 1; k <= Nz; k++) {
|
||||
for (int j = 1; j <= Ny; j++) {
|
||||
for (int i = 1; i <= Nx; i++) {
|
||||
int id = GlobalBlobID(i, j, k);
|
||||
if (id >= 0) {
|
||||
if (GlobalBlobID(i - 1, j, k) < 0) {
|
||||
mean[id] += Mean(i - 1, j, k);
|
||||
count[id]++;
|
||||
}
|
||||
if ( GlobalBlobID(i+1,j,k)<0 ) {
|
||||
mean[id] += Mean(i+1,j,k);
|
||||
if (GlobalBlobID(i + 1, j, k) < 0) {
|
||||
mean[id] += Mean(i + 1, j, k);
|
||||
count[id]++;
|
||||
}
|
||||
if ( GlobalBlobID(i,j-1,k)<0 ) {
|
||||
mean[id] += Mean(i,j-1,k);
|
||||
if (GlobalBlobID(i, j - 1, k) < 0) {
|
||||
mean[id] += Mean(i, j - 1, k);
|
||||
count[id]++;
|
||||
}
|
||||
if ( GlobalBlobID(i,j+1,k)<0 ) {
|
||||
mean[id] += Mean(i,j+1,k);
|
||||
if (GlobalBlobID(i, j + 1, k) < 0) {
|
||||
mean[id] += Mean(i, j + 1, k);
|
||||
count[id]++;
|
||||
}
|
||||
if ( GlobalBlobID(i,j,k-1)<0 ) {
|
||||
mean[id] += Mean(i,j,k-1);
|
||||
if (GlobalBlobID(i, j, k - 1) < 0) {
|
||||
mean[id] += Mean(i, j, k - 1);
|
||||
count[id]++;
|
||||
}
|
||||
if ( GlobalBlobID(i,j,k+1)<0 ) {
|
||||
mean[id] += Mean(i,j,k+1);
|
||||
if (GlobalBlobID(i, j, k + 1) < 0) {
|
||||
mean[id] += Mean(i, j, k + 1);
|
||||
count[id]++;
|
||||
}
|
||||
}
|
||||
|
@ -322,16 +334,16 @@ void filter_final( Array<char>& ID, Array<float>& Dist,
|
|||
}
|
||||
mean = Dm.Comm.sumReduce(mean);
|
||||
count = Dm.Comm.sumReduce(count);
|
||||
for (size_t i=0; i<mean.size(); i++)
|
||||
for (size_t i = 0; i < mean.size(); i++)
|
||||
mean[i] /= count[i];
|
||||
/*if (rank==0) {
|
||||
for (size_t i=0; i<mean.size(); i++)
|
||||
printf("%i %0.4f\n",i,mean[i]);
|
||||
}*/
|
||||
for (size_t i=0; i<Mean.length(); i++) {
|
||||
for (size_t i = 0; i < Mean.length(); i++) {
|
||||
int id = GlobalBlobID(i);
|
||||
if ( id >= 0 ) {
|
||||
if ( fabs(mean[id]) > 0.95 ) {
|
||||
if (id >= 0) {
|
||||
if (fabs(mean[id]) > 0.95) {
|
||||
// Isolated domain surrounded by one domain
|
||||
GlobalBlobID(i) = -2;
|
||||
Mean(i) = sign(mean[id]);
|
||||
|
@ -343,53 +355,54 @@ void filter_final( Array<char>& ID, Array<float>& Dist,
|
|||
}
|
||||
// Perform the final segmentation and update the distance
|
||||
fillFloat.fill(Mean);
|
||||
segment( Mean, ID, 0.01 );
|
||||
CalcDist( Dist, ID, Dm );
|
||||
segment(Mean, ID, 0.01);
|
||||
CalcDist(Dist, ID, Dm);
|
||||
fillFloat.fill(Dist);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Filter the original data
|
||||
void filter_src( const Domain& Dm, Array<float>& src )
|
||||
{
|
||||
PROFILE_START("Filter source data");
|
||||
int Nx = Dm.Nx-2;
|
||||
int Ny = Dm.Ny-2;
|
||||
int Nz = Dm.Nz-2;
|
||||
fillHalo<float> fillFloat(Dm.Comm,Dm.rank_info,{Nx,Ny,Nz},{1,1,1},0,1);
|
||||
void filter_src(const Domain &Dm, Array<float> &src) {
|
||||
PROFILE_START("Filter source data");
|
||||
int Nx = Dm.Nx - 2;
|
||||
int Ny = Dm.Ny - 2;
|
||||
int Nz = Dm.Nz - 2;
|
||||
fillHalo<float> fillFloat(Dm.Comm, Dm.rank_info, {Nx, Ny, Nz}, {1, 1, 1}, 0,
|
||||
1);
|
||||
// Perform a hot-spot filter on the data
|
||||
std::vector<imfilter::BC> BC = { imfilter::BC::replicate, imfilter::BC::replicate, imfilter::BC::replicate };
|
||||
std::function<float(const Array<float>&)> filter_3D = []( const Array<float>& data )
|
||||
{
|
||||
float min1 = std::min(data(0,1,1),data(2,1,1));
|
||||
float min2 = std::min(data(1,0,1),data(1,2,1));
|
||||
float min3 = std::min(data(1,1,0),data(1,1,2));
|
||||
float max1 = std::max(data(0,1,1),data(2,1,1));
|
||||
float max2 = std::max(data(1,0,1),data(1,2,1));
|
||||
float max3 = std::max(data(1,1,0),data(1,1,2));
|
||||
float min = std::min(min1,std::min(min2,min3));
|
||||
float max = std::max(max1,std::max(max2,max3));
|
||||
return std::max(std::min(data(1,1,1),max),min);
|
||||
};
|
||||
std::function<float(const Array<float>&)> filter_1D = []( const Array<float>& data )
|
||||
{
|
||||
float min = std::min(data(0),data(2));
|
||||
float max = std::max(data(0),data(2));
|
||||
return std::max(std::min(data(1),max),min);
|
||||
};
|
||||
std::vector<imfilter::BC> BC = {imfilter::BC::replicate,
|
||||
imfilter::BC::replicate,
|
||||
imfilter::BC::replicate};
|
||||
std::function<float(const Array<float> &)> filter_3D =
|
||||
[](const Array<float> &data) {
|
||||
float min1 = std::min(data(0, 1, 1), data(2, 1, 1));
|
||||
float min2 = std::min(data(1, 0, 1), data(1, 2, 1));
|
||||
float min3 = std::min(data(1, 1, 0), data(1, 1, 2));
|
||||
float max1 = std::max(data(0, 1, 1), data(2, 1, 1));
|
||||
float max2 = std::max(data(1, 0, 1), data(1, 2, 1));
|
||||
float max3 = std::max(data(1, 1, 0), data(1, 1, 2));
|
||||
float min = std::min(min1, std::min(min2, min3));
|
||||
float max = std::max(max1, std::max(max2, max3));
|
||||
return std::max(std::min(data(1, 1, 1), max), min);
|
||||
};
|
||||
std::function<float(const Array<float> &)> filter_1D =
|
||||
[](const Array<float> &data) {
|
||||
float min = std::min(data(0), data(2));
|
||||
float max = std::max(data(0), data(2));
|
||||
return std::max(std::min(data(1), max), min);
|
||||
};
|
||||
//LOCVOL[0] = imfilter::imfilter<float>( LOCVOL[0], {1,1,1}, filter_3D, BC );
|
||||
std::vector<std::function<float(const Array<float>&)>> filter_set(3,filter_1D);
|
||||
src = imfilter::imfilter_separable<float>( src, {1,1,1}, filter_set, BC );
|
||||
fillFloat.fill( src );
|
||||
std::vector<std::function<float(const Array<float> &)>> filter_set(
|
||||
3, filter_1D);
|
||||
src = imfilter::imfilter_separable<float>(src, {1, 1, 1}, filter_set, BC);
|
||||
fillFloat.fill(src);
|
||||
// Perform a gaussian filter on the data
|
||||
int Nh[3] = { 2, 2, 2 };
|
||||
float sigma[3] = { 1.0, 1.0, 1.0 };
|
||||
int Nh[3] = {2, 2, 2};
|
||||
float sigma[3] = {1.0, 1.0, 1.0};
|
||||
std::vector<Array<float>> H(3);
|
||||
H[0] = imfilter::create_filter<float>( { Nh[0] }, "gaussian", &sigma[0] );
|
||||
H[1] = imfilter::create_filter<float>( { Nh[1] }, "gaussian", &sigma[1] );
|
||||
H[2] = imfilter::create_filter<float>( { Nh[2] }, "gaussian", &sigma[2] );
|
||||
src = imfilter::imfilter_separable( src, H, BC );
|
||||
fillFloat.fill( src );
|
||||
PROFILE_STOP("Filter source data");
|
||||
H[0] = imfilter::create_filter<float>({Nh[0]}, "gaussian", &sigma[0]);
|
||||
H[1] = imfilter::create_filter<float>({Nh[1]}, "gaussian", &sigma[1]);
|
||||
H[2] = imfilter::create_filter<float>({Nh[2]}, "gaussian", &sigma[2]);
|
||||
src = imfilter::imfilter_separable(src, H, BC);
|
||||
fillFloat.fill(src);
|
||||
PROFILE_STOP("Filter source data");
|
||||
}
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef uCT_H_INC
|
||||
#define uCT_H_INC
|
||||
|
||||
|
@ -5,54 +21,46 @@
|
|||
#include "common/Domain.h"
|
||||
#include "common/Communication.h"
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Interpolate between meshes
|
||||
* @details This routine interpolates from a coarse to a fine mesh
|
||||
* @param[in] Coarse Coarse mesh solution
|
||||
* @param[out] Fine Fine mesh solution
|
||||
*/
|
||||
void InterpolateMesh( const Array<float> &Coarse, Array<float> &Fine );
|
||||
|
||||
void InterpolateMesh(const Array<float> &Coarse, Array<float> &Fine);
|
||||
|
||||
// Smooth the data using the distance
|
||||
void smooth( const Array<float>& VOL, const Array<float>& Dist, float sigma, Array<float>& MultiScaleSmooth, fillHalo<float>& fillFloat );
|
||||
|
||||
void smooth(const Array<float> &VOL, const Array<float> &Dist, float sigma,
|
||||
Array<float> &MultiScaleSmooth, fillHalo<float> &fillFloat);
|
||||
|
||||
// Segment the data
|
||||
void segment( const Array<float>& data, Array<char>& ID, float tol );
|
||||
|
||||
void segment(const Array<float> &data, Array<char> &ID, float tol);
|
||||
|
||||
// Remove disconnected phases
|
||||
void removeDisconnected( Array<char>& ID, const Domain& Dm );
|
||||
|
||||
void removeDisconnected(Array<char> &ID, const Domain &Dm);
|
||||
|
||||
// Solve a level (without any coarse level information)
|
||||
void solve( const Array<float>& VOL, Array<float>& Mean, Array<char>& ID,
|
||||
Array<float>& Dist, Array<float>& MultiScaleSmooth, Array<float>& NonLocalMean,
|
||||
fillHalo<float>& fillFloat, const Domain& Dm, int nprocx,
|
||||
float threshold, float lamda, float sigsq, int depth);
|
||||
|
||||
void solve(const Array<float> &VOL, Array<float> &Mean, Array<char> &ID,
|
||||
Array<float> &Dist, Array<float> &MultiScaleSmooth,
|
||||
Array<float> &NonLocalMean, fillHalo<float> &fillFloat,
|
||||
const Domain &Dm, int nprocx, float threshold, float lamda,
|
||||
float sigsq, int depth);
|
||||
|
||||
// Refine a solution from a coarse grid to a fine grid
|
||||
void refine( const Array<float>& Dist_coarse,
|
||||
const Array<float>& VOL, Array<float>& Mean, Array<char>& ID,
|
||||
Array<float>& Dist, Array<float>& MultiScaleSmooth, Array<float>& NonLocalMean,
|
||||
fillHalo<float>& fillFloat, const Domain& Dm, int nprocx, int level,
|
||||
float threshold, float lamda, float sigsq, int depth);
|
||||
|
||||
void refine(const Array<float> &Dist_coarse, const Array<float> &VOL,
|
||||
Array<float> &Mean, Array<char> &ID, Array<float> &Dist,
|
||||
Array<float> &MultiScaleSmooth, Array<float> &NonLocalMean,
|
||||
fillHalo<float> &fillFloat, const Domain &Dm, int nprocx, int level,
|
||||
float threshold, float lamda, float sigsq, int depth);
|
||||
|
||||
// Remove regions that are likely noise by shrinking the volumes by dx,
|
||||
// removing all values that are more than dx+delta from the surface, and then
|
||||
// growing by dx+delta and intersecting with the original data
|
||||
void filter_final( Array<char>& ID, Array<float>& Dist,
|
||||
fillHalo<float>& fillFloat, const Domain& Dm,
|
||||
Array<float>& Mean, Array<float>& Dist1, Array<float>& Dist2 );
|
||||
|
||||
void filter_final(Array<char> &ID, Array<float> &Dist,
|
||||
fillHalo<float> &fillFloat, const Domain &Dm,
|
||||
Array<float> &Mean, Array<float> &Dist1, Array<float> &Dist2);
|
||||
|
||||
// Filter the original data
|
||||
void filter_src( const Domain& Dm, Array<float>& src );
|
||||
|
||||
void filter_src(const Domain &Dm, Array<float> &src);
|
||||
|
||||
#endif
|
||||
|
|
84
clang-format-all
Executable file
84
clang-format-all
Executable file
|
@ -0,0 +1,84 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# clang-format-all: a tool to run clang-format on an entire project
|
||||
# Copyright (C) 2016 Evan Klitzke <evan@eklitzke.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
function usage {
|
||||
echo "Usage: $0 DIR..."
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
# Variable that will hold the name of the clang-format command
|
||||
FMT=""
|
||||
|
||||
# Some distros just call it clang-format. Others (e.g. Ubuntu) are insistent
|
||||
# that the version number be part of the command. We prefer clang-format if
|
||||
# that's present, otherwise we work backwards from highest version to lowest
|
||||
# version.
|
||||
for clangfmt in clang-format{,-{4,3}.{9,8,7,6,5,4,3,2,1,0}}; do
|
||||
if which "$clangfmt" &>/dev/null; then
|
||||
FMT="$clangfmt"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Check if we found a working clang-format
|
||||
if [ -z "$FMT" ]; then
|
||||
echo "failed to find clang-format"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check all of the arguments first to make sure they're all directories
|
||||
for dir in "$@"; do
|
||||
if [ ! -d "${dir}" ]; then
|
||||
echo "${dir} is not a directory"
|
||||
usage
|
||||
fi
|
||||
done
|
||||
|
||||
# Find a dominating file, starting from a given directory and going up.
|
||||
find-dominating-file() {
|
||||
if [ -r "$1"/"$2" ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ "$1" = "/" ]; then
|
||||
return 1
|
||||
fi
|
||||
find-dominating-file "$(realpath "$1"/..)" "$2"
|
||||
return $?
|
||||
}
|
||||
|
||||
# Run clang-format -i on all of the things
|
||||
for dir in "$@"; do
|
||||
pushd "${dir}" &>/dev/null
|
||||
if ! find-dominating-file . .clang-format; then
|
||||
echo "Failed to find dominating .clang-format starting at $PWD"
|
||||
continue
|
||||
fi
|
||||
find . \
|
||||
\( -name '*.c' \
|
||||
-o -name '*.cc' \
|
||||
-o -name '*.cpp' \
|
||||
-o -name '*.h' \
|
||||
-o -name '*.hh' \
|
||||
-o -name '*.hpp' \) \
|
||||
-exec "${FMT}" -i '{}' \;
|
||||
popd &>/dev/null
|
||||
done
|
|
@ -103,12 +103,12 @@ ENDMACRO()
|
|||
# Macro to find and configure hdf5
|
||||
MACRO ( CONFIGURE_HDF5 )
|
||||
CHECK_ENABLE_FLAG( USE_HDF5 0 )
|
||||
IF ( USE_HDF5 )
|
||||
# Check if we specified the silo directory
|
||||
IF ( USE_HDF5 AND NOT FOUND_HDF5 )
|
||||
# Check if we specified the hdf5 directory
|
||||
IF ( HDF5_DIRECTORY )
|
||||
VERIFY_PATH ( ${HDF5_DIRECTORY} )
|
||||
INCLUDE_DIRECTORIES ( ${HDF5_DIRECTORY}/include )
|
||||
SET ( HDF5_INCLUDE ${HDF5_DIRECTORY}/include )
|
||||
SET( HDF5_INCLUDE ${HDF5_DIRECTORY}/include )
|
||||
FIND_LIBRARY ( HDF5_LIB NAMES hdf5 PATHS ${HDF5_DIRECTORY}/lib NO_DEFAULT_PATH )
|
||||
FIND_LIBRARY ( HDF5_HL_LIB NAMES hdf5_hl PATHS ${HDF5_DIRECTORY}/lib NO_DEFAULT_PATH )
|
||||
ELSE()
|
||||
|
@ -118,6 +118,8 @@ MACRO ( CONFIGURE_HDF5 )
|
|||
${HDF5_HL_LIB}
|
||||
${HDF5_LIB}
|
||||
)
|
||||
SET( FOUND_HDF5 TRUE )
|
||||
SET( EXTERNAL_LIBS ${HDF5_LIBS} ${EXTERNAL_LIBS} )
|
||||
ADD_DEFINITIONS ( -DUSE_HDF5 )
|
||||
MESSAGE( "Using hdf5" )
|
||||
MESSAGE( " ${HDF5_LIB}" )
|
||||
|
@ -151,7 +153,7 @@ MACRO( CONFIGURE_NETCDF )
|
|||
ELSE()
|
||||
MESSAGE( FATAL_ERROR "Default search for netcdf is not yet supported. Use -D NETCDF_DIRECTORY=" )
|
||||
ENDIF()
|
||||
SET( EXTERNAL_LIBS ${NETCDF_LIBS} ${HDF5_LIBS} ${EXTERNAL_LIBS} )
|
||||
SET( EXTERNAL_LIBS ${NETCDF_LIBS} ${EXTERNAL_LIBS} )
|
||||
ADD_DEFINITIONS ( -DUSE_NETCDF )
|
||||
MESSAGE( "Using netcdf" )
|
||||
MESSAGE( " ${NETCDF_LIBS}" )
|
||||
|
@ -179,7 +181,7 @@ MACRO ( CONFIGURE_SILO )
|
|||
SET ( SILO_LIBS
|
||||
${SILO_LIB}
|
||||
)
|
||||
SET( EXTERNAL_LIBS ${SILO_LIBS} ${HDF5_LIBS} ${EXTERNAL_LIBS} )
|
||||
SET( EXTERNAL_LIBS ${SILO_LIBS} ${EXTERNAL_LIBS} )
|
||||
ADD_DEFINITIONS ( -DUSE_SILO )
|
||||
MESSAGE( "Using silo" )
|
||||
MESSAGE( " ${SILO_LIB}" )
|
||||
|
@ -261,7 +263,7 @@ ENDMACRO ()
|
|||
# Macro to configure LBPM specific options
|
||||
MACRO ( CONFIGURE_LBPM )
|
||||
# Set the maximum number of processors for the tests
|
||||
IF ( NOT TEST_MAX_PROCS )
|
||||
IF ( NOT DEFINED TEST_MAX_PROCS )
|
||||
SET( TEST_MAX_PROCS 32 )
|
||||
ENDIF()
|
||||
# Add the correct paths to rpath in case we build shared libraries
|
||||
|
|
143
common/Array.cpp
143
common/Array.cpp
|
@ -1,117 +1,74 @@
|
|||
// clang-format off
|
||||
#include "common/Array.h"
|
||||
#include "common/Array.hpp"
|
||||
#include "common/Utilities.h"
|
||||
|
||||
#include <complex>
|
||||
|
||||
|
||||
/********************************************************
|
||||
* ArraySize *
|
||||
********************************************************/
|
||||
ArraySize::ArraySize( const std::vector<size_t>& N )
|
||||
{
|
||||
d_ndim = N.size();
|
||||
d_N[0] = 0;
|
||||
d_N[1] = 1;
|
||||
d_N[2] = 1;
|
||||
d_N[3] = 1;
|
||||
d_N[4] = 1;
|
||||
for ( size_t i = 0; i < d_ndim; i++ )
|
||||
d_N[i] = N[i];
|
||||
d_length = 1;
|
||||
for ( unsigned long i : d_N )
|
||||
d_length *= i;
|
||||
if ( d_ndim == 0 )
|
||||
d_length = 0;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* Explicit instantiations of Array *
|
||||
********************************************************/
|
||||
template class Array<char, FunctionTable>;
|
||||
template class Array<uint8_t, FunctionTable>;
|
||||
template class Array<uint16_t, FunctionTable>;
|
||||
template class Array<uint32_t, FunctionTable>;
|
||||
template class Array<uint64_t, FunctionTable>;
|
||||
template class Array<int8_t, FunctionTable>;
|
||||
template class Array<int16_t, FunctionTable>;
|
||||
template class Array<int32_t, FunctionTable>;
|
||||
template class Array<int64_t, FunctionTable>;
|
||||
template class Array<float, FunctionTable>;
|
||||
template class Array<double, FunctionTable>;
|
||||
template class Array<char,FunctionTable>;
|
||||
template class Array<uint8_t,FunctionTable>;
|
||||
template class Array<uint16_t,FunctionTable>;
|
||||
template class Array<uint32_t,FunctionTable>;
|
||||
template class Array<uint64_t,FunctionTable>;
|
||||
template class Array<int8_t,FunctionTable>;
|
||||
template class Array<int16_t,FunctionTable>;
|
||||
template class Array<int32_t,FunctionTable>;
|
||||
template class Array<int64_t,FunctionTable>;
|
||||
template class Array<float,FunctionTable>;
|
||||
template class Array<double,FunctionTable>;
|
||||
template class Array<long double,FunctionTable>;
|
||||
|
||||
|
||||
/********************************************************
|
||||
* Explicit instantiations of Array<bool> *
|
||||
********************************************************/
|
||||
// clang-format off
|
||||
template Array<bool, FunctionTable>::Array();
|
||||
template Array<bool, FunctionTable>::~Array();
|
||||
template Array<bool, FunctionTable>::Array( size_t );
|
||||
template Array<bool, FunctionTable>::Array( size_t, size_t );
|
||||
template Array<bool, FunctionTable>::Array( size_t, size_t, size_t );
|
||||
template Array<bool, FunctionTable>::Array( size_t, size_t, size_t, size_t );
|
||||
template Array<bool, FunctionTable>::Array( size_t, size_t, size_t, size_t, size_t );
|
||||
template Array<bool, FunctionTable>::Array( const std::vector<size_t>&, const bool* );
|
||||
template Array<bool, FunctionTable>::Array( std::string );
|
||||
template Array<bool, FunctionTable>::Array( std::initializer_list<bool> );
|
||||
template Array<bool, FunctionTable>::Array( const Array<bool, FunctionTable>& );
|
||||
template Array<bool, FunctionTable>::Array( Array<bool, FunctionTable>&& );
|
||||
template Array<bool, FunctionTable>& Array<bool, FunctionTable>::operator=( const Array<bool, FunctionTable>& );
|
||||
template Array<bool, FunctionTable>& Array<bool, FunctionTable>::operator=( Array<bool, FunctionTable>&& );
|
||||
template Array<bool, FunctionTable>& Array<bool, FunctionTable>::operator=( const std::vector<bool>& );
|
||||
template void Array<bool, FunctionTable>::fill(bool const&);
|
||||
template void Array<bool, FunctionTable>::clear();
|
||||
template bool Array<bool, FunctionTable>::operator==(Array<bool, FunctionTable> const&) const;
|
||||
template void Array<bool, FunctionTable>::resize( ArraySize const& );
|
||||
// clang-format on
|
||||
instantiateArrayConstructors( bool )
|
||||
template Array<bool,FunctionTable>& Array<bool,FunctionTable>::operator=( const std::vector<bool>& );
|
||||
template void Array<bool,FunctionTable>::clear();
|
||||
template bool Array<bool,FunctionTable>::operator==(Array<bool,FunctionTable> const&) const;
|
||||
template void Array<bool,FunctionTable>::resize( ArraySize const& );
|
||||
|
||||
|
||||
/********************************************************
|
||||
* Explicit instantiations of Array<std::complex> *
|
||||
********************************************************/
|
||||
// clang-format off
|
||||
template Array<std::complex<double>, FunctionTable>::Array();
|
||||
template Array<std::complex<double>, FunctionTable>::~Array();
|
||||
template Array<std::complex<double>, FunctionTable>::Array( size_t );
|
||||
template Array<std::complex<double>, FunctionTable>::Array( size_t, size_t );
|
||||
template Array<std::complex<double>, FunctionTable>::Array( size_t, size_t, size_t );
|
||||
template Array<std::complex<double>, FunctionTable>::Array( size_t, size_t, size_t, size_t );
|
||||
template Array<std::complex<double>, FunctionTable>::Array( size_t, size_t, size_t, size_t, size_t );
|
||||
template Array<std::complex<double>, FunctionTable>::Array( const std::vector<size_t>&, const std::complex<double>* );
|
||||
template Array<std::complex<double>, FunctionTable>::Array( std::initializer_list<std::complex<double>> );
|
||||
template Array<std::complex<double>, FunctionTable>::Array( const Range<std::complex<double>>& range );
|
||||
template Array<std::complex<double>, FunctionTable>::Array( const Array<std::complex<double>, FunctionTable>& );
|
||||
template Array<std::complex<double>, FunctionTable>::Array( Array<std::complex<double>, FunctionTable>&& );
|
||||
template Array<std::complex<double>, FunctionTable>& Array<std::complex<double>, FunctionTable>::operator=( const Array<std::complex<double>, FunctionTable>& );
|
||||
template Array<std::complex<double>, FunctionTable>& Array<std::complex<double>, FunctionTable>::operator=( Array<std::complex<double>, FunctionTable>&& );
|
||||
template Array<std::complex<double>, FunctionTable>& Array<std::complex<double>, FunctionTable>::operator=( const std::vector<std::complex<double>>& );
|
||||
template void Array<std::complex<double>, FunctionTable>::resize( ArraySize const& );
|
||||
template void Array<std::complex<double>, FunctionTable>::viewRaw( ArraySize const&, std::complex<double>*, bool, bool );
|
||||
template void Array<std::complex<double>, FunctionTable>::fill(std::complex<double> const&);
|
||||
template void Array<std::complex<double>, FunctionTable>::clear();
|
||||
template bool Array<std::complex<double>, FunctionTable>::operator==(Array<std::complex<double>, FunctionTable> const&) const;
|
||||
template Array<std::complex<double>, FunctionTable> Array<std::complex<double>, FunctionTable>::repmat(std::vector<unsigned long, std::allocator<unsigned long> > const&) const;
|
||||
// clang-format on
|
||||
instantiateArrayConstructors( std::complex<float> )
|
||||
instantiateArrayConstructors( std::complex<double> )
|
||||
template void Array<std::complex<float>,FunctionTable>::resize( ArraySize const& );
|
||||
template void Array<std::complex<double>,FunctionTable>::resize( ArraySize const& );
|
||||
template Array<std::complex<double>,FunctionTable>& Array<std::complex<double>,FunctionTable>::operator=(std::vector<std::complex<double>> const&);
|
||||
template Array<std::complex<float>,FunctionTable>& Array<std::complex<float>,FunctionTable>::operator=(std::vector<std::complex<float>> const&);
|
||||
template void Array<std::complex<float>,FunctionTable>::clear();
|
||||
template void Array<std::complex<double>,FunctionTable>::clear();
|
||||
template bool Array<std::complex<float>,FunctionTable>::operator==(Array<std::complex<float>,FunctionTable> const&) const;
|
||||
template bool Array<std::complex<double>,FunctionTable>::operator==(Array<std::complex<double>,FunctionTable> const&) const;
|
||||
template Array<std::complex<float>,FunctionTable> Array<std::complex<float>,FunctionTable>::repmat(std::vector<unsigned long> const&) const;
|
||||
template Array<std::complex<double>,FunctionTable> Array<std::complex<double>,FunctionTable>::repmat(std::vector<unsigned long> const&) const;
|
||||
template void Array<std::complex<float>,FunctionTable>::copySubset(std::vector<unsigned long> const&, Array<std::complex<float>,FunctionTable> const&);
|
||||
template void Array<std::complex<double>,FunctionTable>::copySubset(std::vector<unsigned long> const&, Array<std::complex<double>,FunctionTable> const&);
|
||||
template Array<std::complex<float>,FunctionTable> Array<std::complex<float>,FunctionTable>::subset(std::vector<unsigned long> const&) const;
|
||||
template Array<std::complex<double>,FunctionTable> Array<std::complex<double>,FunctionTable>::subset(std::vector<unsigned long> const&) const;
|
||||
template bool Array<std::complex<float>,FunctionTable>::NaNs() const;
|
||||
template bool Array<std::complex<double>,FunctionTable>::NaNs() const;
|
||||
|
||||
|
||||
/********************************************************
|
||||
* Explicit instantiations of Array<std::string> *
|
||||
********************************************************/
|
||||
// clang-format off
|
||||
template Array<std::string, FunctionTable>::Array();
|
||||
template Array<std::string, FunctionTable>::~Array();
|
||||
template Array<std::string, FunctionTable>::Array( size_t );
|
||||
template Array<std::string, FunctionTable>::Array( size_t, size_t );
|
||||
template Array<std::string, FunctionTable>::Array( size_t, size_t, size_t );
|
||||
template Array<std::string, FunctionTable>::Array( size_t, size_t, size_t, size_t );
|
||||
template Array<std::string, FunctionTable>::Array( size_t, size_t, size_t, size_t, size_t );
|
||||
template Array<std::string, FunctionTable>::Array( const std::vector<size_t>&, const std::string* );
|
||||
template Array<std::string, FunctionTable>::Array( std::initializer_list<std::string> );
|
||||
template Array<std::string, FunctionTable>::Array( const Array<std::string, FunctionTable>& );
|
||||
template Array<std::string, FunctionTable>::Array( Array<std::string, FunctionTable>&& );
|
||||
template Array<std::string, FunctionTable>& Array<std::string, FunctionTable>::operator=( const Array<std::string, FunctionTable>& );
|
||||
template Array<std::string, FunctionTable>& Array<std::string, FunctionTable>::operator=( Array<std::string, FunctionTable>&& );
|
||||
template Array<std::string, FunctionTable>& Array<std::string, FunctionTable>::operator=( const std::vector<std::string>& );
|
||||
template void Array<std::string, FunctionTable>::resize( ArraySize const& );
|
||||
// clang-format on
|
||||
instantiateArrayConstructors( std::string )
|
||||
template void Array<std::string,FunctionTable>::resize( ArraySize const& );
|
||||
template void Array<std::string,FunctionTable>::clear();
|
||||
template Array<std::string, FunctionTable> &Array<std::string, FunctionTable>::
|
||||
operator=( const std::vector<std::string> & );
|
||||
template bool Array<std::string>::operator==(Array<std::string> const&) const;
|
||||
|
||||
|
||||
#if defined( USING_ICC )
|
||||
ENABLE_WARNINGS
|
||||
#endif
|
||||
|
||||
|
||||
|
|
519
common/Array.h
519
common/Array.h
File diff suppressed because it is too large
Load Diff
1711
common/Array.hpp
1711
common/Array.hpp
File diff suppressed because it is too large
Load Diff
|
@ -1,54 +1,53 @@
|
|||
#ifndef included_ArraySizeClass
|
||||
#define included_ArraySizeClass
|
||||
|
||||
#include "common/Utilities.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <complex>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#if defined( __CUDA_ARCH__ )
|
||||
#if defined(__CUDA_ARCH__)
|
||||
#include <cuda.h>
|
||||
#define HOST_DEVICE __host__ __device__
|
||||
#else
|
||||
#define HOST_DEVICE
|
||||
#endif
|
||||
#if defined( USING_GCC ) || defined( USING_CLANG )
|
||||
#define ARRAY_ATTRIBUTE HOST_DEVICE __attribute__( ( always_inline ) )
|
||||
#if defined(USING_GCC) || defined(USING_CLANG)
|
||||
#define ARRAY_ATTRIBUTE HOST_DEVICE __attribute__((always_inline))
|
||||
#else
|
||||
#define ARRAY_ATTRIBUTE HOST_DEVICE
|
||||
#endif
|
||||
|
||||
|
||||
#if ( defined( DEBUG ) || defined( _DEBUG ) ) && !defined( NDEBUG )
|
||||
#define CHECK_ARRAY_LENGTH( i ) \
|
||||
do { \
|
||||
if ( i >= d_length ) \
|
||||
throw std::out_of_range( "Index exceeds array bounds" ); \
|
||||
} while ( 0 )
|
||||
#if (defined(DEBUG) || defined(_DEBUG)) && !defined(NDEBUG)
|
||||
#define CHECK_ARRAY_LENGTH(i, length) \
|
||||
do { \
|
||||
if (i >= length) \
|
||||
throw std::out_of_range("Index exceeds array bounds"); \
|
||||
} while (0)
|
||||
#else
|
||||
#define CHECK_ARRAY_LENGTH( i ) \
|
||||
do { \
|
||||
} while ( 0 )
|
||||
#define CHECK_ARRAY_LENGTH(i, length) \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
// Forward declerations
|
||||
class FunctionTable;
|
||||
template<class TYPE, class FUN = FunctionTable, class Allocator = std::nullptr_t>
|
||||
template <class TYPE, class FUN = FunctionTable,
|
||||
class Allocator = std::allocator<TYPE>>
|
||||
class Array;
|
||||
|
||||
|
||||
//! Simple range class
|
||||
template<class TYPE = size_t>
|
||||
class Range final
|
||||
{
|
||||
template <class TYPE = size_t> class Range final {
|
||||
public:
|
||||
//! Empty constructor
|
||||
constexpr Range() : i( 0 ), j( -1 ), k( 1 ) {}
|
||||
Range() : i(0), j(-1), k(1) {}
|
||||
|
||||
/*!
|
||||
* Create a range i:k:j (or i:j)
|
||||
|
@ -56,34 +55,49 @@ public:
|
|||
* @param j_ Ending value
|
||||
* @param k_ Increment value
|
||||
*/
|
||||
constexpr Range( TYPE i_, TYPE j_, TYPE k_ = 1 ) : i( i_ ), j( j_ ), k( k_ ) {}
|
||||
Range(const TYPE &i_, const TYPE &j_, const TYPE &k_ = 1)
|
||||
: i(i_), j(j_), k(k_) {}
|
||||
|
||||
//! Get the number of values in the range
|
||||
size_t size() const {
|
||||
if (std::is_integral<TYPE>::value) {
|
||||
return (static_cast<int64_t>(j) - static_cast<int64_t>(i)) /
|
||||
static_cast<int64_t>(k);
|
||||
} else if (std::is_floating_point<TYPE>::value) {
|
||||
double tmp = static_cast<double>((j - i)) / static_cast<double>(k);
|
||||
return static_cast<size_t>(floor(tmp + 1e-12) + 1);
|
||||
} else if (std::is_same<TYPE, std::complex<float>>::value ||
|
||||
std::is_same<TYPE, std::complex<double>>::value) {
|
||||
double tmp = std::real((j - i) / (k));
|
||||
return static_cast<size_t>(floor(tmp + 1e-12) + 1);
|
||||
} else {
|
||||
ERROR("Unsupported type for range");
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
TYPE i, j, k;
|
||||
};
|
||||
|
||||
|
||||
//! Simple class to store the array dimensions
|
||||
class ArraySize final
|
||||
{
|
||||
class ArraySize final {
|
||||
public:
|
||||
//! Empty constructor
|
||||
constexpr ArraySize() : d_ndim( 1 ), d_length( 0 ), d_N{ 0, 1, 1, 1, 1 } {}
|
||||
ArraySize() : d_ndim(1), d_length(0), d_N{0, 1, 1, 1, 1} {}
|
||||
|
||||
/*!
|
||||
* Create the vector size
|
||||
* @param N1 Number of elements in the first dimension
|
||||
*/
|
||||
constexpr ArraySize( size_t N1 ) : d_ndim( 1 ), d_length( N1 ), d_N{ N1, 1, 1, 1, 1 } {}
|
||||
ArraySize(size_t N1) : d_ndim(1), d_length(N1), d_N{N1, 1, 1, 1, 1} {}
|
||||
|
||||
/*!
|
||||
* Create the vector size
|
||||
* @param N1 Number of elements in the first dimension
|
||||
* @param N2 Number of elements in the second dimension
|
||||
*/
|
||||
constexpr ArraySize( size_t N1, size_t N2 )
|
||||
: d_ndim( 2 ), d_length( N1 * N2 ), d_N{ N1, N2, 1, 1, 1 }
|
||||
{
|
||||
}
|
||||
ArraySize(size_t N1, size_t N2)
|
||||
: d_ndim(2), d_length(N1 * N2), d_N{N1, N2, 1, 1, 1} {}
|
||||
|
||||
/*!
|
||||
* Create the vector size
|
||||
|
@ -91,10 +105,8 @@ public:
|
|||
* @param N2 Number of elements in the second dimension
|
||||
* @param N3 Number of elements in the third dimension
|
||||
*/
|
||||
constexpr ArraySize( size_t N1, size_t N2, size_t N3 )
|
||||
: d_ndim( 3 ), d_length( N1 * N2 * N3 ), d_N{ N1, N2, N3, 1, 1 }
|
||||
{
|
||||
}
|
||||
ArraySize(size_t N1, size_t N2, size_t N3)
|
||||
: d_ndim(3), d_length(N1 * N2 * N3), d_N{N1, N2, N3, 1, 1} {}
|
||||
|
||||
/*!
|
||||
* Create the vector size
|
||||
|
@ -103,10 +115,8 @@ public:
|
|||
* @param N3 Number of elements in the third dimension
|
||||
* @param N4 Number of elements in the fourth dimension
|
||||
*/
|
||||
constexpr ArraySize( size_t N1, size_t N2, size_t N3, size_t N4 )
|
||||
: d_ndim( 4 ), d_length( N1 * N2 * N3 * N4 ), d_N{ N1, N2, N3, N4, 1 }
|
||||
{
|
||||
}
|
||||
ArraySize(size_t N1, size_t N2, size_t N3, size_t N4)
|
||||
: d_ndim(4), d_length(N1 * N2 * N3 * N4), d_N{N1, N2, N3, N4, 1} {}
|
||||
|
||||
/*!
|
||||
* Create the vector size
|
||||
|
@ -116,85 +126,91 @@ public:
|
|||
* @param N4 Number of elements in the fourth dimension
|
||||
* @param N5 Number of elements in the fifth dimension
|
||||
*/
|
||||
constexpr ArraySize( size_t N1, size_t N2, size_t N3, size_t N4, size_t N5 )
|
||||
: d_ndim( 5 ), d_length( N1 * N2 * N3 * N4 * N5 ), d_N{ N1, N2, N3, N4, N5 }
|
||||
{
|
||||
ArraySize(size_t N1, size_t N2, size_t N3, size_t N4, size_t N5)
|
||||
: d_ndim(5), d_length(N1 * N2 * N3 * N4 * N5), d_N{N1, N2, N3, N4, N5} {
|
||||
}
|
||||
|
||||
/*!
|
||||
* Create from initializer list
|
||||
* @param N Size of the array
|
||||
* @param ndim Number of dimensions
|
||||
*/
|
||||
constexpr ArraySize( std::initializer_list<size_t> N )
|
||||
: d_ndim( N.size() ), d_length( 0 ), d_N{ 0, 1, 1, 1, 1 }
|
||||
{
|
||||
if ( d_ndim > maxDim() )
|
||||
throw std::out_of_range( "Maximum number of dimensions exceeded" );
|
||||
ArraySize(std::initializer_list<size_t> N, int ndim = -1)
|
||||
: d_ndim(N.size()), d_length(0), d_N{0, 1, 1, 1, 1} {
|
||||
if (ndim >= 0)
|
||||
d_ndim = ndim;
|
||||
if (d_ndim > 5)
|
||||
throw std::out_of_range("Maximum number of dimensions exceeded");
|
||||
auto it = N.begin();
|
||||
for ( size_t i = 0; i < d_ndim; i++, ++it )
|
||||
for (size_t i = 0; i < d_ndim; i++, ++it)
|
||||
d_N[i] = *it;
|
||||
d_length = 1;
|
||||
for ( unsigned long i : d_N )
|
||||
for (unsigned long i : d_N)
|
||||
d_length *= i;
|
||||
if ( d_ndim == 0 )
|
||||
if (d_ndim == 0)
|
||||
d_length = 0;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Create from raw pointer
|
||||
* @param ndim Number of dimensions
|
||||
* @param dims Dimensions
|
||||
*/
|
||||
constexpr ArraySize( size_t ndim, const size_t *dims )
|
||||
: d_ndim( ndim ), d_length( 0 ), d_N{ 0, 1, 1, 1, 1 }
|
||||
{
|
||||
if ( d_ndim > maxDim() )
|
||||
throw std::out_of_range( "Maximum number of dimensions exceeded" );
|
||||
for ( size_t i = 0; i < ndim; i++ )
|
||||
ArraySize(size_t ndim, const size_t *dims)
|
||||
: d_ndim(ndim), d_length(0), d_N{0, 1, 1, 1, 1} {
|
||||
if (d_ndim > 5)
|
||||
throw std::out_of_range("Maximum number of dimensions exceeded");
|
||||
for (size_t i = 0; i < ndim; i++)
|
||||
d_N[i] = dims[i];
|
||||
d_length = 1;
|
||||
for ( unsigned long i : d_N )
|
||||
for (unsigned long i : d_N)
|
||||
d_length *= i;
|
||||
if ( d_ndim == 0 )
|
||||
if (d_ndim == 0)
|
||||
d_length = 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Create from std::array
|
||||
* @param N Size of the array
|
||||
*/
|
||||
template <std::size_t NDIM>
|
||||
ArraySize(const std::array<size_t, NDIM> &N) : ArraySize(NDIM, N.data()) {}
|
||||
|
||||
/*!
|
||||
* Create from std::vector
|
||||
* @param N Size of the array
|
||||
*/
|
||||
ArraySize( const std::vector<size_t> &N );
|
||||
inline ArraySize(const std::vector<size_t> &N)
|
||||
: ArraySize(N.size(), N.data()) {}
|
||||
|
||||
// Copy/assignment constructors
|
||||
constexpr ArraySize( ArraySize &&rhs ) = default;
|
||||
constexpr ArraySize( const ArraySize &rhs ) = default;
|
||||
constexpr ArraySize &operator=( ArraySize &&rhs ) = default;
|
||||
constexpr ArraySize &operator=( const ArraySize &rhs ) = default;
|
||||
ArraySize(ArraySize &&rhs) = default;
|
||||
ArraySize(const ArraySize &rhs) = default;
|
||||
ArraySize &operator=(ArraySize &&rhs) = default;
|
||||
ArraySize &operator=(const ArraySize &rhs) = default;
|
||||
|
||||
/*!
|
||||
* Access the ith dimension
|
||||
* @param i Index to access
|
||||
*/
|
||||
constexpr ARRAY_ATTRIBUTE size_t operator[]( size_t i ) const { return d_N[i]; }
|
||||
ARRAY_ATTRIBUTE size_t operator[](size_t i) const { return d_N[i]; }
|
||||
|
||||
//! Return the number of dimensions
|
||||
constexpr ARRAY_ATTRIBUTE uint8_t ndim() const { return d_ndim; }
|
||||
ARRAY_ATTRIBUTE uint8_t ndim() const { return d_ndim; }
|
||||
|
||||
//! Return the number of dimensions
|
||||
constexpr ARRAY_ATTRIBUTE size_t size() const { return d_ndim; }
|
||||
ARRAY_ATTRIBUTE size_t size() const { return d_ndim; }
|
||||
|
||||
//! Return the total number of elements in the array
|
||||
constexpr ARRAY_ATTRIBUTE size_t length() const { return d_length; }
|
||||
ARRAY_ATTRIBUTE size_t length() const { return d_length; }
|
||||
|
||||
//! Resize the dimension
|
||||
constexpr void resize( uint8_t dim, size_t N )
|
||||
{
|
||||
if ( dim >= d_ndim )
|
||||
throw std::out_of_range( "Invalid dimension" );
|
||||
void resize(uint8_t dim, size_t N) {
|
||||
if (dim >= d_ndim)
|
||||
throw std::out_of_range("Invalid dimension");
|
||||
d_N[dim] = N;
|
||||
d_length = 1;
|
||||
for ( unsigned long i : d_N )
|
||||
for (unsigned long i : d_N)
|
||||
d_length *= i;
|
||||
}
|
||||
|
||||
|
@ -203,94 +219,173 @@ public:
|
|||
* max of ndim and the largest dim>1.
|
||||
* @param ndim Desired number of dimensions
|
||||
*/
|
||||
constexpr void setNdim( uint8_t ndim ) { d_ndim = std::max( ndim, d_ndim ); }
|
||||
void setNdim(uint8_t ndim) { d_ndim = std::max(ndim, d_ndim); }
|
||||
|
||||
/*!
|
||||
* Remove singleton dimensions
|
||||
*/
|
||||
void squeeze() {
|
||||
d_ndim = 0;
|
||||
for (uint8_t i = 0; i < maxDim(); i++) {
|
||||
if (d_N[i] != 1)
|
||||
d_N[d_ndim++] = d_N[i];
|
||||
}
|
||||
}
|
||||
|
||||
//! Returns an iterator to the beginning
|
||||
constexpr const size_t *begin() const { return d_N; }
|
||||
const size_t *begin() const { return d_N; }
|
||||
|
||||
//! Returns an iterator to the end
|
||||
constexpr const size_t *end() const { return d_N + d_ndim; }
|
||||
const size_t *end() const { return d_N + d_ndim; }
|
||||
|
||||
// Check if two array sizes are equal
|
||||
constexpr ARRAY_ATTRIBUTE bool operator==( const ArraySize &rhs ) const
|
||||
{
|
||||
return d_ndim == rhs.d_ndim && memcmp( d_N, rhs.d_N, sizeof( d_N ) ) == 0;
|
||||
ARRAY_ATTRIBUTE bool operator==(const ArraySize &rhs) const {
|
||||
return d_ndim == rhs.d_ndim && memcmp(d_N, rhs.d_N, sizeof(d_N)) == 0;
|
||||
}
|
||||
|
||||
// Check if two array sizes are equal (ignoring the dimension)
|
||||
constexpr ARRAY_ATTRIBUTE bool approxEqual( const ArraySize &rhs ) const
|
||||
{
|
||||
return ( length() == 0 && rhs.length() == 0 ) || memcmp( d_N, rhs.d_N, sizeof( d_N ) ) == 0;
|
||||
ARRAY_ATTRIBUTE bool approxEqual(const ArraySize &rhs) const {
|
||||
return (length() == 0 && rhs.length() == 0) ||
|
||||
memcmp(d_N, rhs.d_N, sizeof(d_N)) == 0;
|
||||
}
|
||||
|
||||
//! Check if two matrices are not equal
|
||||
constexpr ARRAY_ATTRIBUTE bool operator!=( const ArraySize &rhs ) const
|
||||
{
|
||||
return d_ndim != rhs.d_ndim || memcmp( d_N, rhs.d_N, sizeof( d_N ) ) != 0;
|
||||
ARRAY_ATTRIBUTE bool operator!=(const ArraySize &rhs) const {
|
||||
return d_ndim != rhs.d_ndim || memcmp(d_N, rhs.d_N, sizeof(d_N)) != 0;
|
||||
}
|
||||
|
||||
//! Maximum supported dimension
|
||||
constexpr ARRAY_ATTRIBUTE static uint8_t maxDim() { return 5u; }
|
||||
ARRAY_ATTRIBUTE static uint8_t maxDim() { return 5; }
|
||||
|
||||
//! Get the index
|
||||
constexpr ARRAY_ATTRIBUTE size_t index( size_t i ) const
|
||||
{
|
||||
CHECK_ARRAY_LENGTH( i );
|
||||
ARRAY_ATTRIBUTE size_t index(size_t i) const {
|
||||
CHECK_ARRAY_LENGTH(i, d_length);
|
||||
return i;
|
||||
}
|
||||
|
||||
//! Get the index
|
||||
constexpr ARRAY_ATTRIBUTE size_t index( size_t i1, size_t i2 ) const
|
||||
{
|
||||
ARRAY_ATTRIBUTE size_t index(size_t i1, size_t i2) const {
|
||||
size_t index = i1 + i2 * d_N[0];
|
||||
CHECK_ARRAY_LENGTH( index );
|
||||
CHECK_ARRAY_LENGTH(index, d_length);
|
||||
return index;
|
||||
}
|
||||
|
||||
//! Get the index
|
||||
constexpr ARRAY_ATTRIBUTE size_t index( size_t i1, size_t i2, size_t i3 ) const
|
||||
{
|
||||
size_t index = i1 + d_N[0] * ( i2 + d_N[1] * i3 );
|
||||
CHECK_ARRAY_LENGTH( index );
|
||||
ARRAY_ATTRIBUTE size_t index(size_t i1, size_t i2, size_t i3) const {
|
||||
size_t index = i1 + d_N[0] * (i2 + d_N[1] * i3);
|
||||
CHECK_ARRAY_LENGTH(index, d_length);
|
||||
return index;
|
||||
}
|
||||
|
||||
//! Get the index
|
||||
constexpr ARRAY_ATTRIBUTE size_t index( size_t i1, size_t i2, size_t i3, size_t i4 ) const
|
||||
{
|
||||
size_t index = i1 + d_N[0] * ( i2 + d_N[1] * ( i3 + d_N[2] * i4 ) );
|
||||
CHECK_ARRAY_LENGTH( index );
|
||||
ARRAY_ATTRIBUTE size_t index(size_t i1, size_t i2, size_t i3,
|
||||
size_t i4) const {
|
||||
size_t index = i1 + d_N[0] * (i2 + d_N[1] * (i3 + d_N[2] * i4));
|
||||
CHECK_ARRAY_LENGTH(index, d_length);
|
||||
return index;
|
||||
}
|
||||
|
||||
//! Get the index
|
||||
constexpr ARRAY_ATTRIBUTE size_t index(
|
||||
size_t i1, size_t i2, size_t i3, size_t i4, size_t i5 ) const
|
||||
{
|
||||
size_t index = i1 + d_N[0] * ( i2 + d_N[1] * ( i3 + d_N[2] * ( i4 + d_N[3] * i5 ) ) );
|
||||
CHECK_ARRAY_LENGTH( index );
|
||||
ARRAY_ATTRIBUTE size_t index(size_t i1, size_t i2, size_t i3, size_t i4,
|
||||
size_t i5) const {
|
||||
size_t index =
|
||||
i1 + d_N[0] * (i2 + d_N[1] * (i3 + d_N[2] * (i4 + d_N[3] * i5)));
|
||||
CHECK_ARRAY_LENGTH(index, d_length);
|
||||
return index;
|
||||
}
|
||||
|
||||
//! Get the index
|
||||
size_t index(const std::array<size_t, 5> &i) const {
|
||||
size_t j = 0;
|
||||
for (size_t m = 0, N = 1; m < 5; m++) {
|
||||
j += i[m] * N;
|
||||
N *= d_N[m];
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
//! Get the index
|
||||
size_t index(std::initializer_list<size_t> i) const {
|
||||
size_t N = 1;
|
||||
size_t j = 0;
|
||||
size_t m = 0;
|
||||
for (size_t k : i) {
|
||||
j += k * N;
|
||||
N *= d_N[m++];
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
//! Convert the index to ijk values
|
||||
std::array<size_t, 5> ijk(size_t index) const {
|
||||
CHECK_ARRAY_LENGTH(index, d_length);
|
||||
size_t i0 = index % d_N[0];
|
||||
index = index / d_N[0];
|
||||
size_t i1 = index % d_N[1];
|
||||
index = index / d_N[1];
|
||||
size_t i2 = index % d_N[2];
|
||||
index = index / d_N[2];
|
||||
size_t i3 = index % d_N[3];
|
||||
index = index / d_N[3];
|
||||
return {i0, i1, i2, i3, index};
|
||||
}
|
||||
|
||||
//! Convert the index to ijk values
|
||||
void ijk(size_t index, size_t *x) const {
|
||||
CHECK_ARRAY_LENGTH(index, d_length);
|
||||
x[0] = index % d_N[0];
|
||||
index = index / d_N[0];
|
||||
x[1] = index % d_N[1];
|
||||
index = index / d_N[1];
|
||||
x[2] = index % d_N[2];
|
||||
index = index / d_N[2];
|
||||
x[3] = index % d_N[3];
|
||||
index = index / d_N[3];
|
||||
x[4] = index;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t d_ndim;
|
||||
size_t d_length;
|
||||
size_t d_N[5];
|
||||
};
|
||||
|
||||
|
||||
// Function to concatenate dimensions of two array sizes
|
||||
constexpr ArraySize cat( const ArraySize &x, const ArraySize &y )
|
||||
{
|
||||
if ( x.ndim() + y.ndim() > ArraySize::maxDim() )
|
||||
throw std::out_of_range( "Maximum number of dimensions exceeded" );
|
||||
size_t N[ArraySize::maxDim()] = { 0 };
|
||||
for ( int i = 0; i < x.ndim(); i++ )
|
||||
inline ArraySize cat(const ArraySize &x, const ArraySize &y) {
|
||||
if (x.ndim() + y.ndim() > 5)
|
||||
throw std::out_of_range("Maximum number of dimensions exceeded");
|
||||
size_t N[5] = {0};
|
||||
for (int i = 0; i < x.ndim(); i++)
|
||||
N[i] = x[i];
|
||||
for ( int i = 0; i < y.ndim(); i++ )
|
||||
for (int i = 0; i < y.ndim(); i++)
|
||||
N[i + x.ndim()] = y[i];
|
||||
return ArraySize( x.ndim() + y.ndim(), N );
|
||||
return ArraySize(x.ndim() + y.ndim(), N);
|
||||
}
|
||||
|
||||
// Operator overloads
|
||||
inline ArraySize operator*(size_t v, const ArraySize &x) {
|
||||
size_t N[5] = {v * x[0], v * x[1], v * x[2], v * x[3], v * x[4]};
|
||||
return ArraySize(x.ndim(), N);
|
||||
}
|
||||
inline ArraySize operator*(const ArraySize &x, size_t v) {
|
||||
size_t N[5] = {v * x[0], v * x[1], v * x[2], v * x[3], v * x[4]};
|
||||
return ArraySize(x.ndim(), N);
|
||||
}
|
||||
inline ArraySize operator-(const ArraySize &x, size_t v) {
|
||||
size_t N[5] = {x[0] - v, x[1] - v, x[2] - v, x[3] - v, x[4] - v};
|
||||
return ArraySize(x.ndim(), N);
|
||||
}
|
||||
inline ArraySize operator+(const ArraySize &x, size_t v) {
|
||||
size_t N[5] = {x[0] + v, x[1] + v, x[2] + v, x[3] + v, x[4] + v};
|
||||
return ArraySize(x.ndim(), N);
|
||||
}
|
||||
inline ArraySize operator+(size_t v, const ArraySize &x) {
|
||||
size_t N[5] = {x[0] + v, x[1] + v, x[2] + v, x[3] + v, x[4] + v};
|
||||
return ArraySize(x.ndim(), N);
|
||||
}
|
||||
|
||||
#if defined(USING_ICC)
|
||||
ENABLE_WARNINGS
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,99 +1,107 @@
|
|||
#include "common/Communication.h"
|
||||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "common/Communication.h"
|
||||
|
||||
/********************************************************
|
||||
* Structure to store the rank info *
|
||||
********************************************************/
|
||||
int RankInfoStruct::getRankForBlock( int i, int j, int k ) const
|
||||
{
|
||||
int i2 = (i+nx)%nx;
|
||||
int j2 = (j+ny)%ny;
|
||||
int k2 = (k+nz)%nz;
|
||||
return i2 + j2*nx + k2*nx*ny;
|
||||
int RankInfoStruct::getRankForBlock(int i, int j, int k) const {
|
||||
int i2 = (i + nx) % nx;
|
||||
int j2 = (j + ny) % ny;
|
||||
int k2 = (k + nz) % nz;
|
||||
return i2 + j2 * nx + k2 * nx * ny;
|
||||
}
|
||||
RankInfoStruct::RankInfoStruct()
|
||||
{
|
||||
RankInfoStruct::RankInfoStruct() {
|
||||
nx = 0;
|
||||
ny = 0;
|
||||
nz = 0;
|
||||
ix = -1;
|
||||
jy = -1;
|
||||
kz = -1;
|
||||
for (int i=-1; i<=1; i++) {
|
||||
for (int j=-1; j<=1; j++) {
|
||||
for (int k=-1; k<=1; k++) {
|
||||
rank[i+1][j+1][k+1] = -1;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
rank[i + 1][j + 1][k + 1] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
RankInfoStruct::RankInfoStruct( int rank0, int nprocx, int nprocy, int nprocz )
|
||||
{
|
||||
memset(this,0,sizeof(RankInfoStruct));
|
||||
RankInfoStruct::RankInfoStruct(int rank0, int nprocx, int nprocy, int nprocz) {
|
||||
memset(this, 0, sizeof(RankInfoStruct));
|
||||
nx = nprocx;
|
||||
ny = nprocy;
|
||||
nz = nprocz;
|
||||
if ( rank0 >= nprocx * nprocy * nprocz ) {
|
||||
ix = -1;
|
||||
jy = -1;
|
||||
kz = -1;
|
||||
for (int i=-1; i<=1; i++) {
|
||||
for (int j=-1; j<=1; j++) {
|
||||
for (int k=-1; k<=1; k++) {
|
||||
rank[i+1][j+1][k+1] = -1;
|
||||
if (rank0 >= nprocx * nprocy * nprocz) {
|
||||
ix = -1;
|
||||
jy = -1;
|
||||
kz = -1;
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
rank[i + 1][j + 1][k + 1] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ix = rank0%nprocx;
|
||||
jy = (rank0/nprocx)%nprocy;
|
||||
kz = rank0/(nprocx*nprocy);
|
||||
for (int i=-1; i<=1; i++) {
|
||||
for (int j=-1; j<=1; j++) {
|
||||
for (int k=-1; k<=1; k++) {
|
||||
rank[i+1][j+1][k+1] = getRankForBlock(ix+i,jy+j,kz+k);
|
||||
ix = rank0 % nprocx;
|
||||
jy = (rank0 / nprocx) % nprocy;
|
||||
kz = rank0 / (nprocx * nprocy);
|
||||
for (int i = -1; i <= 1; i++) {
|
||||
for (int j = -1; j <= 1; j++) {
|
||||
for (int k = -1; k <= 1; k++) {
|
||||
rank[i + 1][j + 1][k + 1] =
|
||||
getRankForBlock(ix + i, jy + j, kz + k);
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT(rank[1][1][1]==rank0);
|
||||
ASSERT(rank[1][1][1] == rank0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* Deprecated functions *
|
||||
********************************************************/
|
||||
void InitializeRanks( const int rank, const int nprocx, const int nprocy, const int nprocz,
|
||||
int& iproc, int& jproc, int& kproc,
|
||||
int& rank_x, int& rank_y, int& rank_z,
|
||||
int& rank_X, int& rank_Y, int& rank_Z,
|
||||
int& rank_xy, int& rank_XY, int& rank_xY, int& rank_Xy,
|
||||
int& rank_xz, int& rank_XZ, int& rank_xZ, int& rank_Xz,
|
||||
int& rank_yz, int& rank_YZ, int& rank_yZ, int& rank_Yz )
|
||||
{
|
||||
const RankInfoStruct data(rank,nprocx,nprocy,nprocz);
|
||||
iproc = data.ix;
|
||||
void InitializeRanks(const int rank, const int nprocx, const int nprocy,
|
||||
const int nprocz, int &iproc, int &jproc, int &kproc,
|
||||
int &rank_x, int &rank_y, int &rank_z, int &rank_X,
|
||||
int &rank_Y, int &rank_Z, int &rank_xy, int &rank_XY,
|
||||
int &rank_xY, int &rank_Xy, int &rank_xz, int &rank_XZ,
|
||||
int &rank_xZ, int &rank_Xz, int &rank_yz, int &rank_YZ,
|
||||
int &rank_yZ, int &rank_Yz) {
|
||||
const RankInfoStruct data(rank, nprocx, nprocy, nprocz);
|
||||
iproc = data.ix;
|
||||
jproc = data.jy;
|
||||
kproc = data.kz;
|
||||
rank_X = data.rank[2][1][1];
|
||||
rank_x = data.rank[0][1][1];
|
||||
rank_Y = data.rank[1][2][1];
|
||||
rank_y = data.rank[1][0][1];
|
||||
rank_Z = data.rank[1][1][2];
|
||||
rank_z = data.rank[1][1][0];
|
||||
rank_XY = data.rank[2][2][1];
|
||||
rank_xy = data.rank[0][0][1];
|
||||
rank_Xy = data.rank[2][0][1];
|
||||
rank_xY = data.rank[0][2][1];
|
||||
rank_XZ = data.rank[2][1][2];
|
||||
rank_xz = data.rank[0][1][0];
|
||||
rank_Xz = data.rank[2][1][0];
|
||||
rank_xZ = data.rank[0][1][2];
|
||||
rank_YZ = data.rank[1][2][2];
|
||||
rank_yz = data.rank[1][0][0];
|
||||
rank_Yz = data.rank[1][2][0];
|
||||
rank_yZ = data.rank[1][0][2];
|
||||
rank_X = data.rank[2][1][1];
|
||||
rank_x = data.rank[0][1][1];
|
||||
rank_Y = data.rank[1][2][1];
|
||||
rank_y = data.rank[1][0][1];
|
||||
rank_Z = data.rank[1][1][2];
|
||||
rank_z = data.rank[1][1][0];
|
||||
rank_XY = data.rank[2][2][1];
|
||||
rank_xy = data.rank[0][0][1];
|
||||
rank_Xy = data.rank[2][0][1];
|
||||
rank_xY = data.rank[0][2][1];
|
||||
rank_XZ = data.rank[2][1][2];
|
||||
rank_xz = data.rank[0][1][0];
|
||||
rank_Xz = data.rank[2][1][0];
|
||||
rank_xZ = data.rank[0][1][2];
|
||||
rank_YZ = data.rank[1][2][2];
|
||||
rank_yz = data.rank[1][0][0];
|
||||
rank_Yz = data.rank[1][2][0];
|
||||
rank_yZ = data.rank[1][0][2];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef COMMUNICATION_H_INC
|
||||
#define COMMUNICATION_H_INC
|
||||
|
||||
|
@ -16,41 +32,39 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Rank info structure
|
||||
* @details Structure used to hold the ranks for the current process and it's neighbors
|
||||
*/
|
||||
struct RankInfoStruct {
|
||||
int nx; //!< The number of processors in the x direction
|
||||
int ny; //!< The number of processors in the y direction
|
||||
int nz; //!< The number of processors in the z direction
|
||||
int ix; //!< The index of the current process in the x direction
|
||||
int jy; //!< The index of the current process in the y direction
|
||||
int kz; //!< The index of the current process in the z direction
|
||||
int rank[3][3][3]; //!< The rank for the neighbor [i][j][k]
|
||||
int nx; //!< The number of processors in the x direction
|
||||
int ny; //!< The number of processors in the y direction
|
||||
int nz; //!< The number of processors in the z direction
|
||||
int ix; //!< The index of the current process in the x direction
|
||||
int jy; //!< The index of the current process in the y direction
|
||||
int kz; //!< The index of the current process in the z direction
|
||||
int rank[3][3][3]; //!< The rank for the neighbor [i][j][k]
|
||||
RankInfoStruct();
|
||||
RankInfoStruct( int rank, int nprocx, int nprocy, int nprocz );
|
||||
int getRankForBlock( int i, int j, int k ) const;
|
||||
RankInfoStruct(int rank, int nprocx, int nprocy, int nprocz);
|
||||
int getRankForBlock(int i, int j, int k) const;
|
||||
};
|
||||
|
||||
|
||||
//! Redistribute domain data (dst may be smaller than the src)
|
||||
template<class TYPE>
|
||||
Array<TYPE> redistribute( const RankInfoStruct& src_rank, const Array<TYPE>& src_data,
|
||||
const RankInfoStruct& dst_rank, std::array<int,3> dst_size, const Utilities::MPI& comm );
|
||||
|
||||
template <class TYPE>
|
||||
Array<TYPE>
|
||||
redistribute(const RankInfoStruct &src_rank, const Array<TYPE> &src_data,
|
||||
const RankInfoStruct &dst_rank, std::array<int, 3> dst_size,
|
||||
const Utilities::MPI &comm);
|
||||
|
||||
/*!
|
||||
* @brief Communicate halo
|
||||
* @details Fill the halo cells in an array from the neighboring processes
|
||||
*/
|
||||
template<class TYPE>
|
||||
class fillHalo
|
||||
{
|
||||
template <class TYPE> class fillHalo {
|
||||
public:
|
||||
/*!
|
||||
* @brief Default constructor
|
||||
* @param[in] comm Communicator to use
|
||||
* @param[in] info Rank and neighbor rank info
|
||||
* @param[in] n Number of local cells
|
||||
* @param[in] ng Number of ghost cells
|
||||
|
@ -59,37 +73,36 @@ public:
|
|||
* @param[in] fill Fill {faces,edges,corners}
|
||||
* @param[in] periodic Periodic dimensions
|
||||
*/
|
||||
fillHalo( const Utilities::MPI& comm, const RankInfoStruct& info,
|
||||
std::array<int,3> n, std::array<int,3> ng, int tag, int depth,
|
||||
std::array<bool,3> fill = {true,true,true},
|
||||
std::array<bool,3> periodic = {true,true,true} );
|
||||
fillHalo(const Utilities::MPI &comm, const RankInfoStruct &info,
|
||||
std::array<int, 3> n, std::array<int, 3> ng, int tag, int depth,
|
||||
std::array<bool, 3> fill = {true, true, true},
|
||||
std::array<bool, 3> periodic = {true, true, true});
|
||||
|
||||
//! Destructor
|
||||
~fillHalo( );
|
||||
~fillHalo();
|
||||
|
||||
fillHalo() = delete;
|
||||
fillHalo(const fillHalo&) = delete;
|
||||
fillHalo& operator=(const fillHalo&) = delete;
|
||||
fillHalo(const fillHalo &) = delete;
|
||||
fillHalo &operator=(const fillHalo &) = delete;
|
||||
|
||||
/*!
|
||||
* @brief Communicate the halos
|
||||
* @param[in] array The array on which we fill the halos
|
||||
*/
|
||||
void fill( Array<TYPE>& array );
|
||||
void fill(Array<TYPE> &array);
|
||||
|
||||
/*!
|
||||
* @brief Copy data from the src array to the dst array
|
||||
* @param[in] src The src array with or without halos
|
||||
* @param[in] dst The dst array with or without halos
|
||||
*/
|
||||
template<class TYPE1, class TYPE2>
|
||||
void copy( const Array<TYPE1>& src, Array<TYPE2>& dst );
|
||||
|
||||
template <class TYPE1, class TYPE2>
|
||||
void copy(const Array<TYPE1> &src, Array<TYPE2> &dst);
|
||||
|
||||
private:
|
||||
Utilities::MPI comm;
|
||||
RankInfoStruct info;
|
||||
std::array<int,3> n, ng;
|
||||
std::array<int, 3> n, ng;
|
||||
int depth;
|
||||
bool fill_pattern[3][3][3];
|
||||
int tag[3][3][3];
|
||||
|
@ -97,107 +110,103 @@ private:
|
|||
TYPE *mem;
|
||||
TYPE *send[3][3][3], *recv[3][3][3];
|
||||
MPI_Request send_req[3][3][3], recv_req[3][3][3];
|
||||
void pack( const Array<TYPE>& array, int i, int j, int k, TYPE *buffer );
|
||||
void unpack( Array<TYPE>& array, int i, int j, int k, const TYPE *buffer );
|
||||
void pack(const Array<TYPE> &array, int i, int j, int k, TYPE *buffer);
|
||||
void unpack(Array<TYPE> &array, int i, int j, int k, const TYPE *buffer);
|
||||
};
|
||||
|
||||
|
||||
//***************************************************************************************
|
||||
inline void PackMeshData(const int *list, int count, double *sendbuf, double *data){
|
||||
// Fill in the phase ID values from neighboring processors
|
||||
// This packs up the values that need to be sent from one processor to another
|
||||
int idx,n;
|
||||
for (idx=0; idx<count; idx++){
|
||||
n = list[idx];
|
||||
sendbuf[idx] = data[n];
|
||||
}
|
||||
inline void PackMeshData(const int *list, int count, double *sendbuf,
|
||||
double *data) {
|
||||
// Fill in the phase ID values from neighboring processors
|
||||
// This packs up the values that need to be sent from one processor to another
|
||||
int idx, n;
|
||||
for (idx = 0; idx < count; idx++) {
|
||||
n = list[idx];
|
||||
sendbuf[idx] = data[n];
|
||||
}
|
||||
}
|
||||
inline void UnpackMeshData(const int *list, int count, double *recvbuf, double *data){
|
||||
// Fill in the phase ID values from neighboring processors
|
||||
// This unpacks the values once they have been recieved from neighbors
|
||||
int idx,n;
|
||||
inline void UnpackMeshData(const int *list, int count, double *recvbuf,
|
||||
double *data) {
|
||||
// Fill in the phase ID values from neighboring processors
|
||||
// This unpacks the values once they have been recieved from neighbors
|
||||
int idx, n;
|
||||
|
||||
for (idx=0; idx<count; idx++){
|
||||
n = list[idx];
|
||||
data[n] = recvbuf[idx];
|
||||
}
|
||||
for (idx = 0; idx < count; idx++) {
|
||||
n = list[idx];
|
||||
data[n] = recvbuf[idx];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Initialize the ranks (this is deprecated, see RankInfoStruct)
|
||||
void InitializeRanks( const int rank, const int nprocx, const int nprocy, const int nprocz,
|
||||
int& iproc, int& jproc, int& kproc,
|
||||
int& rank_x, int& rank_y, int& rank_z,
|
||||
int& rank_X, int& rank_Y, int& rank_Z,
|
||||
int& rank_xy, int& rank_XY, int& rank_xY, int& rank_Xy,
|
||||
int& rank_xz, int& rank_XZ, int& rank_xZ, int& rank_Xz,
|
||||
int& rank_yz, int& rank_YZ, int& rank_yZ, int& rank_Yz );
|
||||
|
||||
void InitializeRanks(const int rank, const int nprocx, const int nprocy,
|
||||
const int nprocz, int &iproc, int &jproc, int &kproc,
|
||||
int &rank_x, int &rank_y, int &rank_z, int &rank_X,
|
||||
int &rank_Y, int &rank_Z, int &rank_xy, int &rank_XY,
|
||||
int &rank_xY, int &rank_Xy, int &rank_xz, int &rank_XZ,
|
||||
int &rank_xZ, int &rank_Xz, int &rank_yz, int &rank_YZ,
|
||||
int &rank_yZ, int &rank_Yz);
|
||||
|
||||
//***************************************************************************************
|
||||
inline void CommunicateSendRecvCounts( const Utilities::MPI& comm, int sendtag, int recvtag,
|
||||
int rank_x, int rank_y, int rank_z,
|
||||
int rank_X, int rank_Y, int rank_Z,
|
||||
int rank_xy, int rank_XY, int rank_xY, int rank_Xy,
|
||||
int rank_xz, int rank_XZ, int rank_xZ, int rank_Xz,
|
||||
int rank_yz, int rank_YZ, int rank_yZ, int rank_Yz,
|
||||
int sendCount_x, int sendCount_y, int sendCount_z,
|
||||
int sendCount_X, int sendCount_Y, int sendCount_Z,
|
||||
int sendCount_xy, int sendCount_XY, int sendCount_xY, int sendCount_Xy,
|
||||
int sendCount_xz, int sendCount_XZ, int sendCount_xZ, int sendCount_Xz,
|
||||
int sendCount_yz, int sendCount_YZ, int sendCount_yZ, int sendCount_Yz,
|
||||
int& recvCount_x, int& recvCount_y, int& recvCount_z,
|
||||
int& recvCount_X, int& recvCount_Y, int& recvCount_Z,
|
||||
int& recvCount_xy, int& recvCount_XY, int& recvCount_xY, int& recvCount_Xy,
|
||||
int& recvCount_xz, int& recvCount_XZ, int& recvCount_xZ, int& recvCount_Xz,
|
||||
int& recvCount_yz, int& recvCount_YZ, int& recvCount_yZ, int& recvCount_Yz )
|
||||
{
|
||||
MPI_Request req1[18], req2[18];
|
||||
req1[0] = comm.Isend(&sendCount_x,1,rank_x,sendtag+0);
|
||||
req2[0] = comm.Irecv(&recvCount_X,1,rank_X,recvtag+0);
|
||||
req1[1] = comm.Isend(&sendCount_X,1,rank_X,sendtag+1);
|
||||
req2[1] = comm.Irecv(&recvCount_x,1,rank_x,recvtag+1);
|
||||
req1[2] = comm.Isend(&sendCount_y,1,rank_y,sendtag+2);
|
||||
req2[2] = comm.Irecv(&recvCount_Y,1,rank_Y,recvtag+2);
|
||||
req1[3] = comm.Isend(&sendCount_Y,1,rank_Y,sendtag+3);
|
||||
req2[3] = comm.Irecv(&recvCount_y,1,rank_y,recvtag+3);
|
||||
req1[4] = comm.Isend(&sendCount_z,1,rank_z,sendtag+4);
|
||||
req2[4] = comm.Irecv(&recvCount_Z,1,rank_Z,recvtag+4);
|
||||
req1[5] = comm.Isend(&sendCount_Z,1,rank_Z,sendtag+5);
|
||||
req2[5] = comm.Irecv(&recvCount_z,1,rank_z,recvtag+5);
|
||||
inline void CommunicateSendRecvCounts(
|
||||
const Utilities::MPI &comm, int sendtag, int recvtag, int rank_x,
|
||||
int rank_y, int rank_z, int rank_X, int rank_Y, int rank_Z, int rank_xy,
|
||||
int rank_XY, int rank_xY, int rank_Xy, int rank_xz, int rank_XZ,
|
||||
int rank_xZ, int rank_Xz, int rank_yz, int rank_YZ, int rank_yZ,
|
||||
int rank_Yz, int sendCount_x, int sendCount_y, int sendCount_z,
|
||||
int sendCount_X, int sendCount_Y, int sendCount_Z, int sendCount_xy,
|
||||
int sendCount_XY, int sendCount_xY, int sendCount_Xy, int sendCount_xz,
|
||||
int sendCount_XZ, int sendCount_xZ, int sendCount_Xz, int sendCount_yz,
|
||||
int sendCount_YZ, int sendCount_yZ, int sendCount_Yz, int &recvCount_x,
|
||||
int &recvCount_y, int &recvCount_z, int &recvCount_X, int &recvCount_Y,
|
||||
int &recvCount_Z, int &recvCount_xy, int &recvCount_XY, int &recvCount_xY,
|
||||
int &recvCount_Xy, int &recvCount_xz, int &recvCount_XZ, int &recvCount_xZ,
|
||||
int &recvCount_Xz, int &recvCount_yz, int &recvCount_YZ, int &recvCount_yZ,
|
||||
int &recvCount_Yz) {
|
||||
MPI_Request req1[18], req2[18];
|
||||
req1[0] = comm.Isend(&sendCount_x, 1, rank_x, sendtag + 0);
|
||||
req2[0] = comm.Irecv(&recvCount_X, 1, rank_X, recvtag + 0);
|
||||
req1[1] = comm.Isend(&sendCount_X, 1, rank_X, sendtag + 1);
|
||||
req2[1] = comm.Irecv(&recvCount_x, 1, rank_x, recvtag + 1);
|
||||
req1[2] = comm.Isend(&sendCount_y, 1, rank_y, sendtag + 2);
|
||||
req2[2] = comm.Irecv(&recvCount_Y, 1, rank_Y, recvtag + 2);
|
||||
req1[3] = comm.Isend(&sendCount_Y, 1, rank_Y, sendtag + 3);
|
||||
req2[3] = comm.Irecv(&recvCount_y, 1, rank_y, recvtag + 3);
|
||||
req1[4] = comm.Isend(&sendCount_z, 1, rank_z, sendtag + 4);
|
||||
req2[4] = comm.Irecv(&recvCount_Z, 1, rank_Z, recvtag + 4);
|
||||
req1[5] = comm.Isend(&sendCount_Z, 1, rank_Z, sendtag + 5);
|
||||
req2[5] = comm.Irecv(&recvCount_z, 1, rank_z, recvtag + 5);
|
||||
|
||||
req1[6] = comm.Isend(&sendCount_xy,1,rank_xy,sendtag+6);
|
||||
req2[6] = comm.Irecv(&recvCount_XY,1,rank_XY,recvtag+6);
|
||||
req1[7] = comm.Isend(&sendCount_XY,1,rank_XY,sendtag+7);
|
||||
req2[7] = comm.Irecv(&recvCount_xy,1,rank_xy,recvtag+7);
|
||||
req1[8] = comm.Isend(&sendCount_Xy,1,rank_Xy,sendtag+8);
|
||||
req2[8] = comm.Irecv(&recvCount_xY,1,rank_xY,recvtag+8);
|
||||
req1[9] = comm.Isend(&sendCount_xY,1,rank_xY,sendtag+9);
|
||||
req2[9] = comm.Irecv(&recvCount_Xy,1,rank_Xy,recvtag+9);
|
||||
req1[6] = comm.Isend(&sendCount_xy, 1, rank_xy, sendtag + 6);
|
||||
req2[6] = comm.Irecv(&recvCount_XY, 1, rank_XY, recvtag + 6);
|
||||
req1[7] = comm.Isend(&sendCount_XY, 1, rank_XY, sendtag + 7);
|
||||
req2[7] = comm.Irecv(&recvCount_xy, 1, rank_xy, recvtag + 7);
|
||||
req1[8] = comm.Isend(&sendCount_Xy, 1, rank_Xy, sendtag + 8);
|
||||
req2[8] = comm.Irecv(&recvCount_xY, 1, rank_xY, recvtag + 8);
|
||||
req1[9] = comm.Isend(&sendCount_xY, 1, rank_xY, sendtag + 9);
|
||||
req2[9] = comm.Irecv(&recvCount_Xy, 1, rank_Xy, recvtag + 9);
|
||||
|
||||
req1[10] = comm.Isend(&sendCount_xz,1,rank_xz,sendtag+10);
|
||||
req2[10] = comm.Irecv(&recvCount_XZ,1,rank_XZ,recvtag+10);
|
||||
req1[11] = comm.Isend(&sendCount_XZ,1,rank_XZ,sendtag+11);
|
||||
req2[11] = comm.Irecv(&recvCount_xz,1,rank_xz,recvtag+11);
|
||||
req1[12] = comm.Isend(&sendCount_Xz,1,rank_Xz,sendtag+12);
|
||||
req2[12] = comm.Irecv(&recvCount_xZ,1,rank_xZ,recvtag+12);
|
||||
req1[13] = comm.Isend(&sendCount_xZ,1,rank_xZ,sendtag+13);
|
||||
req2[13] = comm.Irecv(&recvCount_Xz,1,rank_Xz,recvtag+13);
|
||||
req1[10] = comm.Isend(&sendCount_xz, 1, rank_xz, sendtag + 10);
|
||||
req2[10] = comm.Irecv(&recvCount_XZ, 1, rank_XZ, recvtag + 10);
|
||||
req1[11] = comm.Isend(&sendCount_XZ, 1, rank_XZ, sendtag + 11);
|
||||
req2[11] = comm.Irecv(&recvCount_xz, 1, rank_xz, recvtag + 11);
|
||||
req1[12] = comm.Isend(&sendCount_Xz, 1, rank_Xz, sendtag + 12);
|
||||
req2[12] = comm.Irecv(&recvCount_xZ, 1, rank_xZ, recvtag + 12);
|
||||
req1[13] = comm.Isend(&sendCount_xZ, 1, rank_xZ, sendtag + 13);
|
||||
req2[13] = comm.Irecv(&recvCount_Xz, 1, rank_Xz, recvtag + 13);
|
||||
|
||||
req1[14] = comm.Isend(&sendCount_yz,1,rank_yz,sendtag+14);
|
||||
req2[14] = comm.Irecv(&recvCount_YZ,1,rank_YZ,recvtag+14);
|
||||
req1[15] = comm.Isend(&sendCount_YZ,1,rank_YZ,sendtag+15);
|
||||
req2[15] = comm.Irecv(&recvCount_yz,1,rank_yz,recvtag+15);
|
||||
req1[16] = comm.Isend(&sendCount_Yz,1,rank_Yz,sendtag+16);
|
||||
req2[16] = comm.Irecv(&recvCount_yZ,1,rank_yZ,recvtag+16);
|
||||
req1[17] = comm.Isend(&sendCount_yZ,1,rank_yZ,sendtag+17);
|
||||
req2[17] = comm.Irecv(&recvCount_Yz,1,rank_Yz,recvtag+17);
|
||||
comm.waitAll( 18, req1 );
|
||||
comm.waitAll( 18, req2 );
|
||||
comm.barrier();
|
||||
req1[14] = comm.Isend(&sendCount_yz, 1, rank_yz, sendtag + 14);
|
||||
req2[14] = comm.Irecv(&recvCount_YZ, 1, rank_YZ, recvtag + 14);
|
||||
req1[15] = comm.Isend(&sendCount_YZ, 1, rank_YZ, sendtag + 15);
|
||||
req2[15] = comm.Irecv(&recvCount_yz, 1, rank_yz, recvtag + 15);
|
||||
req1[16] = comm.Isend(&sendCount_Yz, 1, rank_Yz, sendtag + 16);
|
||||
req2[16] = comm.Irecv(&recvCount_yZ, 1, rank_yZ, recvtag + 16);
|
||||
req1[17] = comm.Isend(&sendCount_yZ, 1, rank_yZ, sendtag + 17);
|
||||
req2[17] = comm.Irecv(&recvCount_Yz, 1, rank_Yz, recvtag + 17);
|
||||
comm.waitAll(18, req1);
|
||||
comm.waitAll(18, req2);
|
||||
comm.barrier();
|
||||
}
|
||||
|
||||
|
||||
//***************************************************************************************
|
||||
inline void CommunicateRecvLists( const Utilities::MPI& comm, int sendtag, int recvtag,
|
||||
int *sendList_x, int *sendList_y, int *sendList_z, int *sendList_X, int *sendList_Y, int *sendList_Z,
|
||||
|
@ -263,100 +272,120 @@ inline void CommunicateRecvLists( const Utilities::MPI& comm, int sendtag, int r
|
|||
comm.waitAll( 18, req2 );
|
||||
}
|
||||
|
||||
|
||||
//***************************************************************************************
|
||||
inline void CommunicateMeshHalo(DoubleArray &Mesh, const Utilities::MPI& comm,
|
||||
double *sendbuf_x,double *sendbuf_y,double *sendbuf_z,double *sendbuf_X,double *sendbuf_Y,double *sendbuf_Z,
|
||||
double *sendbuf_xy,double *sendbuf_XY,double *sendbuf_xY,double *sendbuf_Xy,
|
||||
double *sendbuf_xz,double *sendbuf_XZ,double *sendbuf_xZ,double *sendbuf_Xz,
|
||||
double *sendbuf_yz,double *sendbuf_YZ,double *sendbuf_yZ,double *sendbuf_Yz,
|
||||
double *recvbuf_x,double *recvbuf_y,double *recvbuf_z,double *recvbuf_X,double *recvbuf_Y,double *recvbuf_Z,
|
||||
double *recvbuf_xy,double *recvbuf_XY,double *recvbuf_xY,double *recvbuf_Xy,
|
||||
double *recvbuf_xz,double *recvbuf_XZ,double *recvbuf_xZ,double *recvbuf_Xz,
|
||||
double *recvbuf_yz,double *recvbuf_YZ,double *recvbuf_yZ,double *recvbuf_Yz,
|
||||
int *sendList_x,int *sendList_y,int *sendList_z,int *sendList_X,int *sendList_Y,int *sendList_Z,
|
||||
int *sendList_xy,int *sendList_XY,int *sendList_xY,int *sendList_Xy,
|
||||
int *sendList_xz,int *sendList_XZ,int *sendList_xZ,int *sendList_Xz,
|
||||
int *sendList_yz,int *sendList_YZ,int *sendList_yZ,int *sendList_Yz,
|
||||
int sendCount_x,int sendCount_y,int sendCount_z,int sendCount_X,int sendCount_Y,int sendCount_Z,
|
||||
int sendCount_xy,int sendCount_XY,int sendCount_xY,int sendCount_Xy,
|
||||
int sendCount_xz,int sendCount_XZ,int sendCount_xZ,int sendCount_Xz,
|
||||
int sendCount_yz,int sendCount_YZ,int sendCount_yZ,int sendCount_Yz,
|
||||
int *recvList_x,int *recvList_y,int *recvList_z,int *recvList_X,int *recvList_Y,int *recvList_Z,
|
||||
int *recvList_xy,int *recvList_XY,int *recvList_xY,int *recvList_Xy,
|
||||
int *recvList_xz,int *recvList_XZ,int *recvList_xZ,int *recvList_Xz,
|
||||
int *recvList_yz,int *recvList_YZ,int *recvList_yZ,int *recvList_Yz,
|
||||
int recvCount_x,int recvCount_y,int recvCount_z,int recvCount_X,int recvCount_Y,int recvCount_Z,
|
||||
int recvCount_xy,int recvCount_XY,int recvCount_xY,int recvCount_Xy,
|
||||
int recvCount_xz,int recvCount_XZ,int recvCount_xZ,int recvCount_Xz,
|
||||
int recvCount_yz,int recvCount_YZ,int recvCount_yZ,int recvCount_Yz,
|
||||
int rank_x,int rank_y,int rank_z,int rank_X,int rank_Y,int rank_Z,int rank_xy,int rank_XY,int rank_xY,
|
||||
int rank_Xy,int rank_xz,int rank_XZ,int rank_xZ,int rank_Xz,int rank_yz,int rank_YZ,int rank_yZ,int rank_Yz)
|
||||
{
|
||||
int sendtag, recvtag;
|
||||
sendtag = recvtag = 7;
|
||||
inline void CommunicateMeshHalo(
|
||||
DoubleArray &Mesh, const Utilities::MPI &comm, double *sendbuf_x,
|
||||
double *sendbuf_y, double *sendbuf_z, double *sendbuf_X, double *sendbuf_Y,
|
||||
double *sendbuf_Z, double *sendbuf_xy, double *sendbuf_XY,
|
||||
double *sendbuf_xY, double *sendbuf_Xy, double *sendbuf_xz,
|
||||
double *sendbuf_XZ, double *sendbuf_xZ, double *sendbuf_Xz,
|
||||
double *sendbuf_yz, double *sendbuf_YZ, double *sendbuf_yZ,
|
||||
double *sendbuf_Yz, double *recvbuf_x, double *recvbuf_y, double *recvbuf_z,
|
||||
double *recvbuf_X, double *recvbuf_Y, double *recvbuf_Z, double *recvbuf_xy,
|
||||
double *recvbuf_XY, double *recvbuf_xY, double *recvbuf_Xy,
|
||||
double *recvbuf_xz, double *recvbuf_XZ, double *recvbuf_xZ,
|
||||
double *recvbuf_Xz, double *recvbuf_yz, double *recvbuf_YZ,
|
||||
double *recvbuf_yZ, double *recvbuf_Yz, int *sendList_x, int *sendList_y,
|
||||
int *sendList_z, int *sendList_X, int *sendList_Y, int *sendList_Z,
|
||||
int *sendList_xy, int *sendList_XY, int *sendList_xY, int *sendList_Xy,
|
||||
int *sendList_xz, int *sendList_XZ, int *sendList_xZ, int *sendList_Xz,
|
||||
int *sendList_yz, int *sendList_YZ, int *sendList_yZ, int *sendList_Yz,
|
||||
int sendCount_x, int sendCount_y, int sendCount_z, int sendCount_X,
|
||||
int sendCount_Y, int sendCount_Z, int sendCount_xy, int sendCount_XY,
|
||||
int sendCount_xY, int sendCount_Xy, int sendCount_xz, int sendCount_XZ,
|
||||
int sendCount_xZ, int sendCount_Xz, int sendCount_yz, int sendCount_YZ,
|
||||
int sendCount_yZ, int sendCount_Yz, int *recvList_x, int *recvList_y,
|
||||
int *recvList_z, int *recvList_X, int *recvList_Y, int *recvList_Z,
|
||||
int *recvList_xy, int *recvList_XY, int *recvList_xY, int *recvList_Xy,
|
||||
int *recvList_xz, int *recvList_XZ, int *recvList_xZ, int *recvList_Xz,
|
||||
int *recvList_yz, int *recvList_YZ, int *recvList_yZ, int *recvList_Yz,
|
||||
int recvCount_x, int recvCount_y, int recvCount_z, int recvCount_X,
|
||||
int recvCount_Y, int recvCount_Z, int recvCount_xy, int recvCount_XY,
|
||||
int recvCount_xY, int recvCount_Xy, int recvCount_xz, int recvCount_XZ,
|
||||
int recvCount_xZ, int recvCount_Xz, int recvCount_yz, int recvCount_YZ,
|
||||
int recvCount_yZ, int recvCount_Yz, int rank_x, int rank_y, int rank_z,
|
||||
int rank_X, int rank_Y, int rank_Z, int rank_xy, int rank_XY, int rank_xY,
|
||||
int rank_Xy, int rank_xz, int rank_XZ, int rank_xZ, int rank_Xz,
|
||||
int rank_yz, int rank_YZ, int rank_yZ, int rank_Yz) {
|
||||
int sendtag, recvtag;
|
||||
sendtag = recvtag = 7;
|
||||
double *MeshData = Mesh.data();
|
||||
PackMeshData(sendList_x, sendCount_x ,sendbuf_x, MeshData);
|
||||
PackMeshData(sendList_X, sendCount_X ,sendbuf_X, MeshData);
|
||||
PackMeshData(sendList_y, sendCount_y ,sendbuf_y, MeshData);
|
||||
PackMeshData(sendList_Y, sendCount_Y ,sendbuf_Y, MeshData);
|
||||
PackMeshData(sendList_z, sendCount_z ,sendbuf_z, MeshData);
|
||||
PackMeshData(sendList_Z, sendCount_Z ,sendbuf_Z, MeshData);
|
||||
PackMeshData(sendList_xy, sendCount_xy ,sendbuf_xy, MeshData);
|
||||
PackMeshData(sendList_Xy, sendCount_Xy ,sendbuf_Xy, MeshData);
|
||||
PackMeshData(sendList_xY, sendCount_xY ,sendbuf_xY, MeshData);
|
||||
PackMeshData(sendList_XY, sendCount_XY ,sendbuf_XY, MeshData);
|
||||
PackMeshData(sendList_xz, sendCount_xz ,sendbuf_xz, MeshData);
|
||||
PackMeshData(sendList_Xz, sendCount_Xz ,sendbuf_Xz, MeshData);
|
||||
PackMeshData(sendList_xZ, sendCount_xZ ,sendbuf_xZ, MeshData);
|
||||
PackMeshData(sendList_XZ, sendCount_XZ ,sendbuf_XZ, MeshData);
|
||||
PackMeshData(sendList_yz, sendCount_yz ,sendbuf_yz, MeshData);
|
||||
PackMeshData(sendList_Yz, sendCount_Yz ,sendbuf_Yz, MeshData);
|
||||
PackMeshData(sendList_yZ, sendCount_yZ ,sendbuf_yZ, MeshData);
|
||||
PackMeshData(sendList_YZ, sendCount_YZ ,sendbuf_YZ, MeshData);
|
||||
//......................................................................................
|
||||
comm.sendrecv(sendbuf_x,sendCount_x,rank_x,sendtag,recvbuf_X,recvCount_X,rank_X,recvtag);
|
||||
comm.sendrecv(sendbuf_X,sendCount_X,rank_X,sendtag,recvbuf_x,recvCount_x,rank_x,recvtag);
|
||||
comm.sendrecv(sendbuf_y,sendCount_y,rank_y,sendtag,recvbuf_Y,recvCount_Y,rank_Y,recvtag);
|
||||
comm.sendrecv(sendbuf_Y,sendCount_Y,rank_Y,sendtag,recvbuf_y,recvCount_y,rank_y,recvtag);
|
||||
comm.sendrecv(sendbuf_z,sendCount_z,rank_z,sendtag,recvbuf_Z,recvCount_Z,rank_Z,recvtag);
|
||||
comm.sendrecv(sendbuf_Z,sendCount_Z,rank_Z,sendtag,recvbuf_z,recvCount_z,rank_z,recvtag);
|
||||
comm.sendrecv(sendbuf_xy,sendCount_xy,rank_xy,sendtag,recvbuf_XY,recvCount_XY,rank_XY,recvtag);
|
||||
comm.sendrecv(sendbuf_XY,sendCount_XY,rank_XY,sendtag,recvbuf_xy,recvCount_xy,rank_xy,recvtag);
|
||||
comm.sendrecv(sendbuf_Xy,sendCount_Xy,rank_Xy,sendtag,recvbuf_xY,recvCount_xY,rank_xY,recvtag);
|
||||
comm.sendrecv(sendbuf_xY,sendCount_xY,rank_xY,sendtag,recvbuf_Xy,recvCount_Xy,rank_Xy,recvtag);
|
||||
comm.sendrecv(sendbuf_xz,sendCount_xz,rank_xz,sendtag,recvbuf_XZ,recvCount_XZ,rank_XZ,recvtag);
|
||||
comm.sendrecv(sendbuf_XZ,sendCount_XZ,rank_XZ,sendtag,recvbuf_xz,recvCount_xz,rank_xz,recvtag);
|
||||
comm.sendrecv(sendbuf_Xz,sendCount_Xz,rank_Xz,sendtag,recvbuf_xZ,recvCount_xZ,rank_xZ,recvtag);
|
||||
comm.sendrecv(sendbuf_xZ,sendCount_xZ,rank_xZ,sendtag,recvbuf_Xz,recvCount_Xz,rank_Xz,recvtag);
|
||||
comm.sendrecv(sendbuf_yz,sendCount_yz,rank_yz,sendtag,recvbuf_YZ,recvCount_YZ,rank_YZ,recvtag);
|
||||
comm.sendrecv(sendbuf_YZ,sendCount_YZ,rank_YZ,sendtag,recvbuf_yz,recvCount_yz,rank_yz,recvtag);
|
||||
comm.sendrecv(sendbuf_Yz,sendCount_Yz,rank_Yz,sendtag,recvbuf_yZ,recvCount_yZ,rank_yZ,recvtag);
|
||||
comm.sendrecv(sendbuf_yZ,sendCount_yZ,rank_yZ,sendtag,recvbuf_Yz,recvCount_Yz,rank_Yz,recvtag);
|
||||
//........................................................................................
|
||||
UnpackMeshData(recvList_x, recvCount_x ,recvbuf_x, MeshData);
|
||||
UnpackMeshData(recvList_X, recvCount_X ,recvbuf_X, MeshData);
|
||||
UnpackMeshData(recvList_y, recvCount_y ,recvbuf_y, MeshData);
|
||||
UnpackMeshData(recvList_Y, recvCount_Y ,recvbuf_Y, MeshData);
|
||||
UnpackMeshData(recvList_z, recvCount_z ,recvbuf_z, MeshData);
|
||||
UnpackMeshData(recvList_Z, recvCount_Z ,recvbuf_Z, MeshData);
|
||||
UnpackMeshData(recvList_xy, recvCount_xy ,recvbuf_xy, MeshData);
|
||||
UnpackMeshData(recvList_Xy, recvCount_Xy ,recvbuf_Xy, MeshData);
|
||||
UnpackMeshData(recvList_xY, recvCount_xY ,recvbuf_xY, MeshData);
|
||||
UnpackMeshData(recvList_XY, recvCount_XY ,recvbuf_XY, MeshData);
|
||||
UnpackMeshData(recvList_xz, recvCount_xz ,recvbuf_xz, MeshData);
|
||||
UnpackMeshData(recvList_Xz, recvCount_Xz ,recvbuf_Xz, MeshData);
|
||||
UnpackMeshData(recvList_xZ, recvCount_xZ ,recvbuf_xZ, MeshData);
|
||||
UnpackMeshData(recvList_XZ, recvCount_XZ ,recvbuf_XZ, MeshData);
|
||||
UnpackMeshData(recvList_yz, recvCount_yz ,recvbuf_yz, MeshData);
|
||||
UnpackMeshData(recvList_Yz, recvCount_Yz ,recvbuf_Yz, MeshData);
|
||||
UnpackMeshData(recvList_yZ, recvCount_yZ ,recvbuf_yZ, MeshData);
|
||||
UnpackMeshData(recvList_YZ, recvCount_YZ ,recvbuf_YZ, MeshData);
|
||||
PackMeshData(sendList_x, sendCount_x, sendbuf_x, MeshData);
|
||||
PackMeshData(sendList_X, sendCount_X, sendbuf_X, MeshData);
|
||||
PackMeshData(sendList_y, sendCount_y, sendbuf_y, MeshData);
|
||||
PackMeshData(sendList_Y, sendCount_Y, sendbuf_Y, MeshData);
|
||||
PackMeshData(sendList_z, sendCount_z, sendbuf_z, MeshData);
|
||||
PackMeshData(sendList_Z, sendCount_Z, sendbuf_Z, MeshData);
|
||||
PackMeshData(sendList_xy, sendCount_xy, sendbuf_xy, MeshData);
|
||||
PackMeshData(sendList_Xy, sendCount_Xy, sendbuf_Xy, MeshData);
|
||||
PackMeshData(sendList_xY, sendCount_xY, sendbuf_xY, MeshData);
|
||||
PackMeshData(sendList_XY, sendCount_XY, sendbuf_XY, MeshData);
|
||||
PackMeshData(sendList_xz, sendCount_xz, sendbuf_xz, MeshData);
|
||||
PackMeshData(sendList_Xz, sendCount_Xz, sendbuf_Xz, MeshData);
|
||||
PackMeshData(sendList_xZ, sendCount_xZ, sendbuf_xZ, MeshData);
|
||||
PackMeshData(sendList_XZ, sendCount_XZ, sendbuf_XZ, MeshData);
|
||||
PackMeshData(sendList_yz, sendCount_yz, sendbuf_yz, MeshData);
|
||||
PackMeshData(sendList_Yz, sendCount_Yz, sendbuf_Yz, MeshData);
|
||||
PackMeshData(sendList_yZ, sendCount_yZ, sendbuf_yZ, MeshData);
|
||||
PackMeshData(sendList_YZ, sendCount_YZ, sendbuf_YZ, MeshData);
|
||||
//......................................................................................
|
||||
comm.sendrecv(sendbuf_x, sendCount_x, rank_x, sendtag, recvbuf_X,
|
||||
recvCount_X, rank_X, recvtag);
|
||||
comm.sendrecv(sendbuf_X, sendCount_X, rank_X, sendtag, recvbuf_x,
|
||||
recvCount_x, rank_x, recvtag);
|
||||
comm.sendrecv(sendbuf_y, sendCount_y, rank_y, sendtag, recvbuf_Y,
|
||||
recvCount_Y, rank_Y, recvtag);
|
||||
comm.sendrecv(sendbuf_Y, sendCount_Y, rank_Y, sendtag, recvbuf_y,
|
||||
recvCount_y, rank_y, recvtag);
|
||||
comm.sendrecv(sendbuf_z, sendCount_z, rank_z, sendtag, recvbuf_Z,
|
||||
recvCount_Z, rank_Z, recvtag);
|
||||
comm.sendrecv(sendbuf_Z, sendCount_Z, rank_Z, sendtag, recvbuf_z,
|
||||
recvCount_z, rank_z, recvtag);
|
||||
comm.sendrecv(sendbuf_xy, sendCount_xy, rank_xy, sendtag, recvbuf_XY,
|
||||
recvCount_XY, rank_XY, recvtag);
|
||||
comm.sendrecv(sendbuf_XY, sendCount_XY, rank_XY, sendtag, recvbuf_xy,
|
||||
recvCount_xy, rank_xy, recvtag);
|
||||
comm.sendrecv(sendbuf_Xy, sendCount_Xy, rank_Xy, sendtag, recvbuf_xY,
|
||||
recvCount_xY, rank_xY, recvtag);
|
||||
comm.sendrecv(sendbuf_xY, sendCount_xY, rank_xY, sendtag, recvbuf_Xy,
|
||||
recvCount_Xy, rank_Xy, recvtag);
|
||||
comm.sendrecv(sendbuf_xz, sendCount_xz, rank_xz, sendtag, recvbuf_XZ,
|
||||
recvCount_XZ, rank_XZ, recvtag);
|
||||
comm.sendrecv(sendbuf_XZ, sendCount_XZ, rank_XZ, sendtag, recvbuf_xz,
|
||||
recvCount_xz, rank_xz, recvtag);
|
||||
comm.sendrecv(sendbuf_Xz, sendCount_Xz, rank_Xz, sendtag, recvbuf_xZ,
|
||||
recvCount_xZ, rank_xZ, recvtag);
|
||||
comm.sendrecv(sendbuf_xZ, sendCount_xZ, rank_xZ, sendtag, recvbuf_Xz,
|
||||
recvCount_Xz, rank_Xz, recvtag);
|
||||
comm.sendrecv(sendbuf_yz, sendCount_yz, rank_yz, sendtag, recvbuf_YZ,
|
||||
recvCount_YZ, rank_YZ, recvtag);
|
||||
comm.sendrecv(sendbuf_YZ, sendCount_YZ, rank_YZ, sendtag, recvbuf_yz,
|
||||
recvCount_yz, rank_yz, recvtag);
|
||||
comm.sendrecv(sendbuf_Yz, sendCount_Yz, rank_Yz, sendtag, recvbuf_yZ,
|
||||
recvCount_yZ, rank_yZ, recvtag);
|
||||
comm.sendrecv(sendbuf_yZ, sendCount_yZ, rank_yZ, sendtag, recvbuf_Yz,
|
||||
recvCount_Yz, rank_Yz, recvtag);
|
||||
//........................................................................................
|
||||
UnpackMeshData(recvList_x, recvCount_x, recvbuf_x, MeshData);
|
||||
UnpackMeshData(recvList_X, recvCount_X, recvbuf_X, MeshData);
|
||||
UnpackMeshData(recvList_y, recvCount_y, recvbuf_y, MeshData);
|
||||
UnpackMeshData(recvList_Y, recvCount_Y, recvbuf_Y, MeshData);
|
||||
UnpackMeshData(recvList_z, recvCount_z, recvbuf_z, MeshData);
|
||||
UnpackMeshData(recvList_Z, recvCount_Z, recvbuf_Z, MeshData);
|
||||
UnpackMeshData(recvList_xy, recvCount_xy, recvbuf_xy, MeshData);
|
||||
UnpackMeshData(recvList_Xy, recvCount_Xy, recvbuf_Xy, MeshData);
|
||||
UnpackMeshData(recvList_xY, recvCount_xY, recvbuf_xY, MeshData);
|
||||
UnpackMeshData(recvList_XY, recvCount_XY, recvbuf_XY, MeshData);
|
||||
UnpackMeshData(recvList_xz, recvCount_xz, recvbuf_xz, MeshData);
|
||||
UnpackMeshData(recvList_Xz, recvCount_Xz, recvbuf_Xz, MeshData);
|
||||
UnpackMeshData(recvList_xZ, recvCount_xZ, recvbuf_xZ, MeshData);
|
||||
UnpackMeshData(recvList_XZ, recvCount_XZ, recvbuf_XZ, MeshData);
|
||||
UnpackMeshData(recvList_yz, recvCount_yz, recvbuf_yz, MeshData);
|
||||
UnpackMeshData(recvList_Yz, recvCount_Yz, recvbuf_Yz, MeshData);
|
||||
UnpackMeshData(recvList_yZ, recvCount_yZ, recvbuf_yZ, MeshData);
|
||||
UnpackMeshData(recvList_YZ, recvCount_YZ, recvbuf_YZ, MeshData);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#include "common/Communication.hpp"
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,35 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef COMMUNICATION_HPP_INC
|
||||
#define COMMUNICATION_HPP_INC
|
||||
|
||||
|
@ -5,101 +37,116 @@
|
|||
#include "common/MPI.h"
|
||||
#include "common/Utilities.h"
|
||||
|
||||
|
||||
/********************************************************
|
||||
* Redistribute data between two grids *
|
||||
********************************************************/
|
||||
template<class TYPE>
|
||||
Array<TYPE> redistribute( const RankInfoStruct& src_rank, const Array<TYPE>& src_data,
|
||||
const RankInfoStruct& dst_rank, std::array<int,3> dst_size, const Utilities::MPI& comm )
|
||||
{
|
||||
if ( comm.getSize() == 1 ) {
|
||||
return src_data.subset( { 0, (size_t) dst_size[0]-1, 0, (size_t) dst_size[1]-1, 0, (size_t) dst_size[2]-1 } );
|
||||
template <class TYPE>
|
||||
Array<TYPE>
|
||||
redistribute(const RankInfoStruct &src_rank, const Array<TYPE> &src_data,
|
||||
const RankInfoStruct &dst_rank, std::array<int, 3> dst_size,
|
||||
const Utilities::MPI &comm) {
|
||||
if (comm.getSize() == 1) {
|
||||
return src_data.subset({0, (size_t)dst_size[0] - 1, 0,
|
||||
(size_t)dst_size[1] - 1, 0,
|
||||
(size_t)dst_size[2] - 1});
|
||||
}
|
||||
// Get the src size
|
||||
std::array<int,3> src_size;
|
||||
int size0[3] = { (int) src_data.size(0), (int) src_data.size(1), (int) src_data.size(2) };
|
||||
comm.maxReduce( size0, src_size.data(), 3 );
|
||||
if ( !src_data.empty() )
|
||||
ASSERT( src_size[0] == size0[0] && src_size[1] == size0[1] && src_size[2] == size0[2] );
|
||||
std::array<int, 3> src_size;
|
||||
int size0[3] = {(int)src_data.size(0), (int)src_data.size(1),
|
||||
(int)src_data.size(2)};
|
||||
comm.maxReduce(size0, src_size.data(), 3);
|
||||
if (!src_data.empty())
|
||||
ASSERT(src_size[0] == size0[0] && src_size[1] == size0[1] &&
|
||||
src_size[2] == size0[2]);
|
||||
// Check that dst_size matches on all ranks
|
||||
comm.maxReduce( dst_size.data(), size0, 3 );
|
||||
ASSERT( dst_size[0] == size0[0] && dst_size[1] == size0[1] && dst_size[2] == size0[2] );
|
||||
comm.maxReduce(dst_size.data(), size0, 3);
|
||||
ASSERT(dst_size[0] == size0[0] && dst_size[1] == size0[1] &&
|
||||
dst_size[2] == size0[2]);
|
||||
// Function to get overlap range
|
||||
auto calcOverlap = []( int i1[3], int i2[3], int j1[3], int j2[3] ) {
|
||||
auto calcOverlap = [](int i1[3], int i2[3], int j1[3], int j2[3]) {
|
||||
std::vector<size_t> index;
|
||||
if ( i1[0] > j2[0] || i2[0] < j1[0] || i1[1] > j2[1] || i2[1] < j1[1] || i1[2] > j2[2] || i2[2] < j1[2] )
|
||||
if (i1[0] > j2[0] || i2[0] < j1[0] || i1[1] > j2[1] || i2[1] < j1[1] ||
|
||||
i1[2] > j2[2] || i2[2] < j1[2])
|
||||
return index;
|
||||
index.resize( 6 );
|
||||
index[0] = std::max( j1[0] - i1[0], 0 );
|
||||
index[1] = std::min( j2[0] - i1[0], i2[0] - i1[0] );
|
||||
index[2] = std::max( j1[1] - i1[1], 0 );
|
||||
index[3] = std::min( j2[1] - i1[1], i2[1] - i1[1] );
|
||||
index[4] = std::max( j1[2] - i1[2], 0 );
|
||||
index[5] = std::min( j2[2] - i1[2], i2[2] - i1[2] );
|
||||
index.resize(6);
|
||||
index[0] = std::max(j1[0] - i1[0], 0);
|
||||
index[1] = std::min(j2[0] - i1[0], i2[0] - i1[0]);
|
||||
index[2] = std::max(j1[1] - i1[1], 0);
|
||||
index[3] = std::min(j2[1] - i1[1], i2[1] - i1[1]);
|
||||
index[4] = std::max(j1[2] - i1[2], 0);
|
||||
index[5] = std::min(j2[2] - i1[2], i2[2] - i1[2]);
|
||||
return index;
|
||||
};
|
||||
// Pack and send my data to the appropriate ranks (including myself)
|
||||
std::vector<int> send_rank;
|
||||
std::vector<Array<TYPE>> send_data;
|
||||
if ( !src_data.empty() ) {
|
||||
int i1[3] = { src_size[0] * src_rank.ix, src_size[1] * src_rank.jy, src_size[2] * src_rank.kz };
|
||||
int i2[3] = { i1[0] + src_size[0] - 1, i1[1] + src_size[1] - 1, i1[2] + src_size[2] - 1 };
|
||||
for ( int i=0; i<dst_rank.nx; i++ ) {
|
||||
for ( int j=0; j<dst_rank.ny; j++ ) {
|
||||
for ( int k=0; k<dst_rank.nz; k++ ) {
|
||||
int j1[3] = { i * dst_size[0], j * dst_size[1], k * dst_size[2] };
|
||||
int j2[3] = { j1[0] + dst_size[0] - 1, j1[1] + dst_size[1] - 1, j1[2] + dst_size[2] - 1 };
|
||||
auto index = calcOverlap( i1, i2, j1, j2 );
|
||||
if ( index.empty() )
|
||||
if (!src_data.empty()) {
|
||||
int i1[3] = {src_size[0] * src_rank.ix, src_size[1] * src_rank.jy,
|
||||
src_size[2] * src_rank.kz};
|
||||
int i2[3] = {i1[0] + src_size[0] - 1, i1[1] + src_size[1] - 1,
|
||||
i1[2] + src_size[2] - 1};
|
||||
for (int i = 0; i < dst_rank.nx; i++) {
|
||||
for (int j = 0; j < dst_rank.ny; j++) {
|
||||
for (int k = 0; k < dst_rank.nz; k++) {
|
||||
int j1[3] = {i * dst_size[0], j * dst_size[1],
|
||||
k * dst_size[2]};
|
||||
int j2[3] = {j1[0] + dst_size[0] - 1,
|
||||
j1[1] + dst_size[1] - 1,
|
||||
j1[2] + dst_size[2] - 1};
|
||||
auto index = calcOverlap(i1, i2, j1, j2);
|
||||
if (index.empty())
|
||||
continue;
|
||||
send_rank.push_back( dst_rank.getRankForBlock(i,j,k) );
|
||||
send_data.push_back( src_data.subset( index ) );
|
||||
send_rank.push_back(dst_rank.getRankForBlock(i, j, k));
|
||||
send_data.push_back(src_data.subset(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<MPI_Request> send_request( send_rank.size() );
|
||||
for (size_t i=0; i<send_rank.size(); i++)
|
||||
send_request[i] = comm.Isend( send_data[i].data(), send_data[i].length(), send_rank[i], 5462 );
|
||||
std::vector<MPI_Request> send_request(send_rank.size());
|
||||
for (size_t i = 0; i < send_rank.size(); i++)
|
||||
send_request[i] = comm.Isend(send_data[i].data(), send_data[i].length(),
|
||||
send_rank[i], 5462);
|
||||
// Unpack data from the appropriate ranks (including myself)
|
||||
Array<TYPE> dst_data( dst_size[0], dst_size[1], dst_size[2] );
|
||||
int i1[3] = { dst_size[0] * dst_rank.ix, dst_size[1] * dst_rank.jy, dst_size[2] * dst_rank.kz };
|
||||
int i2[3] = { i1[0] + dst_size[0] - 1, i1[1] + dst_size[1] - 1, i1[2] + dst_size[2] - 1 };
|
||||
for ( int i=0; i<src_rank.nx; i++ ) {
|
||||
for ( int j=0; j<src_rank.ny; j++ ) {
|
||||
for ( int k=0; k<src_rank.nz; k++ ) {
|
||||
int j1[3] = { i * src_size[0], j * src_size[1], k * src_size[2] };
|
||||
int j2[3] = { j1[0] + src_size[0] - 1, j1[1] + src_size[1] - 1, j1[2] + src_size[2] - 1 };
|
||||
auto index = calcOverlap( i1, i2, j1, j2 );
|
||||
if ( index.empty() )
|
||||
Array<TYPE> dst_data(dst_size[0], dst_size[1], dst_size[2]);
|
||||
int i1[3] = {dst_size[0] * dst_rank.ix, dst_size[1] * dst_rank.jy,
|
||||
dst_size[2] * dst_rank.kz};
|
||||
int i2[3] = {i1[0] + dst_size[0] - 1, i1[1] + dst_size[1] - 1,
|
||||
i1[2] + dst_size[2] - 1};
|
||||
for (int i = 0; i < src_rank.nx; i++) {
|
||||
for (int j = 0; j < src_rank.ny; j++) {
|
||||
for (int k = 0; k < src_rank.nz; k++) {
|
||||
int j1[3] = {i * src_size[0], j * src_size[1], k * src_size[2]};
|
||||
int j2[3] = {j1[0] + src_size[0] - 1, j1[1] + src_size[1] - 1,
|
||||
j1[2] + src_size[2] - 1};
|
||||
auto index = calcOverlap(i1, i2, j1, j2);
|
||||
if (index.empty())
|
||||
continue;
|
||||
int rank = src_rank.getRankForBlock(i,j,k);
|
||||
Array<TYPE> data( index[1] - index[0] + 1, index[3] - index[2] + 1, index[5] - index[4] + 1 );
|
||||
comm.recv( data.data(), data.length(), rank, 5462 );
|
||||
dst_data.copySubset( index, data );
|
||||
int rank = src_rank.getRankForBlock(i, j, k);
|
||||
Array<TYPE> data(index[1] - index[0] + 1,
|
||||
index[3] - index[2] + 1,
|
||||
index[5] - index[4] + 1);
|
||||
comm.recv(data.data(), data.length(), rank, 5462);
|
||||
dst_data.copySubset(index, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Free data
|
||||
comm.waitAll( send_request.size(), send_request.data() );
|
||||
comm.waitAll(send_request.size(), send_request.data());
|
||||
return dst_data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************************************
|
||||
* Structure to fill halo cells *
|
||||
********************************************************/
|
||||
template<class TYPE>
|
||||
fillHalo<TYPE>::fillHalo( const Utilities::MPI& comm_, const RankInfoStruct& info_,
|
||||
std::array<int,3> n_, std::array<int,3> ng_, int tag0, int depth_,
|
||||
std::array<bool,3> fill, std::array<bool,3> periodic ):
|
||||
comm(comm_), info(info_), n(n_), ng(ng_), depth(depth_)
|
||||
{
|
||||
template <class TYPE>
|
||||
fillHalo<TYPE>::fillHalo(const Utilities::MPI &comm_,
|
||||
const RankInfoStruct &info_, std::array<int, 3> n_,
|
||||
std::array<int, 3> ng_, int tag0, int depth_,
|
||||
std::array<bool, 3> fill, std::array<bool, 3> periodic)
|
||||
: comm(comm_), info(info_), n(n_), ng(ng_), depth(depth_) {
|
||||
// Set the fill pattern
|
||||
memset(fill_pattern,0,sizeof(fill_pattern));
|
||||
if ( fill[0] ) {
|
||||
memset(fill_pattern, 0, sizeof(fill_pattern));
|
||||
if (fill[0]) {
|
||||
fill_pattern[0][1][1] = true;
|
||||
fill_pattern[2][1][1] = true;
|
||||
fill_pattern[1][0][1] = true;
|
||||
|
@ -107,7 +154,7 @@ fillHalo<TYPE>::fillHalo( const Utilities::MPI& comm_, const RankInfoStruct& inf
|
|||
fill_pattern[1][1][0] = true;
|
||||
fill_pattern[1][1][2] = true;
|
||||
}
|
||||
if ( fill[1] ) {
|
||||
if (fill[1]) {
|
||||
fill_pattern[0][0][1] = true;
|
||||
fill_pattern[0][2][1] = true;
|
||||
fill_pattern[2][0][1] = true;
|
||||
|
@ -121,7 +168,7 @@ fillHalo<TYPE>::fillHalo( const Utilities::MPI& comm_, const RankInfoStruct& inf
|
|||
fill_pattern[1][2][0] = true;
|
||||
fill_pattern[1][2][2] = true;
|
||||
}
|
||||
if ( fill[2] ) {
|
||||
if (fill[2]) {
|
||||
fill_pattern[0][0][0] = true;
|
||||
fill_pattern[0][0][2] = true;
|
||||
fill_pattern[0][2][0] = true;
|
||||
|
@ -132,238 +179,233 @@ fillHalo<TYPE>::fillHalo( const Utilities::MPI& comm_, const RankInfoStruct& inf
|
|||
fill_pattern[2][2][2] = true;
|
||||
}
|
||||
// Remove communication for non-perioidic directions
|
||||
if ( !periodic[0] && info.ix==0 ) {
|
||||
for (int j=0; j<3; j++) {
|
||||
for (int k=0; k<3; k++)
|
||||
if (!periodic[0] && info.ix == 0) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
for (int k = 0; k < 3; k++)
|
||||
fill_pattern[0][j][k] = false;
|
||||
}
|
||||
}
|
||||
if ( !periodic[0] && info.ix==info.nx-1 ) {
|
||||
for (int j=0; j<3; j++) {
|
||||
for (int k=0; k<3; k++)
|
||||
if (!periodic[0] && info.ix == info.nx - 1) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
for (int k = 0; k < 3; k++)
|
||||
fill_pattern[2][j][k] = false;
|
||||
}
|
||||
}
|
||||
if ( !periodic[1] && info.jy==0 ) {
|
||||
for (int i=0; i<3; i++) {
|
||||
for (int k=0; k<3; k++)
|
||||
if (!periodic[1] && info.jy == 0) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int k = 0; k < 3; k++)
|
||||
fill_pattern[i][0][k] = false;
|
||||
}
|
||||
}
|
||||
if ( !periodic[1] && info.jy==info.ny-1 ) {
|
||||
for (int i=0; i<3; i++) {
|
||||
for (int k=0; k<3; k++)
|
||||
if (!periodic[1] && info.jy == info.ny - 1) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int k = 0; k < 3; k++)
|
||||
fill_pattern[i][2][k] = false;
|
||||
}
|
||||
}
|
||||
if ( !periodic[2] && info.kz==0 ) {
|
||||
for (int i=0; i<3; i++) {
|
||||
for (int j=0; j<3; j++)
|
||||
if (!periodic[2] && info.kz == 0) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++)
|
||||
fill_pattern[i][j][0] = false;
|
||||
}
|
||||
}
|
||||
if ( !periodic[2] && info.kz==info.nz-1 ) {
|
||||
for (int i=0; i<3; i++) {
|
||||
for (int j=0; j<3; j++)
|
||||
if (!periodic[2] && info.kz == info.nz - 1) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++)
|
||||
fill_pattern[i][j][2] = false;
|
||||
}
|
||||
}
|
||||
// Determine the number of elements for each send/recv
|
||||
for (int i=0; i<3; i++) {
|
||||
int ni = (i-1)==0 ? n[0]:ng[0];
|
||||
for (int j=0; j<3; j++) {
|
||||
int nj = (j-1)==0 ? n[1]:ng[1];
|
||||
for (int k=0; k<3; k++) {
|
||||
int nk = (k-1)==0 ? n[2]:ng[2];
|
||||
if ( fill_pattern[i][j][k] )
|
||||
N_send_recv[i][j][k] = ni*nj*nk;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int ni = (i - 1) == 0 ? n[0] : ng[0];
|
||||
for (int j = 0; j < 3; j++) {
|
||||
int nj = (j - 1) == 0 ? n[1] : ng[1];
|
||||
for (int k = 0; k < 3; k++) {
|
||||
int nk = (k - 1) == 0 ? n[2] : ng[2];
|
||||
if (fill_pattern[i][j][k])
|
||||
N_send_recv[i][j][k] = ni * nj * nk;
|
||||
else
|
||||
N_send_recv[i][j][k] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create send/recv buffers
|
||||
size_t N_mem=0;
|
||||
for (int i=0; i<3; i++) {
|
||||
for (int j=0; j<3; j++) {
|
||||
for (int k=0; k<3; k++)
|
||||
size_t N_mem = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
for (int k = 0; k < 3; k++)
|
||||
N_mem += N_send_recv[i][j][k];
|
||||
}
|
||||
}
|
||||
mem = new TYPE[2*depth*N_mem];
|
||||
mem = new TYPE[2 * depth * N_mem];
|
||||
size_t index = 0;
|
||||
for (int i=0; i<3; i++) {
|
||||
for (int j=0; j<3; j++) {
|
||||
for (int k=0; k<3; k++) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
for (int k = 0; k < 3; k++) {
|
||||
send[i][j][k] = &mem[index];
|
||||
index += depth*N_send_recv[i][j][k];
|
||||
index += depth * N_send_recv[i][j][k];
|
||||
recv[i][j][k] = &mem[index];
|
||||
index += depth*N_send_recv[i][j][k];
|
||||
index += depth * N_send_recv[i][j][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create the tags
|
||||
for (int i=0; i<3; i++) {
|
||||
for (int j=0; j<3; j++) {
|
||||
for (int k=0; k<3; k++) {
|
||||
tag[i][j][k] = tag0 + i + j*3 + k*9;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
for (int k = 0; k < 3; k++) {
|
||||
tag[i][j][k] = tag0 + i + j * 3 + k * 9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
template<class TYPE>
|
||||
fillHalo<TYPE>::~fillHalo( )
|
||||
{
|
||||
delete [] mem;
|
||||
}
|
||||
template<class TYPE>
|
||||
void fillHalo<TYPE>::fill( Array<TYPE>& data )
|
||||
{
|
||||
template <class TYPE> fillHalo<TYPE>::~fillHalo() { delete[] mem; }
|
||||
template <class TYPE> void fillHalo<TYPE>::fill(Array<TYPE> &data) {
|
||||
//PROFILE_START("fillHalo::fill",1);
|
||||
int depth2 = data.size(3);
|
||||
ASSERT((int)data.size(0)==n[0]+2*ng[0]);
|
||||
ASSERT((int)data.size(1)==n[1]+2*ng[1]);
|
||||
ASSERT((int)data.size(2)==n[2]+2*ng[2]);
|
||||
ASSERT(depth2<=depth);
|
||||
ASSERT(data.ndim()==3||data.ndim()==4);
|
||||
ASSERT((int)data.size(0) == n[0] + 2 * ng[0]);
|
||||
ASSERT((int)data.size(1) == n[1] + 2 * ng[1]);
|
||||
ASSERT((int)data.size(2) == n[2] + 2 * ng[2]);
|
||||
ASSERT(depth2 <= depth);
|
||||
ASSERT(data.ndim() == 3 || data.ndim() == 4);
|
||||
// Start the recieves
|
||||
for (int i=0; i<3; i++) {
|
||||
for (int j=0; j<3; j++) {
|
||||
for (int k=0; k<3; k++) {
|
||||
if ( !fill_pattern[i][j][k] )
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
for (int k = 0; k < 3; k++) {
|
||||
if (!fill_pattern[i][j][k])
|
||||
continue;
|
||||
recv_req[i][j][k] = comm.Irecv( recv[i][j][k], depth2*N_send_recv[i][j][k],
|
||||
info.rank[i][j][k], tag[2-i][2-j][2-k] );
|
||||
recv_req[i][j][k] =
|
||||
comm.Irecv(recv[i][j][k], depth2 * N_send_recv[i][j][k],
|
||||
info.rank[i][j][k], tag[2 - i][2 - j][2 - k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Pack the src data and start the sends
|
||||
for (int i=0; i<3; i++) {
|
||||
for (int j=0; j<3; j++) {
|
||||
for (int k=0; k<3; k++) {
|
||||
if ( !fill_pattern[i][j][k] )
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
for (int k = 0; k < 3; k++) {
|
||||
if (!fill_pattern[i][j][k])
|
||||
continue;
|
||||
pack( data, i-1, j-1, k-1, send[i][j][k] );
|
||||
send_req[i][j][k] = comm.Isend( send[i][j][k], depth2*N_send_recv[i][j][k],
|
||||
info.rank[i][j][k], tag[i][j][k] );
|
||||
pack(data, i - 1, j - 1, k - 1, send[i][j][k]);
|
||||
send_req[i][j][k] =
|
||||
comm.Isend(send[i][j][k], depth2 * N_send_recv[i][j][k],
|
||||
info.rank[i][j][k], tag[i][j][k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Recv the dst data and unpack (we recive in reverse order to match the sends)
|
||||
for (int i=2; i>=0; i--) {
|
||||
for (int j=2; j>=0; j--) {
|
||||
for (int k=2; k>=0; k--) {
|
||||
if ( !fill_pattern[i][j][k] )
|
||||
for (int i = 2; i >= 0; i--) {
|
||||
for (int j = 2; j >= 0; j--) {
|
||||
for (int k = 2; k >= 0; k--) {
|
||||
if (!fill_pattern[i][j][k])
|
||||
continue;
|
||||
comm.wait( recv_req[i][j][k] );
|
||||
unpack( data, i-1, j-1, k-1, recv[i][j][k] );
|
||||
comm.wait(recv_req[i][j][k]);
|
||||
unpack(data, i - 1, j - 1, k - 1, recv[i][j][k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Wait until all sends have completed
|
||||
for (int i=0; i<3; i++) {
|
||||
for (int j=0; j<3; j++) {
|
||||
for (int k=0; k<3; k++) {
|
||||
if ( !fill_pattern[i][j][k] )
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
for (int k = 0; k < 3; k++) {
|
||||
if (!fill_pattern[i][j][k])
|
||||
continue;
|
||||
comm.wait( send_req[i][j][k] );
|
||||
comm.wait(send_req[i][j][k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
//PROFILE_STOP("fillHalo::fill",1);
|
||||
}
|
||||
template<class TYPE>
|
||||
void fillHalo<TYPE>::pack( const Array<TYPE>& data, int i0, int j0, int k0, TYPE *buffer )
|
||||
{
|
||||
template <class TYPE>
|
||||
void fillHalo<TYPE>::pack(const Array<TYPE> &data, int i0, int j0, int k0,
|
||||
TYPE *buffer) {
|
||||
int depth2 = data.size(3);
|
||||
int ni = i0==0 ? n[0]:ng[0];
|
||||
int nj = j0==0 ? n[1]:ng[1];
|
||||
int nk = k0==0 ? n[2]:ng[2];
|
||||
int is = i0==0 ? ng[0]:((i0==-1)?ng[0]:n[0]);
|
||||
int js = j0==0 ? ng[1]:((j0==-1)?ng[1]:n[1]);
|
||||
int ks = k0==0 ? ng[2]:((k0==-1)?ng[2]:n[2]);
|
||||
for (int d=0; d<depth2; d++) {
|
||||
for (int k=0; k<nk; k++) {
|
||||
for (int j=0; j<nj; j++) {
|
||||
for (int i=0; i<ni; i++) {
|
||||
buffer[i+j*ni+k*ni*nj+d*ni*nj*nk] = data(i+is,j+js,k+ks,d);
|
||||
int ni = i0 == 0 ? n[0] : ng[0];
|
||||
int nj = j0 == 0 ? n[1] : ng[1];
|
||||
int nk = k0 == 0 ? n[2] : ng[2];
|
||||
int is = i0 == 0 ? ng[0] : ((i0 == -1) ? ng[0] : n[0]);
|
||||
int js = j0 == 0 ? ng[1] : ((j0 == -1) ? ng[1] : n[1]);
|
||||
int ks = k0 == 0 ? ng[2] : ((k0 == -1) ? ng[2] : n[2]);
|
||||
for (int d = 0; d < depth2; d++) {
|
||||
for (int k = 0; k < nk; k++) {
|
||||
for (int j = 0; j < nj; j++) {
|
||||
for (int i = 0; i < ni; i++) {
|
||||
buffer[i + j * ni + k * ni * nj + d * ni * nj * nk] =
|
||||
data(i + is, j + js, k + ks, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
template<class TYPE>
|
||||
void fillHalo<TYPE>::unpack( Array<TYPE>& data, int i0, int j0, int k0, const TYPE *buffer )
|
||||
{
|
||||
template <class TYPE>
|
||||
void fillHalo<TYPE>::unpack(Array<TYPE> &data, int i0, int j0, int k0,
|
||||
const TYPE *buffer) {
|
||||
int depth2 = data.size(3);
|
||||
int ni = i0==0 ? n[0]:ng[0];
|
||||
int nj = j0==0 ? n[1]:ng[1];
|
||||
int nk = k0==0 ? n[2]:ng[2];
|
||||
int is = i0==0 ? ng[0]:((i0==-1)?0:n[0]+ng[0]);
|
||||
int js = j0==0 ? ng[1]:((j0==-1)?0:n[1]+ng[1]);
|
||||
int ks = k0==0 ? ng[2]:((k0==-1)?0:n[2]+ng[2]);
|
||||
for (int d=0; d<depth2; d++) {
|
||||
for (int k=0; k<nk; k++) {
|
||||
for (int j=0; j<nj; j++) {
|
||||
for (int i=0; i<ni; i++) {
|
||||
data(i+is,j+js,k+ks,d) = buffer[i+j*ni+k*ni*nj+d*ni*nj*nk];
|
||||
int ni = i0 == 0 ? n[0] : ng[0];
|
||||
int nj = j0 == 0 ? n[1] : ng[1];
|
||||
int nk = k0 == 0 ? n[2] : ng[2];
|
||||
int is = i0 == 0 ? ng[0] : ((i0 == -1) ? 0 : n[0] + ng[0]);
|
||||
int js = j0 == 0 ? ng[1] : ((j0 == -1) ? 0 : n[1] + ng[1]);
|
||||
int ks = k0 == 0 ? ng[2] : ((k0 == -1) ? 0 : n[2] + ng[2]);
|
||||
for (int d = 0; d < depth2; d++) {
|
||||
for (int k = 0; k < nk; k++) {
|
||||
for (int j = 0; j < nj; j++) {
|
||||
for (int i = 0; i < ni; i++) {
|
||||
data(i + is, j + js, k + ks, d) =
|
||||
buffer[i + j * ni + k * ni * nj + d * ni * nj * nk];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* Function to remove the ghost halo *
|
||||
********************************************************/
|
||||
template<class TYPE>
|
||||
template<class TYPE1, class TYPE2>
|
||||
void fillHalo<TYPE>::copy( const Array<TYPE1>& src, Array<TYPE2>& dst )
|
||||
{
|
||||
template <class TYPE>
|
||||
template <class TYPE1, class TYPE2>
|
||||
void fillHalo<TYPE>::copy(const Array<TYPE1> &src, Array<TYPE2> &dst) {
|
||||
//PROFILE_START("fillHalo::copy",1);
|
||||
ASSERT( (int)src.size(0)==n[0] || (int)src.size(0)==n[0]+2*ng[0] );
|
||||
ASSERT( (int)dst.size(0)==n[0] || (int)dst.size(0)==n[0]+2*ng[0] );
|
||||
bool src_halo = (int)src.size(0)==n[0]+2*ng[0];
|
||||
bool dst_halo = (int)dst.size(0)==n[0]+2*ng[0];
|
||||
if ( src_halo ) {
|
||||
ASSERT((int)src.size(0)==n[0]+2*ng[0]);
|
||||
ASSERT((int)src.size(1)==n[1]+2*ng[1]);
|
||||
ASSERT((int)src.size(2)==n[2]+2*ng[2]);
|
||||
ASSERT((int)src.size(0) == n[0] || (int)src.size(0) == n[0] + 2 * ng[0]);
|
||||
ASSERT((int)dst.size(0) == n[0] || (int)dst.size(0) == n[0] + 2 * ng[0]);
|
||||
bool src_halo = (int)src.size(0) == n[0] + 2 * ng[0];
|
||||
bool dst_halo = (int)dst.size(0) == n[0] + 2 * ng[0];
|
||||
if (src_halo) {
|
||||
ASSERT((int)src.size(0) == n[0] + 2 * ng[0]);
|
||||
ASSERT((int)src.size(1) == n[1] + 2 * ng[1]);
|
||||
ASSERT((int)src.size(2) == n[2] + 2 * ng[2]);
|
||||
} else {
|
||||
ASSERT((int)src.size(0)==n[0]);
|
||||
ASSERT((int)src.size(1)==n[1]);
|
||||
ASSERT((int)src.size(2)==n[2]);
|
||||
ASSERT((int)src.size(0) == n[0]);
|
||||
ASSERT((int)src.size(1) == n[1]);
|
||||
ASSERT((int)src.size(2) == n[2]);
|
||||
}
|
||||
if ( dst_halo ) {
|
||||
ASSERT((int)dst.size(0)==n[0]+2*ng[0]);
|
||||
ASSERT((int)dst.size(1)==n[1]+2*ng[1]);
|
||||
ASSERT((int)dst.size(2)==n[2]+2*ng[2]);
|
||||
if (dst_halo) {
|
||||
ASSERT((int)dst.size(0) == n[0] + 2 * ng[0]);
|
||||
ASSERT((int)dst.size(1) == n[1] + 2 * ng[1]);
|
||||
ASSERT((int)dst.size(2) == n[2] + 2 * ng[2]);
|
||||
} else {
|
||||
ASSERT((int)dst.size(0)==n[0]);
|
||||
ASSERT((int)dst.size(1)==n[1]);
|
||||
ASSERT((int)dst.size(2)==n[2]);
|
||||
ASSERT((int)dst.size(0) == n[0]);
|
||||
ASSERT((int)dst.size(1) == n[1]);
|
||||
ASSERT((int)dst.size(2) == n[2]);
|
||||
}
|
||||
if ( src_halo == dst_halo ) {
|
||||
if (src_halo == dst_halo) {
|
||||
// Src and dst halos match
|
||||
for (size_t i=0; i<src.length(); i++)
|
||||
for (size_t i = 0; i < src.length(); i++)
|
||||
dst(i) = src(i);
|
||||
} else if ( src_halo && !dst_halo ) {
|
||||
} else if (src_halo && !dst_halo) {
|
||||
// Src has halos
|
||||
for (int k=0; k<n[2]; k++) {
|
||||
for (int j=0; j<n[1]; j++) {
|
||||
for (int i=0; i<n[0]; i++) {
|
||||
dst(i,j,k) = src(i+ng[0],j+ng[1],k+ng[2]);
|
||||
for (int k = 0; k < n[2]; k++) {
|
||||
for (int j = 0; j < n[1]; j++) {
|
||||
for (int i = 0; i < n[0]; i++) {
|
||||
dst(i, j, k) = src(i + ng[0], j + ng[1], k + ng[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ( !src_halo && dst_halo ) {
|
||||
} else if (!src_halo && dst_halo) {
|
||||
// Dst has halos
|
||||
for (int k=0; k<n[2]; k++) {
|
||||
for (int j=0; j<n[1]; j++) {
|
||||
for (int i=0; i<n[0]; i++) {
|
||||
dst(i+ng[0],j+ng[1],k+ng[2]) = src(i,j,k);
|
||||
for (int k = 0; k < n[2]; k++) {
|
||||
for (int j = 0; j < n[1]; j++) {
|
||||
for (int i = 0; i < n[0]; i++) {
|
||||
dst(i + ng[0], j + ng[1], k + ng[2]) = src(i, j, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -372,5 +414,4 @@ void fillHalo<TYPE>::copy( const Array<TYPE1>& src, Array<TYPE2>& dst )
|
|||
//PROFILE_STOP("fillHalo::copy",1);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "common/Database.h"
|
||||
#include "common/Utilities.h"
|
||||
|
||||
|
@ -8,303 +24,268 @@
|
|||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Constructors/destructor *
|
||||
********************************************************************/
|
||||
Database::Database() = default;
|
||||
Database::Database() = default;
|
||||
Database::~Database() = default;
|
||||
Database::Database( const Database& rhs ) : KeyData( rhs )
|
||||
{
|
||||
Database::Database(const Database &rhs) : KeyData(rhs) {
|
||||
d_data.clear();
|
||||
for ( const auto& tmp : rhs.d_data )
|
||||
putData( tmp.first, tmp.second->clone() );
|
||||
for (const auto &tmp : rhs.d_data)
|
||||
putData(tmp.first, tmp.second->clone());
|
||||
}
|
||||
Database& Database::operator=( const Database& rhs )
|
||||
{
|
||||
if ( this == &rhs )
|
||||
Database &Database::operator=(const Database &rhs) {
|
||||
if (this == &rhs)
|
||||
return *this;
|
||||
d_data.clear();
|
||||
for ( const auto& tmp : rhs.d_data )
|
||||
putData( tmp.first, tmp.second->clone() );
|
||||
for (const auto &tmp : rhs.d_data)
|
||||
putData(tmp.first, tmp.second->clone());
|
||||
return *this;
|
||||
}
|
||||
Database::Database( Database&& rhs ) { std::swap( d_data, rhs.d_data ); }
|
||||
Database& Database::operator=( Database&& rhs )
|
||||
{
|
||||
if ( this != &rhs )
|
||||
std::swap( d_data, rhs.d_data );
|
||||
Database::Database(Database &&rhs) { std::swap(d_data, rhs.d_data); }
|
||||
Database &Database::operator=(Database &&rhs) {
|
||||
if (this != &rhs)
|
||||
std::swap(d_data, rhs.d_data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Clone the database *
|
||||
********************************************************************/
|
||||
std::shared_ptr<KeyData> Database::clone() const { return cloneDatabase(); }
|
||||
std::shared_ptr<Database> Database::cloneDatabase() const
|
||||
{
|
||||
std::shared_ptr<Database> Database::cloneDatabase() const {
|
||||
auto db = std::make_shared<Database>();
|
||||
for ( const auto& tmp : d_data )
|
||||
db->putData( tmp.first, tmp.second->clone() );
|
||||
for (const auto &tmp : d_data)
|
||||
db->putData(tmp.first, tmp.second->clone());
|
||||
return db;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Get the data object *
|
||||
********************************************************************/
|
||||
bool Database::keyExists( const std::string& key ) const
|
||||
{
|
||||
return d_data.find( key ) != d_data.end();
|
||||
bool Database::keyExists(const std::string &key) const {
|
||||
return d_data.find(key) != d_data.end();
|
||||
}
|
||||
std::shared_ptr<KeyData> Database::getData( const std::string& key )
|
||||
{
|
||||
auto it = d_data.find( key );
|
||||
if ( it == d_data.end() ) {
|
||||
std::shared_ptr<KeyData> Database::getData(const std::string &key) {
|
||||
auto it = d_data.find(key);
|
||||
if (it == d_data.end()) {
|
||||
char msg[1000];
|
||||
sprintf( msg, "Variable %s was not found in database", key.c_str() );
|
||||
ERROR( msg );
|
||||
sprintf(msg, "Variable %s was not found in database", key.c_str());
|
||||
ERROR(msg);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
std::shared_ptr<const KeyData> Database::getData( const std::string& key ) const
|
||||
{
|
||||
return const_cast<Database*>( this )->getData( key );
|
||||
std::shared_ptr<const KeyData> Database::getData(const std::string &key) const {
|
||||
return const_cast<Database *>(this)->getData(key);
|
||||
}
|
||||
bool Database::isDatabase( const std::string& key ) const
|
||||
{
|
||||
auto ptr = getData( key );
|
||||
auto ptr2 = std::dynamic_pointer_cast<const Database>( ptr );
|
||||
bool Database::isDatabase(const std::string &key) const {
|
||||
auto ptr = getData(key);
|
||||
auto ptr2 = std::dynamic_pointer_cast<const Database>(ptr);
|
||||
return ptr2 != nullptr;
|
||||
}
|
||||
std::shared_ptr<Database> Database::getDatabase( const std::string& key )
|
||||
{
|
||||
std::shared_ptr<KeyData> ptr = getData( key );
|
||||
std::shared_ptr<Database> ptr2 = std::dynamic_pointer_cast<Database>( ptr );
|
||||
if ( ptr2 == nullptr ) {
|
||||
std::shared_ptr<Database> Database::getDatabase(const std::string &key) {
|
||||
std::shared_ptr<KeyData> ptr = getData(key);
|
||||
std::shared_ptr<Database> ptr2 = std::dynamic_pointer_cast<Database>(ptr);
|
||||
if (ptr2 == nullptr) {
|
||||
char msg[1000];
|
||||
sprintf( msg, "Variable %s is not a database", key.c_str() );
|
||||
ERROR( msg );
|
||||
sprintf(msg, "Variable %s is not a database", key.c_str());
|
||||
ERROR(msg);
|
||||
}
|
||||
return ptr2;
|
||||
}
|
||||
std::shared_ptr<const Database> Database::getDatabase( const std::string& key ) const
|
||||
{
|
||||
return const_cast<Database*>( this )->getDatabase( key );
|
||||
std::shared_ptr<const Database>
|
||||
Database::getDatabase(const std::string &key) const {
|
||||
return const_cast<Database *>(this)->getDatabase(key);
|
||||
}
|
||||
std::vector<std::string> Database::getAllKeys() const
|
||||
{
|
||||
std::vector<std::string> Database::getAllKeys() const {
|
||||
std::vector<std::string> keys;
|
||||
keys.reserve( d_data.size() );
|
||||
for ( const auto& it : d_data )
|
||||
keys.push_back( it.first );
|
||||
keys.reserve(d_data.size());
|
||||
for (const auto &it : d_data)
|
||||
keys.push_back(it.first);
|
||||
return keys;
|
||||
}
|
||||
void Database::putDatabase( const std::string& key, std::shared_ptr<Database> db )
|
||||
{
|
||||
d_data[key] = std::move( db );
|
||||
void Database::putDatabase(const std::string &key,
|
||||
std::shared_ptr<Database> db) {
|
||||
d_data[key] = std::move(db);
|
||||
}
|
||||
void Database::putData( const std::string& key, std::shared_ptr<KeyData> data )
|
||||
{
|
||||
d_data[key] = std::move( data );
|
||||
void Database::putData(const std::string &key, std::shared_ptr<KeyData> data) {
|
||||
d_data[key] = std::move(data);
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Is the data of the given type *
|
||||
********************************************************************/
|
||||
template<>
|
||||
bool Database::isType<double>( const std::string& key ) const
|
||||
{
|
||||
auto type = getData( key )->type();
|
||||
template <> bool Database::isType<double>(const std::string &key) const {
|
||||
auto type = getData(key)->type();
|
||||
return type == "double";
|
||||
}
|
||||
template<>
|
||||
bool Database::isType<float>( const std::string& key ) const
|
||||
{
|
||||
auto type = getData( key )->type();
|
||||
template <> bool Database::isType<float>(const std::string &key) const {
|
||||
auto type = getData(key)->type();
|
||||
return type == "double";
|
||||
}
|
||||
template<>
|
||||
bool Database::isType<int>( const std::string& key ) const
|
||||
{
|
||||
template <> bool Database::isType<int>(const std::string &key) const {
|
||||
bool pass = true;
|
||||
auto type = getData( key )->type();
|
||||
if ( type == "double" ) {
|
||||
auto data = getVector<double>( key );
|
||||
for ( auto tmp : data )
|
||||
pass = pass && static_cast<double>( static_cast<int>( tmp ) ) == tmp;
|
||||
auto type = getData(key)->type();
|
||||
if (type == "double") {
|
||||
auto data = getVector<double>(key);
|
||||
for (auto tmp : data)
|
||||
pass = pass && static_cast<double>(static_cast<int>(tmp)) == tmp;
|
||||
} else {
|
||||
pass = false;
|
||||
}
|
||||
return pass;
|
||||
}
|
||||
template<>
|
||||
bool Database::isType<std::string>( const std::string& key ) const
|
||||
{
|
||||
auto type = getData( key )->type();
|
||||
template <> bool Database::isType<std::string>(const std::string &key) const {
|
||||
auto type = getData(key)->type();
|
||||
return type == "string";
|
||||
}
|
||||
template<>
|
||||
bool Database::isType<bool>( const std::string& key ) const
|
||||
{
|
||||
auto type = getData( key )->type();
|
||||
template <> bool Database::isType<bool>(const std::string &key) const {
|
||||
auto type = getData(key)->type();
|
||||
return type == "bool";
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Get a vector *
|
||||
********************************************************************/
|
||||
template<>
|
||||
std::vector<std::string> Database::getVector<std::string>(
|
||||
const std::string& key, const Units& ) const
|
||||
{
|
||||
std::shared_ptr<const KeyData> ptr = getData( key );
|
||||
if ( std::dynamic_pointer_cast<const EmptyKeyData>( ptr ) )
|
||||
template <>
|
||||
std::vector<std::string>
|
||||
Database::getVector<std::string>(const std::string &key, const Units &) const {
|
||||
std::shared_ptr<const KeyData> ptr = getData(key);
|
||||
if (std::dynamic_pointer_cast<const EmptyKeyData>(ptr))
|
||||
return std::vector<std::string>();
|
||||
const auto* ptr2 = dynamic_cast<const KeyDataString*>( ptr.get() );
|
||||
if ( ptr2 == nullptr ) {
|
||||
ERROR( "Key '" + key + "' is not a string" );
|
||||
const auto *ptr2 = dynamic_cast<const KeyDataString *>(ptr.get());
|
||||
if (ptr2 == nullptr) {
|
||||
ERROR("Key '" + key + "' is not a string");
|
||||
}
|
||||
return ptr2->d_data;
|
||||
}
|
||||
template<>
|
||||
std::vector<bool> Database::getVector<bool>( const std::string& key, const Units& ) const
|
||||
{
|
||||
std::shared_ptr<const KeyData> ptr = getData( key );
|
||||
if ( std::dynamic_pointer_cast<const EmptyKeyData>( ptr ) )
|
||||
template <>
|
||||
std::vector<bool> Database::getVector<bool>(const std::string &key,
|
||||
const Units &) const {
|
||||
std::shared_ptr<const KeyData> ptr = getData(key);
|
||||
if (std::dynamic_pointer_cast<const EmptyKeyData>(ptr))
|
||||
return std::vector<bool>();
|
||||
const auto* ptr2 = dynamic_cast<const KeyDataBool*>( ptr.get() );
|
||||
if ( ptr2 == nullptr ) {
|
||||
ERROR( "Key '" + key + "' is not a bool" );
|
||||
const auto *ptr2 = dynamic_cast<const KeyDataBool *>(ptr.get());
|
||||
if (ptr2 == nullptr) {
|
||||
ERROR("Key '" + key + "' is not a bool");
|
||||
}
|
||||
return ptr2->d_data;
|
||||
}
|
||||
template<class TYPE>
|
||||
std::vector<TYPE> Database::getVector( const std::string& key, const Units& unit ) const
|
||||
{
|
||||
std::shared_ptr<const KeyData> ptr = getData( key );
|
||||
if ( std::dynamic_pointer_cast<const EmptyKeyData>( ptr ) )
|
||||
template <class TYPE>
|
||||
std::vector<TYPE> Database::getVector(const std::string &key,
|
||||
const Units &unit) const {
|
||||
std::shared_ptr<const KeyData> ptr = getData(key);
|
||||
if (std::dynamic_pointer_cast<const EmptyKeyData>(ptr))
|
||||
return std::vector<TYPE>();
|
||||
std::vector<TYPE> data;
|
||||
if ( std::dynamic_pointer_cast<const KeyDataDouble>( ptr ) ) {
|
||||
const auto* ptr2 = dynamic_cast<const KeyDataDouble*>( ptr.get() );
|
||||
const std::vector<double>& data2 = ptr2->d_data;
|
||||
double factor = 1;
|
||||
if ( !unit.isNull() ) {
|
||||
INSIST( !ptr2->d_unit.isNull(), "Field " + key + " must have units" );
|
||||
factor = ptr2->d_unit.convert( unit );
|
||||
INSIST( factor != 0, "Unit conversion failed" );
|
||||
if (std::dynamic_pointer_cast<const KeyDataDouble>(ptr)) {
|
||||
const auto *ptr2 = dynamic_cast<const KeyDataDouble *>(ptr.get());
|
||||
const std::vector<double> &data2 = ptr2->d_data;
|
||||
double factor = 1;
|
||||
if (!unit.isNull()) {
|
||||
INSIST(!ptr2->d_unit.isNull(), "Field " + key + " must have units");
|
||||
factor = ptr2->d_unit.convert(unit);
|
||||
INSIST(factor != 0, "Unit conversion failed");
|
||||
}
|
||||
data.resize( data2.size() );
|
||||
for ( size_t i = 0; i < data2.size(); i++ )
|
||||
data[i] = static_cast<TYPE>( factor * data2[i] );
|
||||
} else if ( std::dynamic_pointer_cast<const KeyDataString>( ptr ) ) {
|
||||
ERROR( "Converting std::string to another type" );
|
||||
} else if ( std::dynamic_pointer_cast<const KeyDataBool>( ptr ) ) {
|
||||
ERROR( "Converting std::bool to another type" );
|
||||
data.resize(data2.size());
|
||||
for (size_t i = 0; i < data2.size(); i++)
|
||||
data[i] = static_cast<TYPE>(factor * data2[i]);
|
||||
} else if (std::dynamic_pointer_cast<const KeyDataString>(ptr)) {
|
||||
ERROR("Converting std::string to another type");
|
||||
} else if (std::dynamic_pointer_cast<const KeyDataBool>(ptr)) {
|
||||
ERROR("Converting std::bool to another type");
|
||||
} else {
|
||||
ERROR( "Unable to convert data format" );
|
||||
ERROR("Unable to convert data format");
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Put a vector *
|
||||
********************************************************************/
|
||||
template<>
|
||||
void Database::putVector<std::string>(
|
||||
const std::string& key, const std::vector<std::string>& data, const Units& )
|
||||
{
|
||||
std::shared_ptr<KeyDataString> ptr( new KeyDataString() );
|
||||
template <>
|
||||
void Database::putVector<std::string>(const std::string &key,
|
||||
const std::vector<std::string> &data,
|
||||
const Units &) {
|
||||
std::shared_ptr<KeyDataString> ptr(new KeyDataString());
|
||||
ptr->d_data = data;
|
||||
d_data[key] = ptr;
|
||||
}
|
||||
template<>
|
||||
void Database::putVector<bool>(
|
||||
const std::string& key, const std::vector<bool>& data, const Units& )
|
||||
{
|
||||
std::shared_ptr<KeyDataBool> ptr( new KeyDataBool() );
|
||||
template <>
|
||||
void Database::putVector<bool>(const std::string &key,
|
||||
const std::vector<bool> &data, const Units &) {
|
||||
std::shared_ptr<KeyDataBool> ptr(new KeyDataBool());
|
||||
ptr->d_data = data;
|
||||
d_data[key] = ptr;
|
||||
}
|
||||
template<class TYPE>
|
||||
void Database::putVector( const std::string& key, const std::vector<TYPE>& data, const Units& unit )
|
||||
{
|
||||
std::shared_ptr<KeyDataDouble> ptr( new KeyDataDouble() );
|
||||
template <class TYPE>
|
||||
void Database::putVector(const std::string &key, const std::vector<TYPE> &data,
|
||||
const Units &unit) {
|
||||
std::shared_ptr<KeyDataDouble> ptr(new KeyDataDouble());
|
||||
ptr->d_unit = unit;
|
||||
ptr->d_data.resize( data.size() );
|
||||
for ( size_t i = 0; i < data.size(); i++ )
|
||||
ptr->d_data[i] = static_cast<double>( data[i] );
|
||||
ptr->d_data.resize(data.size());
|
||||
for (size_t i = 0; i < data.size(); i++)
|
||||
ptr->d_data[i] = static_cast<double>(data[i]);
|
||||
d_data[key] = ptr;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Print the database *
|
||||
********************************************************************/
|
||||
void Database::print( std::ostream& os, const std::string& indent ) const
|
||||
{
|
||||
for ( const auto& it : d_data ) {
|
||||
void Database::print(std::ostream &os, const std::string &indent) const {
|
||||
for (const auto &it : d_data) {
|
||||
os << indent << it.first;
|
||||
if ( dynamic_cast<const Database*>( it.second.get() ) ) {
|
||||
const auto* db = dynamic_cast<const Database*>( it.second.get() );
|
||||
if (dynamic_cast<const Database *>(it.second.get())) {
|
||||
const auto *db = dynamic_cast<const Database *>(it.second.get());
|
||||
os << " {\n";
|
||||
db->print( os, indent + " " );
|
||||
db->print(os, indent + " ");
|
||||
os << indent << "}\n";
|
||||
} else {
|
||||
os << " = ";
|
||||
it.second->print( os, "" );
|
||||
it.second->print(os, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
std::string Database::print( const std::string& indent ) const
|
||||
{
|
||||
std::string Database::print(const std::string &indent) const {
|
||||
std::stringstream ss;
|
||||
print( ss, indent );
|
||||
print(ss, indent);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Read input database file *
|
||||
********************************************************************/
|
||||
Database::Database( const std::string& filename )
|
||||
{
|
||||
Database::Database(const std::string &filename) {
|
||||
// Read the input file into memory
|
||||
FILE* fid = fopen( filename.c_str(), "rb" );
|
||||
if ( fid == nullptr )
|
||||
ERROR( "Error opening file " + filename );
|
||||
fseek( fid, 0, SEEK_END );
|
||||
size_t bytes = ftell( fid );
|
||||
rewind( fid );
|
||||
auto* buffer = new char[bytes + 4];
|
||||
size_t result = fread( buffer, 1, bytes, fid );
|
||||
fclose( fid );
|
||||
if ( result != bytes )
|
||||
ERROR( "Error reading file " + filename );
|
||||
FILE *fid = fopen(filename.c_str(), "rb");
|
||||
if (fid == nullptr)
|
||||
ERROR("Error opening file " + filename);
|
||||
fseek(fid, 0, SEEK_END);
|
||||
size_t bytes = ftell(fid);
|
||||
rewind(fid);
|
||||
auto *buffer = new char[bytes + 4];
|
||||
size_t result = fread(buffer, 1, bytes, fid);
|
||||
fclose(fid);
|
||||
if (result != bytes)
|
||||
ERROR("Error reading file " + filename);
|
||||
buffer[bytes + 0] = '\n';
|
||||
buffer[bytes + 1] = '}';
|
||||
buffer[bytes + 2] = '\n';
|
||||
buffer[bytes + 3] = 0;
|
||||
// Create the database entries
|
||||
loadDatabase( buffer, *this );
|
||||
loadDatabase(buffer, *this);
|
||||
// Free temporary memory
|
||||
delete[] buffer;
|
||||
}
|
||||
std::shared_ptr<Database> Database::createFromString( const std::string& data )
|
||||
{
|
||||
std::shared_ptr<Database> db( new Database() );
|
||||
auto* buffer = new char[data.size() + 4];
|
||||
memcpy( buffer, data.data(), data.size() );
|
||||
std::shared_ptr<Database> Database::createFromString(const std::string &data) {
|
||||
std::shared_ptr<Database> db(new Database());
|
||||
auto *buffer = new char[data.size() + 4];
|
||||
memcpy(buffer, data.data(), data.size());
|
||||
buffer[data.size() + 0] = '\n';
|
||||
buffer[data.size() + 1] = '}';
|
||||
buffer[data.size() + 2] = '\n';
|
||||
buffer[data.size() + 3] = 0;
|
||||
loadDatabase( buffer, *db );
|
||||
loadDatabase(buffer, *db);
|
||||
delete[] buffer;
|
||||
return db;
|
||||
}
|
||||
|
@ -319,279 +300,285 @@ enum class token_type {
|
|||
end_bracket,
|
||||
end
|
||||
};
|
||||
inline size_t length( token_type type )
|
||||
{
|
||||
inline size_t length(token_type type) {
|
||||
size_t len = 0;
|
||||
if ( type == token_type::newline || type == token_type::quote || type == token_type::equal ||
|
||||
type == token_type::bracket || type == token_type::end_bracket ||
|
||||
type == token_type::end ) {
|
||||
if (type == token_type::newline || type == token_type::quote ||
|
||||
type == token_type::equal || type == token_type::bracket ||
|
||||
type == token_type::end_bracket || type == token_type::end) {
|
||||
len = 1;
|
||||
} else if ( type == token_type::line_comment || type == token_type::block_start ||
|
||||
type == token_type::block_stop ) {
|
||||
} else if (type == token_type::line_comment ||
|
||||
type == token_type::block_start ||
|
||||
type == token_type::block_stop) {
|
||||
len = 2;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
inline std::tuple<size_t, token_type> find_next_token( const char* buffer )
|
||||
{
|
||||
inline std::tuple<size_t, token_type> find_next_token(const char *buffer) {
|
||||
size_t i = 0;
|
||||
while ( true ) {
|
||||
if ( buffer[i] == '\n' || buffer[i] == '\r' ) {
|
||||
return std::pair<size_t, token_type>( i + 1, token_type::newline );
|
||||
} else if ( buffer[i] == 0 ) {
|
||||
return std::pair<size_t, token_type>( i + 1, token_type::end );
|
||||
} else if ( buffer[i] == '"' ) {
|
||||
return std::pair<size_t, token_type>( i + 1, token_type::quote );
|
||||
} else if ( buffer[i] == '=' ) {
|
||||
return std::pair<size_t, token_type>( i + 1, token_type::equal );
|
||||
} else if ( buffer[i] == '{' ) {
|
||||
return std::pair<size_t, token_type>( i + 1, token_type::bracket );
|
||||
} else if ( buffer[i] == '}' ) {
|
||||
return std::pair<size_t, token_type>( i + 1, token_type::end_bracket );
|
||||
} else if ( buffer[i] == '/' ) {
|
||||
if ( buffer[i + 1] == '/' ) {
|
||||
return std::pair<size_t, token_type>( i + 2, token_type::line_comment );
|
||||
} else if ( buffer[i + 1] == '*' ) {
|
||||
return std::pair<size_t, token_type>( i + 2, token_type::block_start );
|
||||
while (true) {
|
||||
if (buffer[i] == '\n' || buffer[i] == '\r') {
|
||||
return std::pair<size_t, token_type>(i + 1, token_type::newline);
|
||||
} else if (buffer[i] == 0) {
|
||||
return std::pair<size_t, token_type>(i + 1, token_type::end);
|
||||
} else if (buffer[i] == '"') {
|
||||
return std::pair<size_t, token_type>(i + 1, token_type::quote);
|
||||
} else if (buffer[i] == '=') {
|
||||
return std::pair<size_t, token_type>(i + 1, token_type::equal);
|
||||
} else if (buffer[i] == '{') {
|
||||
return std::pair<size_t, token_type>(i + 1, token_type::bracket);
|
||||
} else if (buffer[i] == '}') {
|
||||
return std::pair<size_t, token_type>(i + 1,
|
||||
token_type::end_bracket);
|
||||
} else if (buffer[i] == '/') {
|
||||
if (buffer[i + 1] == '/') {
|
||||
return std::pair<size_t, token_type>(i + 2,
|
||||
token_type::line_comment);
|
||||
} else if (buffer[i + 1] == '*') {
|
||||
return std::pair<size_t, token_type>(i + 2,
|
||||
token_type::block_start);
|
||||
}
|
||||
} else if ( buffer[i] == '*' ) {
|
||||
if ( buffer[i + 1] == '/' )
|
||||
return std::pair<size_t, token_type>( i + 2, token_type::block_stop );
|
||||
} else if (buffer[i] == '*') {
|
||||
if (buffer[i + 1] == '/')
|
||||
return std::pair<size_t, token_type>(i + 2,
|
||||
token_type::block_stop);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return std::pair<size_t, token_type>( 0, token_type::end );
|
||||
return std::pair<size_t, token_type>(0, token_type::end);
|
||||
}
|
||||
inline std::string deblank( const std::string& str )
|
||||
{
|
||||
inline std::string deblank(const std::string &str) {
|
||||
size_t i1 = 0xFFFFFFF, i2 = 0;
|
||||
for ( size_t i = 0; i < str.size(); i++ ) {
|
||||
if ( str[i] != ' ' ) {
|
||||
i1 = std::min( i1, i );
|
||||
i2 = std::max( i2, i );
|
||||
for (size_t i = 0; i < str.size(); i++) {
|
||||
if (str[i] != ' ') {
|
||||
i1 = std::min(i1, i);
|
||||
i2 = std::max(i2, i);
|
||||
}
|
||||
}
|
||||
return i1 <= i2 ? str.substr( i1, i2 - i1 + 1 ) : std::string();
|
||||
return i1 <= i2 ? str.substr(i1, i2 - i1 + 1) : std::string();
|
||||
}
|
||||
size_t skip_comment( const char* buffer )
|
||||
{
|
||||
auto tmp = find_next_token( buffer );
|
||||
const token_type end_comment = ( std::get<1>( tmp ) == token_type::line_comment ) ?
|
||||
token_type::newline :
|
||||
token_type::block_stop;
|
||||
size_t skip_comment(const char *buffer) {
|
||||
auto tmp = find_next_token(buffer);
|
||||
const token_type end_comment =
|
||||
(std::get<1>(tmp) == token_type::line_comment) ? token_type::newline
|
||||
: token_type::block_stop;
|
||||
size_t pos = 0;
|
||||
while ( std::get<1>( tmp ) != end_comment ) {
|
||||
if ( std::get<1>( tmp ) == token_type::end )
|
||||
ERROR( "Encountered end of file before block comment end" );
|
||||
pos += std::get<0>( tmp );
|
||||
tmp = find_next_token( &buffer[pos] );
|
||||
while (std::get<1>(tmp) != end_comment) {
|
||||
if (std::get<1>(tmp) == token_type::end)
|
||||
ERROR("Encountered end of file before block comment end");
|
||||
pos += std::get<0>(tmp);
|
||||
tmp = find_next_token(&buffer[pos]);
|
||||
}
|
||||
pos += std::get<0>( tmp );
|
||||
pos += std::get<0>(tmp);
|
||||
return pos;
|
||||
}
|
||||
inline std::string lower( const std::string& str )
|
||||
{
|
||||
std::string tmp( str );
|
||||
std::transform( tmp.begin(), tmp.end(), tmp.begin(), ::tolower );
|
||||
inline std::string lower(const std::string &str) {
|
||||
std::string tmp(str);
|
||||
std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
|
||||
return tmp;
|
||||
}
|
||||
static std::tuple<size_t, std::shared_ptr<KeyData>> read_value(
|
||||
const char* buffer, const std::string& key )
|
||||
{
|
||||
static std::tuple<size_t, std::shared_ptr<KeyData>>
|
||||
read_value(const char *buffer, const std::string &key) {
|
||||
// Get the value as a std::string
|
||||
size_t pos = 0;
|
||||
token_type type = token_type::end;
|
||||
std::tie( pos, type ) = find_next_token( &buffer[pos] );
|
||||
size_t len = pos - length( type );
|
||||
while ( type != token_type::newline ) {
|
||||
if ( type == token_type::quote ) {
|
||||
size_t i = 0;
|
||||
std::tie( i, type ) = find_next_token( &buffer[pos] );
|
||||
size_t pos = 0;
|
||||
token_type type = token_type::end;
|
||||
std::tie(pos, type) = find_next_token(&buffer[pos]);
|
||||
size_t len = pos - length(type);
|
||||
while (type != token_type::newline) {
|
||||
if (type == token_type::quote) {
|
||||
size_t i = 0;
|
||||
std::tie(i, type) = find_next_token(&buffer[pos]);
|
||||
pos += i;
|
||||
while ( type != token_type::quote ) {
|
||||
ASSERT( type != token_type::end );
|
||||
std::tie( i, type ) = find_next_token( &buffer[pos] );
|
||||
while (type != token_type::quote) {
|
||||
ASSERT(type != token_type::end);
|
||||
std::tie(i, type) = find_next_token(&buffer[pos]);
|
||||
pos += i;
|
||||
}
|
||||
} else if ( type == token_type::line_comment || type == token_type::block_start ) {
|
||||
len = pos - length( type );
|
||||
pos += skip_comment( &buffer[pos - length( type )] ) - length( type );
|
||||
} else if (type == token_type::line_comment ||
|
||||
type == token_type::block_start) {
|
||||
len = pos - length(type);
|
||||
pos += skip_comment(&buffer[pos - length(type)]) - length(type);
|
||||
break;
|
||||
}
|
||||
size_t i = 0;
|
||||
std::tie( i, type ) = find_next_token( &buffer[pos] );
|
||||
size_t i = 0;
|
||||
std::tie(i, type) = find_next_token(&buffer[pos]);
|
||||
pos += i;
|
||||
len = pos - length( type );
|
||||
len = pos - length(type);
|
||||
}
|
||||
const std::string value = deblank( std::string( buffer, len ) );
|
||||
const std::string value = deblank(std::string(buffer, len));
|
||||
// Split the value to an array of values
|
||||
std::vector<std::string> values;
|
||||
size_t i0 = 0, i = 0, count = 0;
|
||||
for ( ; i < value.size(); i++ ) {
|
||||
if ( value[i] == '"' ) {
|
||||
for (; i < value.size(); i++) {
|
||||
if (value[i] == '"') {
|
||||
count++;
|
||||
} else if ( value[i] == ',' && count % 2 == 0 ) {
|
||||
values.push_back( deblank( value.substr( i0, i - i0 ) ) );
|
||||
} else if (value[i] == ',' && count % 2 == 0) {
|
||||
values.push_back(deblank(value.substr(i0, i - i0)));
|
||||
i0 = i + 1;
|
||||
}
|
||||
}
|
||||
values.push_back( deblank( value.substr( i0 ) ) );
|
||||
values.push_back(deblank(value.substr(i0)));
|
||||
// Convert the string value to the database value
|
||||
std::shared_ptr<KeyData> data;
|
||||
if ( value.empty() ) {
|
||||
data.reset( new EmptyKeyData() );
|
||||
} else if ( value.find( '"' ) != std::string::npos ) {
|
||||
auto* data2 = new KeyDataString();
|
||||
data.reset( data2 );
|
||||
data2->d_data.resize( values.size() );
|
||||
for ( size_t i = 0; i < values.size(); i++ ) {
|
||||
ASSERT( values[i].size() >= 2 );
|
||||
ASSERT( values[i][0] == '"' && values[i][values[i].size() - 1] == '"' );
|
||||
data2->d_data[i] = values[i].substr( 1, values[i].size() - 2 );
|
||||
if (value.empty()) {
|
||||
data.reset(new EmptyKeyData());
|
||||
} else if (value.find('"') != std::string::npos) {
|
||||
auto *data2 = new KeyDataString();
|
||||
data.reset(data2);
|
||||
data2->d_data.resize(values.size());
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
ASSERT(values[i].size() >= 2);
|
||||
ASSERT(values[i][0] == '"' &&
|
||||
values[i][values[i].size() - 1] == '"');
|
||||
data2->d_data[i] = values[i].substr(1, values[i].size() - 2);
|
||||
}
|
||||
} else if ( lower( value ) == "true" || lower( value ) == "false" ) {
|
||||
auto* data2 = new KeyDataBool();
|
||||
data.reset( data2 );
|
||||
data2->d_data.resize( values.size() );
|
||||
for ( size_t i = 0; i < values.size(); i++ ) {
|
||||
ASSERT( values[i].size() >= 2 );
|
||||
if ( lower( values[i] ) != "true" && lower( values[i] ) != "false" )
|
||||
ERROR( "Error converting " + key + " to logical array" );
|
||||
data2->d_data[i] = lower( values[i] ) == "true";
|
||||
} else if (lower(value) == "true" || lower(value) == "false") {
|
||||
auto *data2 = new KeyDataBool();
|
||||
data.reset(data2);
|
||||
data2->d_data.resize(values.size());
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
ASSERT(values[i].size() >= 2);
|
||||
if (lower(values[i]) != "true" && lower(values[i]) != "false")
|
||||
ERROR("Error converting " + key + " to logical array");
|
||||
data2->d_data[i] = lower(values[i]) == "true";
|
||||
}
|
||||
} else { // if ( value.find('.')!=std::string::npos || value.find('e')!=std::string::npos ) {
|
||||
auto* data2 = new KeyDataDouble();
|
||||
data.reset( data2 );
|
||||
data2->d_data.resize( values.size(), 0 );
|
||||
for ( size_t i = 0; i < values.size(); i++ ) {
|
||||
auto *data2 = new KeyDataDouble();
|
||||
data.reset(data2);
|
||||
data2->d_data.resize(values.size(), 0);
|
||||
for (size_t i = 0; i < values.size(); i++) {
|
||||
Units unit;
|
||||
std::tie( data2->d_data[i], unit ) = KeyDataDouble::read( values[i] );
|
||||
if ( !unit.isNull() )
|
||||
std::tie(data2->d_data[i], unit) = KeyDataDouble::read(values[i]);
|
||||
if (!unit.isNull())
|
||||
data2->d_unit = unit;
|
||||
}
|
||||
//} else {
|
||||
// ERROR("Unable to determine data type: "+value);
|
||||
}
|
||||
return std::tuple<size_t, std::shared_ptr<KeyData>>( pos, data );
|
||||
return std::tuple<size_t, std::shared_ptr<KeyData>>(pos, data);
|
||||
}
|
||||
size_t Database::loadDatabase( const char* buffer, Database& db )
|
||||
{
|
||||
size_t Database::loadDatabase(const char *buffer, Database &db) {
|
||||
size_t pos = 0;
|
||||
while ( true ) {
|
||||
while (true) {
|
||||
size_t i;
|
||||
token_type type;
|
||||
std::tie( i, type ) = find_next_token( &buffer[pos] );
|
||||
const std::string key =
|
||||
deblank( std::string( &buffer[pos], std::max<int>( i - length( type ), 1 ) - 1 ) );
|
||||
if ( type == token_type::line_comment || type == token_type::block_start ) {
|
||||
std::tie(i, type) = find_next_token(&buffer[pos]);
|
||||
const std::string key = deblank(
|
||||
std::string(&buffer[pos], std::max<int>(i - length(type), 1) - 1));
|
||||
if (type == token_type::line_comment ||
|
||||
type == token_type::block_start) {
|
||||
// Comment
|
||||
INSIST( key.empty(), "Key should be empty: " + key );
|
||||
pos += skip_comment( &buffer[pos] );
|
||||
} else if ( type == token_type::newline ) {
|
||||
INSIST( key.empty(), "Key should be empty: " + key );
|
||||
INSIST(key.empty(), "Key should be empty: " + key);
|
||||
pos += skip_comment(&buffer[pos]);
|
||||
} else if (type == token_type::newline) {
|
||||
INSIST(key.empty(), "Key should be empty: " + key);
|
||||
pos += i;
|
||||
} else if ( type == token_type::equal ) {
|
||||
} else if (type == token_type::equal) {
|
||||
// Reading key/value pair
|
||||
ASSERT( !key.empty() );
|
||||
ASSERT(!key.empty());
|
||||
pos += i;
|
||||
std::shared_ptr<KeyData> data;
|
||||
std::tie( i, data ) = read_value( &buffer[pos], key );
|
||||
ASSERT( data.get() != nullptr );
|
||||
std::tie(i, data) = read_value(&buffer[pos], key);
|
||||
ASSERT(data.get() != nullptr);
|
||||
db.d_data[key] = data;
|
||||
pos += i;
|
||||
} else if ( type == token_type::bracket ) {
|
||||
} else if (type == token_type::bracket) {
|
||||
// Read database
|
||||
ASSERT( !key.empty() );
|
||||
ASSERT(!key.empty());
|
||||
pos += i;
|
||||
std::shared_ptr<Database> database( new Database() );
|
||||
pos += loadDatabase( &buffer[pos], *database );
|
||||
std::shared_ptr<Database> database(new Database());
|
||||
pos += loadDatabase(&buffer[pos], *database);
|
||||
db.d_data[key] = database;
|
||||
} else if ( type == token_type::end_bracket ) {
|
||||
} else if (type == token_type::end_bracket) {
|
||||
// Finished with the database
|
||||
pos += i;
|
||||
break;
|
||||
} else {
|
||||
ERROR( "Error loading data" );
|
||||
ERROR("Error loading data");
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Data type helper functions *
|
||||
********************************************************************/
|
||||
void KeyDataDouble::print( std::ostream& os, const std::string& indent ) const
|
||||
{
|
||||
void KeyDataDouble::print(std::ostream &os, const std::string &indent) const {
|
||||
os << indent;
|
||||
for ( size_t i = 0; i < d_data.size(); i++ ) {
|
||||
if ( i > 0 )
|
||||
for (size_t i = 0; i < d_data.size(); i++) {
|
||||
if (i > 0)
|
||||
os << ", ";
|
||||
if ( d_data[i] != d_data[i] ) {
|
||||
if (d_data[i] != d_data[i]) {
|
||||
os << "nan";
|
||||
} else if ( d_data[i] == std::numeric_limits<double>::infinity() ) {
|
||||
} else if (d_data[i] == std::numeric_limits<double>::infinity()) {
|
||||
os << "inf";
|
||||
} else if ( d_data[i] == -std::numeric_limits<double>::infinity() ) {
|
||||
} else if (d_data[i] == -std::numeric_limits<double>::infinity()) {
|
||||
os << "-inf";
|
||||
} else {
|
||||
os << std::setprecision( 12 ) << d_data[i];
|
||||
os << std::setprecision(12) << d_data[i];
|
||||
}
|
||||
}
|
||||
if ( !d_unit.isNull() )
|
||||
if (!d_unit.isNull())
|
||||
os << " " << d_unit.str();
|
||||
os << std::endl;
|
||||
}
|
||||
std::tuple<double, Units> KeyDataDouble::read( const std::string& str )
|
||||
{
|
||||
std::string tmp = deblank( str );
|
||||
size_t index = tmp.find( " " );
|
||||
if ( index != std::string::npos ) {
|
||||
return std::make_tuple(
|
||||
readValue( tmp.substr( 0, index ) ), Units( tmp.substr( index + 1 ) ) );
|
||||
std::tuple<double, Units> KeyDataDouble::read(const std::string &str) {
|
||||
std::string tmp = deblank(str);
|
||||
size_t index = tmp.find(" ");
|
||||
if (index != std::string::npos) {
|
||||
return std::make_tuple(readValue(tmp.substr(0, index)),
|
||||
Units(tmp.substr(index + 1)));
|
||||
} else {
|
||||
return std::make_tuple( readValue( tmp ), Units() );
|
||||
return std::make_tuple(readValue(tmp), Units());
|
||||
}
|
||||
}
|
||||
double KeyDataDouble::readValue( const std::string& str )
|
||||
{
|
||||
const std::string tmp = lower( str );
|
||||
double data = 0;
|
||||
if ( tmp == "inf" || tmp == "infinity" ) {
|
||||
double KeyDataDouble::readValue(const std::string &str) {
|
||||
const std::string tmp = lower(str);
|
||||
double data = 0;
|
||||
if (tmp == "inf" || tmp == "infinity") {
|
||||
data = std::numeric_limits<double>::infinity();
|
||||
} else if ( tmp == "-inf" || tmp == "-infinity" ) {
|
||||
} else if (tmp == "-inf" || tmp == "-infinity") {
|
||||
data = -std::numeric_limits<double>::infinity();
|
||||
} else if ( tmp == "nan" ) {
|
||||
} else if (tmp == "nan") {
|
||||
data = std::numeric_limits<double>::quiet_NaN();
|
||||
} else if ( tmp.find( '/' ) != std::string::npos ) {
|
||||
ERROR( "Error reading value" );
|
||||
} else if (tmp.find('/') != std::string::npos) {
|
||||
ERROR("Error reading value");
|
||||
} else {
|
||||
char* pos = nullptr;
|
||||
data = strtod( tmp.c_str(), &pos );
|
||||
if ( static_cast<size_t>( pos - tmp.c_str() ) == tmp.size() + 1 )
|
||||
ERROR( "Error reading value" );
|
||||
char *pos = nullptr;
|
||||
data = strtod(tmp.c_str(), &pos);
|
||||
if (static_cast<size_t>(pos - tmp.c_str()) == tmp.size() + 1)
|
||||
ERROR("Error reading value");
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Instantiations *
|
||||
********************************************************************/
|
||||
template std::vector<char> Database::getVector<char>( const std::string&, const Units& ) const;
|
||||
template std::vector<int> Database::getVector<int>( const std::string&, const Units& ) const;
|
||||
template std::vector<size_t> Database::getVector<size_t>( const std::string&, const Units& ) const;
|
||||
template std::vector<float> Database::getVector<float>( const std::string&, const Units& ) const;
|
||||
template std::vector<double> Database::getVector<double>( const std::string&, const Units& ) const;
|
||||
template void Database::putVector<char>(
|
||||
const std::string&, const std::vector<char>&, const Units& );
|
||||
template void Database::putVector<int>( const std::string&, const std::vector<int>&, const Units& );
|
||||
template void Database::putVector<size_t>(
|
||||
const std::string&, const std::vector<size_t>&, const Units& );
|
||||
template void Database::putVector<float>(
|
||||
const std::string&, const std::vector<float>&, const Units& );
|
||||
template void Database::putVector<double>(
|
||||
const std::string&, const std::vector<double>&, const Units& );
|
||||
template bool Database::isType<int>( const std::string& ) const;
|
||||
template bool Database::isType<float>( const std::string& ) const;
|
||||
template bool Database::isType<double>( const std::string& ) const;
|
||||
template bool Database::isType<std::string>( const std::string& ) const;
|
||||
template std::vector<char> Database::getVector<char>(const std::string &,
|
||||
const Units &) const;
|
||||
template std::vector<int> Database::getVector<int>(const std::string &,
|
||||
const Units &) const;
|
||||
template std::vector<size_t> Database::getVector<size_t>(const std::string &,
|
||||
const Units &) const;
|
||||
template std::vector<float> Database::getVector<float>(const std::string &,
|
||||
const Units &) const;
|
||||
template std::vector<double> Database::getVector<double>(const std::string &,
|
||||
const Units &) const;
|
||||
template void Database::putVector<char>(const std::string &,
|
||||
const std::vector<char> &,
|
||||
const Units &);
|
||||
template void Database::putVector<int>(const std::string &,
|
||||
const std::vector<int> &, const Units &);
|
||||
template void Database::putVector<size_t>(const std::string &,
|
||||
const std::vector<size_t> &,
|
||||
const Units &);
|
||||
template void Database::putVector<float>(const std::string &,
|
||||
const std::vector<float> &,
|
||||
const Units &);
|
||||
template void Database::putVector<double>(const std::string &,
|
||||
const std::vector<double> &,
|
||||
const Units &);
|
||||
template bool Database::isType<int>(const std::string &) const;
|
||||
template bool Database::isType<float>(const std::string &) const;
|
||||
template bool Database::isType<double>(const std::string &) const;
|
||||
template bool Database::isType<std::string>(const std::string &) const;
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef included_Database
|
||||
#define included_Database
|
||||
|
||||
|
@ -10,17 +26,13 @@
|
|||
|
||||
#include "common/Units.h"
|
||||
|
||||
|
||||
inline bool exists( const std::string& filename )
|
||||
{
|
||||
std::ifstream domain( filename );
|
||||
return domain.good();
|
||||
inline bool exists(const std::string &filename) {
|
||||
std::ifstream domain(filename);
|
||||
return domain.good();
|
||||
}
|
||||
|
||||
|
||||
//! Base class to hold data of a given type
|
||||
class KeyData
|
||||
{
|
||||
class KeyData {
|
||||
protected:
|
||||
//! Empty constructor
|
||||
KeyData() {}
|
||||
|
@ -31,19 +43,18 @@ public:
|
|||
//! Copy the data
|
||||
virtual std::shared_ptr<KeyData> clone() const = 0;
|
||||
//! Print the data to a stream
|
||||
virtual void print( std::ostream& os, const std::string& indent = "" ) const = 0;
|
||||
virtual void print(std::ostream &os,
|
||||
const std::string &indent = "") const = 0;
|
||||
//! Return the native data type
|
||||
virtual std::string type() const = 0;
|
||||
|
||||
protected:
|
||||
KeyData( const KeyData& ) {}
|
||||
KeyData& operator=( const KeyData& );
|
||||
KeyData(const KeyData &) {}
|
||||
KeyData &operator=(const KeyData &);
|
||||
};
|
||||
|
||||
|
||||
//! Class to a database
|
||||
class Database : public KeyData
|
||||
{
|
||||
class Database : public KeyData {
|
||||
public:
|
||||
//! Empty constructor
|
||||
Database();
|
||||
|
@ -52,25 +63,25 @@ public:
|
|||
* Open an database file.
|
||||
* @param filename Name of input file to open
|
||||
*/
|
||||
explicit Database( const std::string& filename );
|
||||
explicit Database(const std::string &filename);
|
||||
|
||||
/**
|
||||
* Create database from string
|
||||
* @param data String containing the database data
|
||||
*/
|
||||
static std::shared_ptr<Database> createFromString( const std::string& data );
|
||||
static std::shared_ptr<Database> createFromString(const std::string &data);
|
||||
|
||||
//! Copy constructor
|
||||
Database( const Database& );
|
||||
Database(const Database &);
|
||||
|
||||
//! Assignment operator
|
||||
Database& operator=( const Database& );
|
||||
Database &operator=(const Database &);
|
||||
|
||||
//! Move constructor
|
||||
Database( Database&& rhs );
|
||||
Database(Database &&rhs);
|
||||
|
||||
//! Move assignment operator
|
||||
Database& operator=( Database&& rhs );
|
||||
Database &operator=(Database &&rhs);
|
||||
|
||||
//! Destructor
|
||||
virtual ~Database();
|
||||
|
@ -81,25 +92,21 @@ public:
|
|||
//! Copy the data
|
||||
std::shared_ptr<Database> cloneDatabase() const;
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the specified key exists in the database and false
|
||||
* otherwise.
|
||||
* @param[in] key Key name to lookup.
|
||||
*/
|
||||
bool keyExists( const std::string& key ) const;
|
||||
|
||||
bool keyExists(const std::string &key) const;
|
||||
|
||||
/**
|
||||
* Return all keys in the database.
|
||||
*/
|
||||
std::vector<std::string> getAllKeys() const;
|
||||
|
||||
|
||||
//! Return the number of entries in the database
|
||||
size_t size() const { return d_data.size(); }
|
||||
|
||||
|
||||
/**
|
||||
* Get the scalar entry from the database with the specified key
|
||||
* name. If the specified key does not exist in the database or
|
||||
|
@ -109,14 +116,14 @@ public:
|
|||
* @param[in] key Key name in database.
|
||||
* @param[in] unit Desired units
|
||||
*/
|
||||
template<class TYPE>
|
||||
inline TYPE getScalar( const std::string& key, const Units& unit = Units() ) const;
|
||||
|
||||
template <class TYPE>
|
||||
inline TYPE getScalar(const std::string &key,
|
||||
const Units &unit = Units()) const;
|
||||
|
||||
/// @copydoc Database::getScalar(const std::string&,const Units&) const
|
||||
template<class TYPE>
|
||||
inline TYPE getScalar( const std::string& key, const std::string& unit ) const;
|
||||
|
||||
template <class TYPE>
|
||||
inline TYPE getScalar(const std::string &key,
|
||||
const std::string &unit) const;
|
||||
|
||||
/**
|
||||
* Get the scalar entry from the database with the specified key
|
||||
|
@ -127,16 +134,14 @@ public:
|
|||
* @param[in] value Default value
|
||||
* @param[in] unit Desired units
|
||||
*/
|
||||
template<class TYPE>
|
||||
inline TYPE getWithDefault(
|
||||
const std::string& key, const TYPE& value, const Units& unit = Units() ) const;
|
||||
|
||||
template <class TYPE>
|
||||
inline TYPE getWithDefault(const std::string &key, const TYPE &value,
|
||||
const Units &unit = Units()) const;
|
||||
|
||||
/// @copydoc Database::getWithDefault(const std::string&,const TYPE&,const Units&) const
|
||||
template<class TYPE>
|
||||
inline TYPE getWithDefault(
|
||||
const std::string& key, const TYPE& value, const std::string& unit ) const;
|
||||
|
||||
template <class TYPE>
|
||||
inline TYPE getWithDefault(const std::string &key, const TYPE &value,
|
||||
const std::string &unit) const;
|
||||
|
||||
/**
|
||||
* Put the scalar entry into the database with the specified key name.
|
||||
|
@ -144,9 +149,9 @@ public:
|
|||
* @param value Value to store
|
||||
* @param unit Desired units
|
||||
*/
|
||||
template<class TYPE>
|
||||
inline void putScalar( const std::string& key, const TYPE& value, const Units& unit = Units() );
|
||||
|
||||
template <class TYPE>
|
||||
inline void putScalar(const std::string &key, const TYPE &value,
|
||||
const Units &unit = Units());
|
||||
|
||||
/**
|
||||
* Put the scalar entry into the database with the specified key name.
|
||||
|
@ -154,9 +159,9 @@ public:
|
|||
* @param value Value to store
|
||||
* @param unit Desired units
|
||||
*/
|
||||
template<class TYPE>
|
||||
inline void putScalar( const std::string& key, const TYPE& value, const std::string& unit );
|
||||
|
||||
template <class TYPE>
|
||||
inline void putScalar(const std::string &key, const TYPE &value,
|
||||
const std::string &unit);
|
||||
|
||||
/**
|
||||
* Get the vector entries from the database with the specified key
|
||||
|
@ -167,14 +172,14 @@ public:
|
|||
* @param key Key name in database.
|
||||
* @param unit Desired units
|
||||
*/
|
||||
template<class TYPE>
|
||||
std::vector<TYPE> getVector( const std::string& key, const Units& unit = Units() ) const;
|
||||
|
||||
template <class TYPE>
|
||||
std::vector<TYPE> getVector(const std::string &key,
|
||||
const Units &unit = Units()) const;
|
||||
|
||||
/// @copydoc Database::getVector(const std::string&,const Units&) const
|
||||
template<class TYPE>
|
||||
inline std::vector<TYPE> getVector( const std::string& key, const std::string& unit ) const;
|
||||
|
||||
template <class TYPE>
|
||||
inline std::vector<TYPE> getVector(const std::string &key,
|
||||
const std::string &unit) const;
|
||||
|
||||
/**
|
||||
* Put the vector entries into the database with the specified key
|
||||
|
@ -186,16 +191,14 @@ public:
|
|||
* @param data Data to store
|
||||
* @param unit Desired units
|
||||
*/
|
||||
template<class TYPE>
|
||||
void putVector(
|
||||
const std::string& key, const std::vector<TYPE>& data, const Units& unit = Units() );
|
||||
|
||||
template <class TYPE>
|
||||
void putVector(const std::string &key, const std::vector<TYPE> &data,
|
||||
const Units &unit = Units());
|
||||
|
||||
/// @copydoc Database::putVector(const std::string&,const std::vector<TYPE>&,const Units&)
|
||||
template<class TYPE>
|
||||
inline void putVector(
|
||||
const std::string& key, const std::vector<TYPE>& data, const std::string& unit );
|
||||
|
||||
template <class TYPE>
|
||||
inline void putVector(const std::string &key, const std::vector<TYPE> &data,
|
||||
const std::string &unit);
|
||||
|
||||
/**
|
||||
* Get the data for a key in the database. If the specified key
|
||||
|
@ -204,7 +207,7 @@ public:
|
|||
*
|
||||
* @param key Key name in database.
|
||||
*/
|
||||
std::shared_ptr<KeyData> getData( const std::string& key );
|
||||
std::shared_ptr<KeyData> getData(const std::string &key);
|
||||
|
||||
/**
|
||||
* Get the data for a key in the database. If the specified key
|
||||
|
@ -213,8 +216,7 @@ public:
|
|||
*
|
||||
* @param key Key name in database.
|
||||
*/
|
||||
std::shared_ptr<const KeyData> getData( const std::string& key ) const;
|
||||
|
||||
std::shared_ptr<const KeyData> getData(const std::string &key) const;
|
||||
|
||||
/**
|
||||
* Put the data for a key in the database.
|
||||
|
@ -222,17 +224,13 @@ public:
|
|||
* @param key Key name in database.
|
||||
* @param data Data to store
|
||||
*/
|
||||
void putData( const std::string& key, std::shared_ptr<KeyData> data );
|
||||
|
||||
void putData(const std::string &key, std::shared_ptr<KeyData> data);
|
||||
|
||||
// Check if the key is a database object
|
||||
bool isDatabase( const std::string& key ) const;
|
||||
|
||||
bool isDatabase(const std::string &key) const;
|
||||
|
||||
// Check if the entry can be stored as the given type
|
||||
template<class TYPE>
|
||||
bool isType( const std::string& key ) const;
|
||||
|
||||
template <class TYPE> bool isType(const std::string &key) const;
|
||||
|
||||
/**
|
||||
* Get the database for a key in the database. If the specified key
|
||||
|
@ -241,7 +239,7 @@ public:
|
|||
*
|
||||
* @param key Key name in database.
|
||||
*/
|
||||
std::shared_ptr<Database> getDatabase( const std::string& key );
|
||||
std::shared_ptr<Database> getDatabase(const std::string &key);
|
||||
|
||||
/**
|
||||
* Get the database for a key in the database. If the specified key
|
||||
|
@ -250,8 +248,7 @@ public:
|
|||
*
|
||||
* @param key Key name in database.
|
||||
*/
|
||||
std::shared_ptr<const Database> getDatabase( const std::string& key ) const;
|
||||
|
||||
std::shared_ptr<const Database> getDatabase(const std::string &key) const;
|
||||
|
||||
/**
|
||||
* Get the database for a key in the database. If the specified key
|
||||
|
@ -261,36 +258,32 @@ public:
|
|||
* @param key Key name in database.
|
||||
* @param db Database to store
|
||||
*/
|
||||
void putDatabase( const std::string& key, std::shared_ptr<Database> db );
|
||||
|
||||
void putDatabase(const std::string &key, std::shared_ptr<Database> db);
|
||||
|
||||
/**
|
||||
* Print the data to a stream
|
||||
* @param os Output stream
|
||||
* @param indent Indenting to use before each line
|
||||
*/
|
||||
virtual void print( std::ostream& os, const std::string& indent = "" ) const override;
|
||||
|
||||
virtual void print(std::ostream &os,
|
||||
const std::string &indent = "") const override;
|
||||
|
||||
//! Print the type
|
||||
virtual std::string type() const override { return "database"; }
|
||||
|
||||
|
||||
/**
|
||||
* Print the data to a string
|
||||
* @return Output string
|
||||
*/
|
||||
std::string print( const std::string& indent = "" ) const;
|
||||
|
||||
std::string print(const std::string &indent = "") const;
|
||||
|
||||
protected:
|
||||
std::map<std::string, std::shared_ptr<KeyData>> d_data;
|
||||
|
||||
// Function to load a database from a buffer
|
||||
static size_t loadDatabase( const char* buffer, Database& db );
|
||||
static size_t loadDatabase(const char *buffer, Database &db);
|
||||
};
|
||||
|
||||
|
||||
#include "common/Database.hpp"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,35 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef included_Database_hpp
|
||||
#define included_Database_hpp
|
||||
|
||||
|
@ -6,66 +38,58 @@
|
|||
|
||||
#include <tuple>
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Basic classes for primative data types *
|
||||
********************************************************************/
|
||||
class EmptyKeyData : public KeyData
|
||||
{
|
||||
class EmptyKeyData : public KeyData {
|
||||
public:
|
||||
EmptyKeyData() {}
|
||||
virtual ~EmptyKeyData() {}
|
||||
virtual std::shared_ptr<KeyData> clone() const override
|
||||
{
|
||||
virtual std::shared_ptr<KeyData> clone() const override {
|
||||
return std::make_shared<EmptyKeyData>();
|
||||
}
|
||||
virtual void print( std::ostream& os, const std::string& = "" ) const override
|
||||
{
|
||||
virtual void print(std::ostream &os,
|
||||
const std::string & = "") const override {
|
||||
os << std::endl;
|
||||
}
|
||||
virtual std::string type() const override { return ""; }
|
||||
};
|
||||
class KeyDataDouble : public KeyData
|
||||
{
|
||||
class KeyDataDouble : public KeyData {
|
||||
public:
|
||||
KeyDataDouble() {}
|
||||
explicit KeyDataDouble( const std::vector<double>& data, const Units& unit )
|
||||
: d_data( data ), d_unit( unit )
|
||||
{
|
||||
}
|
||||
explicit KeyDataDouble(const std::vector<double> &data, const Units &unit)
|
||||
: d_data(data), d_unit(unit) {}
|
||||
virtual ~KeyDataDouble() {}
|
||||
virtual std::shared_ptr<KeyData> clone() const override
|
||||
{
|
||||
return std::make_shared<KeyDataDouble>( d_data, d_unit );
|
||||
virtual std::shared_ptr<KeyData> clone() const override {
|
||||
return std::make_shared<KeyDataDouble>(d_data, d_unit);
|
||||
}
|
||||
virtual void print( std::ostream& os, const std::string& indent = "" ) const override;
|
||||
virtual void print(std::ostream &os,
|
||||
const std::string &indent = "") const override;
|
||||
virtual std::string type() const override { return "double"; }
|
||||
|
||||
static std::tuple<double, Units> read( const std::string& );
|
||||
static double readValue( const std::string& );
|
||||
static std::tuple<double, Units> read(const std::string &);
|
||||
static double readValue(const std::string &);
|
||||
|
||||
public:
|
||||
std::vector<double> d_data;
|
||||
Units d_unit;
|
||||
};
|
||||
class KeyDataBool : public KeyData
|
||||
{
|
||||
class KeyDataBool : public KeyData {
|
||||
public:
|
||||
KeyDataBool() {}
|
||||
explicit KeyDataBool( const std::vector<bool>& data ) : d_data( data ) {}
|
||||
explicit KeyDataBool(const std::vector<bool> &data) : d_data(data) {}
|
||||
virtual ~KeyDataBool() {}
|
||||
virtual std::shared_ptr<KeyData> clone() const override
|
||||
{
|
||||
return std::make_shared<KeyDataBool>( d_data );
|
||||
virtual std::shared_ptr<KeyData> clone() const override {
|
||||
return std::make_shared<KeyDataBool>(d_data);
|
||||
}
|
||||
virtual void print( std::ostream& os, const std::string& indent = "" ) const override
|
||||
{
|
||||
virtual void print(std::ostream &os,
|
||||
const std::string &indent = "") const override {
|
||||
os << indent;
|
||||
for ( size_t i = 0; i < d_data.size(); i++ ) {
|
||||
if ( i > 0 ) {
|
||||
for (size_t i = 0; i < d_data.size(); i++) {
|
||||
if (i > 0) {
|
||||
os << ", ";
|
||||
}
|
||||
if ( d_data[i] ) {
|
||||
if (d_data[i]) {
|
||||
os << "true";
|
||||
} else {
|
||||
os << "false";
|
||||
|
@ -76,21 +100,20 @@ public:
|
|||
virtual std::string type() const override { return "bool"; }
|
||||
std::vector<bool> d_data;
|
||||
};
|
||||
class KeyDataString : public KeyData
|
||||
{
|
||||
class KeyDataString : public KeyData {
|
||||
public:
|
||||
KeyDataString() {}
|
||||
explicit KeyDataString( const std::vector<std::string>& data ) : d_data( data ) {}
|
||||
explicit KeyDataString(const std::vector<std::string> &data)
|
||||
: d_data(data) {}
|
||||
virtual ~KeyDataString() {}
|
||||
virtual std::shared_ptr<KeyData> clone() const override
|
||||
{
|
||||
return std::make_shared<KeyDataString>( d_data );
|
||||
virtual std::shared_ptr<KeyData> clone() const override {
|
||||
return std::make_shared<KeyDataString>(d_data);
|
||||
}
|
||||
virtual void print( std::ostream& os, const std::string& indent = "" ) const override
|
||||
{
|
||||
virtual void print(std::ostream &os,
|
||||
const std::string &indent = "") const override {
|
||||
os << indent;
|
||||
for ( size_t i = 0; i < d_data.size(); i++ ) {
|
||||
if ( i > 0 ) {
|
||||
for (size_t i = 0; i < d_data.size(); i++) {
|
||||
if (i > 0) {
|
||||
os << ", ";
|
||||
}
|
||||
os << '"' << d_data[i] << '"';
|
||||
|
@ -101,73 +124,66 @@ public:
|
|||
std::vector<std::string> d_data;
|
||||
};
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Get a vector *
|
||||
********************************************************************/
|
||||
template<class TYPE>
|
||||
inline std::vector<TYPE> Database::getVector(
|
||||
const std::string& key, const std::string& unit ) const
|
||||
{
|
||||
return getVector<TYPE>( key, Units( unit ) );
|
||||
template <class TYPE>
|
||||
inline std::vector<TYPE> Database::getVector(const std::string &key,
|
||||
const std::string &unit) const {
|
||||
return getVector<TYPE>(key, Units(unit));
|
||||
}
|
||||
template<class TYPE>
|
||||
inline void Database::putVector(
|
||||
const std::string& key, const std::vector<TYPE>& data, const std::string& unit )
|
||||
{
|
||||
putVector<TYPE>( key, data, Units( unit ) );
|
||||
template <class TYPE>
|
||||
inline void Database::putVector(const std::string &key,
|
||||
const std::vector<TYPE> &data,
|
||||
const std::string &unit) {
|
||||
putVector<TYPE>(key, data, Units(unit));
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Get a scalar *
|
||||
********************************************************************/
|
||||
template<class TYPE>
|
||||
inline TYPE Database::getScalar( const std::string& key, const Units& unit ) const
|
||||
{
|
||||
const std::vector<TYPE>& data = getVector<TYPE>( key, unit );
|
||||
if ( data.size() != 1 ) {
|
||||
template <class TYPE>
|
||||
inline TYPE Database::getScalar(const std::string &key,
|
||||
const Units &unit) const {
|
||||
const std::vector<TYPE> &data = getVector<TYPE>(key, unit);
|
||||
if (data.size() != 1) {
|
||||
char msg[1000];
|
||||
sprintf( msg, "Variable %s is not a scalar", key.c_str() );
|
||||
ERROR( msg );
|
||||
sprintf(msg, "Variable %s is not a scalar", key.c_str());
|
||||
ERROR(msg);
|
||||
}
|
||||
return data[0];
|
||||
}
|
||||
template<class TYPE>
|
||||
inline TYPE Database::getWithDefault(
|
||||
const std::string& key, const TYPE& value, const Units& unit ) const
|
||||
{
|
||||
if ( !keyExists( key ) )
|
||||
template <class TYPE>
|
||||
inline TYPE Database::getWithDefault(const std::string &key, const TYPE &value,
|
||||
const Units &unit) const {
|
||||
if (!keyExists(key))
|
||||
return value;
|
||||
return getScalar<TYPE>( key, unit );
|
||||
return getScalar<TYPE>(key, unit);
|
||||
}
|
||||
template<class TYPE>
|
||||
inline void Database::putScalar( const std::string& key, const TYPE& data, const Units& unit )
|
||||
{
|
||||
putVector<TYPE>( key, std::vector<TYPE>( 1, data ), unit );
|
||||
template <class TYPE>
|
||||
inline void Database::putScalar(const std::string &key, const TYPE &data,
|
||||
const Units &unit) {
|
||||
putVector<TYPE>(key, std::vector<TYPE>(1, data), unit);
|
||||
}
|
||||
template<class TYPE>
|
||||
inline TYPE Database::getScalar( const std::string& key, const std::string& unit ) const
|
||||
{
|
||||
return getScalar<TYPE>( key, Units( unit ) );
|
||||
template <class TYPE>
|
||||
inline TYPE Database::getScalar(const std::string &key,
|
||||
const std::string &unit) const {
|
||||
return getScalar<TYPE>(key, Units(unit));
|
||||
}
|
||||
template<class TYPE>
|
||||
inline TYPE Database::getWithDefault(
|
||||
const std::string& key, const TYPE& value, const std::string& unit ) const
|
||||
{
|
||||
return getWithDefault<TYPE>( key, value, Units( unit ) );
|
||||
template <class TYPE>
|
||||
inline TYPE Database::getWithDefault(const std::string &key, const TYPE &value,
|
||||
const std::string &unit) const {
|
||||
return getWithDefault<TYPE>(key, value, Units(unit));
|
||||
}
|
||||
template<class TYPE>
|
||||
inline void Database::putScalar( const std::string& key, const TYPE& data, const std::string& unit )
|
||||
{
|
||||
putScalar<TYPE>( key, data, Units( unit ) );
|
||||
template <class TYPE>
|
||||
inline void Database::putScalar(const std::string &key, const TYPE &data,
|
||||
const std::string &unit) {
|
||||
putScalar<TYPE>(key, data, Units(unit));
|
||||
}
|
||||
template<class TYPE>
|
||||
inline void putVector(
|
||||
const std::string& key, const std::vector<TYPE>& data, const std::string& unit )
|
||||
{
|
||||
putVector<TYPE>( key, data, Units( unit ) );
|
||||
template <class TYPE>
|
||||
inline void putVector(const std::string &key, const std::vector<TYPE> &data,
|
||||
const std::string &unit) {
|
||||
putVector<TYPE>(key, data, Units(unit));
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
2704
common/Domain.cpp
2704
common/Domain.cpp
File diff suppressed because it is too large
Load Diff
332
common/Domain.h
Executable file → Normal file
332
common/Domain.h
Executable file → Normal file
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef Domain_INC
|
||||
#define Domain_INC
|
||||
|
||||
|
@ -16,100 +32,106 @@
|
|||
#include "common/MPI.h"
|
||||
#include "common/Communication.h"
|
||||
#include "common/Database.h"
|
||||
/**
|
||||
* @file Domain.h
|
||||
* \brief Parallel Domain data structures and helper functions
|
||||
*/
|
||||
|
||||
class Domain;
|
||||
template<class TYPE> class PatchData;
|
||||
|
||||
|
||||
//! Class to hold information about a box
|
||||
/**
|
||||
* \class Box
|
||||
*
|
||||
* @details
|
||||
* information about a box
|
||||
*/
|
||||
class Box {
|
||||
public:
|
||||
int ifirst[3];
|
||||
int ilast[3];
|
||||
};
|
||||
|
||||
class Patch;
|
||||
|
||||
enum class DataLocation { CPU, DEVICE };
|
||||
/**
|
||||
* \class Domain
|
||||
*
|
||||
* @details
|
||||
* the Domain class includes basic information to distribution 3D image data to multiple processes using MPI.
|
||||
* A regular domain decomposision is performed, with each MPI process getting a [Nx,Ny,Nz] sub-domain.
|
||||
* 8-bit image labels are retained internally.
|
||||
* The domain class resides on the CPU and provides utilities to support CPU-based analysis.
|
||||
* GPU-based data structures should be constructed separately but may utilize information that the Domain class provides.
|
||||
*/
|
||||
|
||||
|
||||
//! Class to hold information about a patch
|
||||
class Patch {
|
||||
class Domain {
|
||||
public:
|
||||
|
||||
//! Empty constructor
|
||||
Patch() = delete;
|
||||
/**
|
||||
* \brief Constructor
|
||||
* @param db input database
|
||||
* @param Communicator MPI communicator
|
||||
*/
|
||||
Domain(std::shared_ptr<Database> db, const Utilities::MPI &Communicator);
|
||||
|
||||
//! Copy constructor
|
||||
Patch( const Patch& ) = delete;
|
||||
/**
|
||||
* \brief Obsolete constructor
|
||||
*/
|
||||
Domain(int nx, int ny, int nz, int rnk, int npx, int npy, int npz,
|
||||
double lx, double ly, double lz, int BC);
|
||||
|
||||
//! Assignment operator
|
||||
Patch& operator=( const Patch& ) = delete;
|
||||
|
||||
//! Return the box for the patch
|
||||
inline const Box& getBox() const { return d_box; }
|
||||
|
||||
//! Create patch data
|
||||
template<class TYPE>
|
||||
std::shared_ptr<PatchData<TYPE>> createPatchData( DataLocation location ) const;
|
||||
|
||||
private:
|
||||
Box d_box;
|
||||
int d_owner;
|
||||
Domain *d_domain;
|
||||
|
||||
};
|
||||
|
||||
|
||||
//! Class to hold domain info
|
||||
class Domain{
|
||||
public:
|
||||
//! Default constructor
|
||||
Domain( std::shared_ptr<Database> db, const Utilities::MPI& Communicator);
|
||||
|
||||
//! Obsolete constructor
|
||||
Domain( int nx, int ny, int nz, int rnk, int npx, int npy, int npz,
|
||||
double lx, double ly, double lz, int BC);
|
||||
|
||||
//! Empty constructor
|
||||
/**
|
||||
* \brief Empty constructor
|
||||
*/
|
||||
Domain() = delete;
|
||||
|
||||
//! Copy constructor
|
||||
Domain( const Domain& ) = delete;
|
||||
/**
|
||||
* \brief Copy constructor
|
||||
*/
|
||||
Domain(const Domain &) = delete;
|
||||
|
||||
//! Assignment operator
|
||||
Domain& operator=( const Domain& ) = delete;
|
||||
/**
|
||||
* \brief Assignment operator
|
||||
*/
|
||||
Domain &operator=(const Domain &) = delete;
|
||||
|
||||
//! Destructor
|
||||
/**
|
||||
* \brief Destructor
|
||||
*/
|
||||
~Domain();
|
||||
|
||||
//! Get the database
|
||||
|
||||
/**
|
||||
* \brief Get the database
|
||||
*/
|
||||
inline std::shared_ptr<const Database> getDatabase() const { return d_db; }
|
||||
|
||||
//! Get the domain box
|
||||
inline const Box& getBox() const { return d_box; }
|
||||
/**
|
||||
* \brief Get the domain box
|
||||
*/
|
||||
inline const Box &getBox() const { return d_box; }
|
||||
|
||||
//! Get local patch
|
||||
inline const Patch& getLocalPatch() const { return *d_localPatch; }
|
||||
|
||||
//! Get all patches
|
||||
inline const std::vector<Patch>& getAllPatch() const { return d_patches; }
|
||||
/**
|
||||
* \brief Get local patch
|
||||
*/
|
||||
inline const Patch &getLocalPatch() const { return *d_localPatch; }
|
||||
|
||||
/**
|
||||
* \brief Get all patches
|
||||
*/
|
||||
inline const std::vector<Patch> &getAllPatch() const { return d_patches; }
|
||||
|
||||
private:
|
||||
|
||||
void initialize( std::shared_ptr<Database> db );
|
||||
/**
|
||||
* \brief initialize from database
|
||||
*/
|
||||
void initialize(std::shared_ptr<Database> db);
|
||||
|
||||
std::shared_ptr<Database> d_db;
|
||||
Box d_box;
|
||||
Patch *d_localPatch;
|
||||
std::vector<Patch> d_patches;
|
||||
|
||||
|
||||
public: // Public variables (need to create accessors instead)
|
||||
|
||||
std::shared_ptr<Database> database;
|
||||
double Lx,Ly,Lz,Volume,voxel_length;
|
||||
int Nx,Ny,Nz,N;
|
||||
double Lx, Ly, Lz, Volume, voxel_length;
|
||||
int Nx, Ny, Nz, N;
|
||||
int inlet_layers_x, inlet_layers_y, inlet_layers_z;
|
||||
int outlet_layers_x, outlet_layers_y, outlet_layers_z;
|
||||
int inlet_layers_phase; //as usual: 1->n, 2->w
|
||||
|
@ -117,13 +139,16 @@ public: // Public variables (need to create accessors instead)
|
|||
double porosity;
|
||||
RankInfoStruct rank_info;
|
||||
|
||||
Utilities::MPI Comm; // MPI Communicator for this domain
|
||||
Utilities::MPI Comm; // MPI Communicator for this domain
|
||||
|
||||
int BoundaryCondition;
|
||||
|
||||
//**********************************
|
||||
// MPI ranks for all 18 neighbors
|
||||
//**********************************
|
||||
/**
|
||||
* \brief Compute the porosity based on the current domain id file
|
||||
*/
|
||||
inline double Porosity() const { return porosity; }
|
||||
inline int iproc() const { return rank_info.ix; }
|
||||
inline int jproc() const { return rank_info.jy; }
|
||||
|
@ -156,62 +181,163 @@ public: // Public variables (need to create accessors instead)
|
|||
// Get the actual D3Q19 communication counts (based on location of solid phase)
|
||||
// Discrete velocity set symmetry implies the sendcount = recvcount
|
||||
//......................................................................................
|
||||
inline int recvCount( const char* dir ) const { return getRecvList( dir ).size(); }
|
||||
inline int sendCount( const char* dir ) const { return getSendList( dir ).size(); }
|
||||
inline const int* recvList( const char* dir ) const { return getRecvList( dir ).data(); }
|
||||
inline const int* sendList( const char* dir ) const { return getSendList( dir ).data(); }
|
||||
inline int recvCount(const char *dir) const {
|
||||
return getRecvList(dir).size();
|
||||
}
|
||||
inline int sendCount(const char *dir) const {
|
||||
return getSendList(dir).size();
|
||||
}
|
||||
inline const int *recvList(const char *dir) const {
|
||||
return getRecvList(dir).data();
|
||||
}
|
||||
inline const int *sendList(const char *dir) const {
|
||||
return getSendList(dir).data();
|
||||
}
|
||||
|
||||
//......................................................................................
|
||||
//......................................................................................
|
||||
// Solid indicator function
|
||||
std::vector<signed char> id;
|
||||
|
||||
/**
|
||||
* \brief Read domain IDs from file
|
||||
*/
|
||||
void ReadIDs();
|
||||
|
||||
/**
|
||||
* \brief Compute the porosity
|
||||
*/
|
||||
void ComputePorosity();
|
||||
void Decomp( const std::string& filename );
|
||||
|
||||
/**
|
||||
* \brief Read image and perform domain decomposition
|
||||
* @param filename - name of file to read IDs
|
||||
*/
|
||||
void Decomp(const std::string &filename);
|
||||
|
||||
/**
|
||||
* \brief Perform a halo exchange using MPI
|
||||
* @param Mesh - array data that holds scalar values
|
||||
*/
|
||||
void CommunicateMeshHalo(DoubleArray &Mesh);
|
||||
void CommInit();
|
||||
|
||||
/**
|
||||
* \brief Initialize communication data structures within Domain object.
|
||||
* This routine needs to be called before the communication functionality will work
|
||||
*/
|
||||
void CommInit();
|
||||
|
||||
/**
|
||||
* \brief Count number of pore nodes (labels > 1)
|
||||
*/
|
||||
int PoreCount();
|
||||
|
||||
void ReadFromFile(const std::string& Filename,const std::string& Datatype, double *UserData);
|
||||
void AggregateLabels( const std::string& filename );
|
||||
void AggregateLabels( const std::string& filename, DoubleArray &UserData );
|
||||
|
||||
/**
|
||||
* \brief Read array data from a file and distribute to local arrays for each MPI process
|
||||
* @param Filename - name of the file to read the data
|
||||
* @param Datatype - data type to use
|
||||
* @param UserData - Array to store the values that are read
|
||||
*/
|
||||
void ReadFromFile(const std::string &Filename, const std::string &Datatype,
|
||||
double *UserData);
|
||||
|
||||
/**
|
||||
* \brief Aggregate labels from all MPI processes and write to a file
|
||||
* @param filename - name of the file to write
|
||||
*/
|
||||
void AggregateLabels(const std::string &filename);
|
||||
/**
|
||||
* \brief Aggregate user provided array from all MPI processes and write to a single file
|
||||
* @param filename - name of the file to write
|
||||
* @param UserData - array data to aggregate and write
|
||||
*/
|
||||
void AggregateLabels(const std::string &filename, DoubleArray &UserData);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* \brief Pack halo data for 8-bit integer
|
||||
* @param list - list of values in the halo
|
||||
* @param count - count of values in the halo
|
||||
* @param sendbuf - memory buffer to use to pack values for MPI
|
||||
* @param ID - 8-bit values on mesh [Nx, Ny, Nz]
|
||||
*/
|
||||
void PackID(int *list, int count, signed char *sendbuf, signed char *ID);
|
||||
void UnpackID(int *list, int count, signed char *recvbuf, signed char *ID);
|
||||
void CommHaloIDs();
|
||||
|
||||
//......................................................................................
|
||||
MPI_Request req1[18], req2[18];
|
||||
//......................................................................................
|
||||
std::vector<int> sendList_x, sendList_y, sendList_z, sendList_X, sendList_Y, sendList_Z;
|
||||
std::vector<int> sendList_xy, sendList_yz, sendList_xz, sendList_Xy, sendList_Yz, sendList_xZ;
|
||||
std::vector<int> sendList_xY, sendList_yZ, sendList_Xz, sendList_XY, sendList_YZ, sendList_XZ;
|
||||
//......................................................................................
|
||||
std::vector<int> recvList_x, recvList_y, recvList_z, recvList_X, recvList_Y, recvList_Z;
|
||||
std::vector<int> recvList_xy, recvList_yz, recvList_xz, recvList_Xy, recvList_Yz, recvList_xZ;
|
||||
std::vector<int> recvList_xY, recvList_yZ, recvList_Xz, recvList_XY, recvList_YZ, recvList_XZ;
|
||||
//......................................................................................
|
||||
const std::vector<int>& getRecvList( const char* dir ) const;
|
||||
const std::vector<int>& getSendList( const char* dir ) const;
|
||||
|
||||
/**
|
||||
* \brief Unpack halo data for 8-bit integer
|
||||
* @param list - list of values in the halo
|
||||
* @param count - count of values in the halo
|
||||
* @param recvbuf - memory buffer containing values recieved by MPI
|
||||
* @param ID - 8-bit values on mesh [Nx, Ny, Nz]
|
||||
*/
|
||||
void UnpackID(int *list, int count, signed char *recvbuf, signed char *ID);
|
||||
|
||||
//......................................................................................
|
||||
MPI_Request req1[18], req2[18];
|
||||
//......................................................................................
|
||||
std::vector<int> sendList_x, sendList_y, sendList_z, sendList_X, sendList_Y,
|
||||
sendList_Z;
|
||||
std::vector<int> sendList_xy, sendList_yz, sendList_xz, sendList_Xy,
|
||||
sendList_Yz, sendList_xZ;
|
||||
std::vector<int> sendList_xY, sendList_yZ, sendList_Xz, sendList_XY,
|
||||
sendList_YZ, sendList_XZ;
|
||||
//......................................................................................
|
||||
std::vector<int> recvList_x, recvList_y, recvList_z, recvList_X, recvList_Y,
|
||||
recvList_Z;
|
||||
std::vector<int> recvList_xy, recvList_yz, recvList_xz, recvList_Xy,
|
||||
recvList_Yz, recvList_xZ;
|
||||
std::vector<int> recvList_xY, recvList_yZ, recvList_Xz, recvList_XY,
|
||||
recvList_YZ, recvList_XZ;
|
||||
//......................................................................................
|
||||
const std::vector<int> &getRecvList(const char *dir) const;
|
||||
const std::vector<int> &getSendList(const char *dir) const;
|
||||
};
|
||||
|
||||
template <class TYPE> class PatchData;
|
||||
|
||||
enum class DataLocation { CPU, DEVICE };
|
||||
|
||||
/**
|
||||
* \class Patch
|
||||
*
|
||||
* @details
|
||||
* store patch data
|
||||
*/
|
||||
class Patch {
|
||||
public:
|
||||
//! Empty constructor
|
||||
Patch() = delete;
|
||||
|
||||
//! Copy constructor
|
||||
Patch(const Patch &) = delete;
|
||||
|
||||
//! Assignment operator
|
||||
Patch &operator=(const Patch &) = delete;
|
||||
|
||||
//! Return the box for the patch
|
||||
inline const Box &getBox() const { return d_box; }
|
||||
|
||||
//! Create patch data
|
||||
template <class TYPE>
|
||||
std::shared_ptr<PatchData<TYPE>>
|
||||
createPatchData(DataLocation location) const;
|
||||
|
||||
private:
|
||||
Box d_box;
|
||||
int d_owner;
|
||||
Domain *d_domain;
|
||||
};
|
||||
|
||||
// Class to hold data on a patch
|
||||
template<class TYPE>
|
||||
class PatchData {
|
||||
template <class TYPE> class PatchData {
|
||||
public:
|
||||
//! Get the raw data pointer
|
||||
TYPE *data() { return d_data; }
|
||||
|
||||
//! Get the raw data pointer
|
||||
TYPE* data() { return d_data; }
|
||||
|
||||
//! Get the raw data pointer
|
||||
const TYPE* data() const { return d_data; }
|
||||
const TYPE *data() const { return d_data; }
|
||||
|
||||
//! Get the patch
|
||||
const Patch& getPatch() const { return *d_patch; }
|
||||
const Patch &getPatch() const { return *d_patch; }
|
||||
|
||||
//! Start communication
|
||||
void beginCommunication();
|
||||
|
@ -220,20 +346,20 @@ public:
|
|||
void endCommunication();
|
||||
|
||||
//! Access ghost values
|
||||
TYPE operator()( int, int, int ) const;
|
||||
TYPE operator()(int, int, int) const;
|
||||
|
||||
//! Copy data from another PatchData
|
||||
void copy( const PatchData& rhs );
|
||||
void copy(const PatchData &rhs);
|
||||
|
||||
private:
|
||||
DataLocation d_location;
|
||||
const Patch *d_patch;
|
||||
TYPE *d_data;
|
||||
TYPE *d_gcw;
|
||||
|
||||
};
|
||||
|
||||
void WriteCheckpoint(const char *FILENAME, const double *cDen, const double *cfq, size_t Np);
|
||||
void WriteCheckpoint(const char *FILENAME, const double *cDen,
|
||||
const double *cfq, size_t Np);
|
||||
|
||||
void ReadCheckpoint(char *FILENAME, double *cDen, double *cfq, size_t Np);
|
||||
|
||||
|
|
127
common/FunctionTable.cpp
Normal file
127
common/FunctionTable.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
#include "FunctionTable.hpp"
|
||||
|
||||
/********************************************************
|
||||
* Random number generation *
|
||||
********************************************************/
|
||||
/*template<> char genRand<char>()
|
||||
{
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen( rd() );
|
||||
static std::uniform_int_distribution<char> dis;
|
||||
return dis( gen );
|
||||
}
|
||||
template<> int8_t genRand<int8_t>()
|
||||
{
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen( rd() );
|
||||
static std::uniform_int_distribution<int8_t> dis;
|
||||
return dis( gen );
|
||||
}
|
||||
template<> uint8_t genRand<uint8_t>()
|
||||
{
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen( rd() );
|
||||
static std::uniform_int_distribution<uint8_t> dis;
|
||||
return dis( gen );
|
||||
}
|
||||
template<> int16_t genRand<int16_t>()
|
||||
{
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen( rd() );
|
||||
static std::uniform_int_distribution<int16_t> dis;
|
||||
return dis( gen );
|
||||
}
|
||||
template<> uint16_t genRand<uint16_t>()
|
||||
{
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen( rd() );
|
||||
static std::uniform_int_distribution<uint16_t> dis;
|
||||
return dis( gen );
|
||||
}
|
||||
template<> int32_t genRand<int32_t>()
|
||||
{
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen( rd() );
|
||||
static std::uniform_int_distribution<int32_t> dis;
|
||||
return dis( gen );
|
||||
}
|
||||
template<> uint32_t genRand<uint32_t>()
|
||||
{
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen( rd() );
|
||||
static std::uniform_int_distribution<uint32_t> dis;
|
||||
return dis( gen );
|
||||
}
|
||||
template<> int64_t genRand<int64_t>()
|
||||
{
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen( rd() );
|
||||
static std::uniform_int_distribution<int64_t> dis;
|
||||
return dis( gen );
|
||||
}
|
||||
template<> uint64_t genRand<uint64_t>()
|
||||
{
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen( rd() );
|
||||
static std::uniform_int_distribution<uint64_t> dis;
|
||||
return dis( gen );
|
||||
}
|
||||
template<> float genRand<float>()
|
||||
{
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen( rd() );
|
||||
static std::uniform_real_distribution<float> dis;
|
||||
return dis( gen );
|
||||
}
|
||||
template<> double genRand<double>()
|
||||
{
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen( rd() );
|
||||
static std::uniform_real_distribution<double> dis;
|
||||
return dis( gen );
|
||||
}
|
||||
template<> long double genRand<long double>()
|
||||
{
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen( rd() );
|
||||
static std::uniform_real_distribution<double> dis;
|
||||
return dis( gen );
|
||||
}
|
||||
*/
|
||||
|
||||
/********************************************************
|
||||
* axpy *
|
||||
********************************************************/
|
||||
template <>
|
||||
void call_axpy<float>(size_t N, const float alpha, const float *x, float *y) {
|
||||
ERROR("Not finished");
|
||||
}
|
||||
template <>
|
||||
void call_axpy<double>(size_t N, const double alpha, const double *x,
|
||||
double *y) {
|
||||
ERROR("Not finished");
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
* Multiply two arrays *
|
||||
********************************************************/
|
||||
template <>
|
||||
void call_gemv<double>(size_t M, size_t N, double alpha, double beta,
|
||||
const double *A, const double *x, double *y) {
|
||||
ERROR("Not finished");
|
||||
}
|
||||
template <>
|
||||
void call_gemv<float>(size_t M, size_t N, float alpha, float beta,
|
||||
const float *A, const float *x, float *y) {
|
||||
ERROR("Not finished");
|
||||
}
|
||||
template <>
|
||||
void call_gemm<double>(size_t M, size_t N, size_t K, double alpha, double beta,
|
||||
const double *A, const double *B, double *C) {
|
||||
ERROR("Not finished");
|
||||
}
|
||||
template <>
|
||||
void call_gemm<float>(size_t M, size_t N, size_t K, float alpha, float beta,
|
||||
const float *A, const float *B, float *C) {
|
||||
ERROR("Not finished");
|
||||
}
|
|
@ -1,62 +1,91 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef included_FunctionTable
|
||||
#define included_FunctionTable
|
||||
|
||||
|
||||
#include "common/ArraySize.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
|
||||
/*!
|
||||
* Class FunctionTable is a serial function table class that defines
|
||||
* a series of operations that can be performed on the Array class.
|
||||
* Users can impliment additional versions of the function table that match
|
||||
* the interface to change the behavior of the array class.
|
||||
*/
|
||||
class FunctionTable final
|
||||
{
|
||||
class FunctionTable final {
|
||||
public:
|
||||
/*!
|
||||
* Initialize the array with random values
|
||||
* @param[in] x The array to operate on
|
||||
*/
|
||||
template<class TYPE, class FUN>
|
||||
static void rand( Array<TYPE, FUN> &x );
|
||||
template <class TYPE, class FUN> static void rand(Array<TYPE, FUN> &x);
|
||||
|
||||
/*!
|
||||
* Perform a reduce operator y = f(x)
|
||||
* @param[in] op The function operation
|
||||
* Note: the operator is a template parameter
|
||||
* (compared to a std::function to improve performance)
|
||||
* @param[in] A The array to operate on
|
||||
* @return The reduction
|
||||
* @param[in] op The function operation
|
||||
* Note: the operator is a template parameter to improve performance
|
||||
* @param[in] A The array to operate on
|
||||
* @param[in] initialValue The initial value for the reduction (0 for sum, +/- inf for min/max,
|
||||
* ...)
|
||||
* @return The reduction
|
||||
*/
|
||||
template<class TYPE, class FUN, typename LAMBDA>
|
||||
static inline TYPE reduce( LAMBDA &op, const Array<TYPE, FUN> &A );
|
||||
template <class TYPE, class FUN, typename LAMBDA>
|
||||
static inline TYPE reduce(LAMBDA &op, const Array<TYPE, FUN> &A,
|
||||
const TYPE &initialValue);
|
||||
|
||||
/*!
|
||||
* Perform a reduce operator z = f(x,y)
|
||||
* @param[in] op The function operation
|
||||
* Note: the operator is a template parameter to improve performance
|
||||
* @param[in] A The first array to operate on
|
||||
* @param[in] B The second array to operate on
|
||||
* @param[in] initialValue The initial value for the reduction (0 for sum, +/- inf for min/max,
|
||||
* ...)
|
||||
* @return The reduction
|
||||
*/
|
||||
template <class TYPE, class FUN, typename LAMBDA>
|
||||
static inline TYPE reduce(LAMBDA &op, const Array<TYPE, FUN> &A,
|
||||
const Array<TYPE, FUN> &B,
|
||||
const TYPE &initialValue);
|
||||
|
||||
/*!
|
||||
* Perform a element-wise operation y = f(x)
|
||||
* @param[in] fun The function operation
|
||||
* Note: the operator is a template parameter
|
||||
* (compared to a std::function to improve performance)
|
||||
* @param[in] x The input array to operate on
|
||||
* @param[out] y The output array
|
||||
* @param[in] fun The function operation
|
||||
* Note: the function is a template parameter to improve performance
|
||||
* @param[in,out] x The array to operate on
|
||||
* @param[out] y The output array
|
||||
*/
|
||||
template<class TYPE, class FUN, typename LAMBDA>
|
||||
static inline void transform( LAMBDA &fun, const Array<TYPE, FUN> &x, Array<TYPE, FUN> &y );
|
||||
template <class TYPE, class FUN, typename LAMBDA>
|
||||
static inline void transform(LAMBDA &fun, const Array<TYPE, FUN> &x,
|
||||
Array<TYPE, FUN> &y);
|
||||
|
||||
/*!
|
||||
* Perform a element-wise operation z = f(x,y)
|
||||
* @param[in] fun The function operation
|
||||
* Note: the operator is a template parameter
|
||||
* (compared to a std::function to improve performance)
|
||||
* @param[in] x The first array
|
||||
* @param[in] y The second array
|
||||
* @param[out] z The result
|
||||
* @param[in] fun The function operation
|
||||
* Note: the function is a template parameter to improve performance
|
||||
* @param[in] x The first array
|
||||
* @param[in] y The second array
|
||||
* @param[out] z The output array
|
||||
*/
|
||||
template<class TYPE, class FUN, typename LAMBDA>
|
||||
static inline void transform(
|
||||
LAMBDA &fun, const Array<TYPE, FUN> &x, const Array<TYPE, FUN> &y, Array<TYPE, FUN> &z );
|
||||
template <class TYPE, class FUN, typename LAMBDA>
|
||||
static inline void transform(LAMBDA &fun, const Array<TYPE, FUN> &x,
|
||||
const Array<TYPE, FUN> &y,
|
||||
Array<TYPE, FUN> &z);
|
||||
|
||||
/*!
|
||||
* Multiply two arrays
|
||||
|
@ -64,9 +93,9 @@ public:
|
|||
* @param[in] b The second array
|
||||
* @param[out] c The output array
|
||||
*/
|
||||
template<class TYPE, class FUN>
|
||||
static inline void multiply(
|
||||
const Array<TYPE, FUN> &a, const Array<TYPE, FUN> &b, Array<TYPE, FUN> &c );
|
||||
template <class TYPE, class FUN>
|
||||
static void multiply(const Array<TYPE, FUN> &a, const Array<TYPE, FUN> &b,
|
||||
Array<TYPE, FUN> &c);
|
||||
|
||||
/*!
|
||||
* Perform dgemv/dgemm equavalent operation ( C = alpha*A*B + beta*C )
|
||||
|
@ -74,11 +103,12 @@ public:
|
|||
* @param[in] A The first array
|
||||
* @param[in] B The second array
|
||||
* @param[in] beta The scalar value alpha
|
||||
* @param[in,out] c The output array C
|
||||
* @param[in,out] C The output array C
|
||||
*/
|
||||
template<class TYPE, class FUN>
|
||||
static void gemm( const TYPE alpha, const Array<TYPE, FUN> &A, const Array<TYPE, FUN> &B,
|
||||
const TYPE beta, Array<TYPE, FUN> &C );
|
||||
template <class TYPE, class FUN>
|
||||
static void gemm(const TYPE alpha, const Array<TYPE, FUN> &A,
|
||||
const Array<TYPE, FUN> &B, const TYPE beta,
|
||||
Array<TYPE, FUN> &C);
|
||||
|
||||
/*!
|
||||
* Perform axpy equavalent operation ( y = alpha*x + y )
|
||||
|
@ -86,8 +116,9 @@ public:
|
|||
* @param[in] x The input array x
|
||||
* @param[in,out] y The output array y
|
||||
*/
|
||||
template<class TYPE, class FUN>
|
||||
static void axpy( const TYPE alpha, const Array<TYPE, FUN> &x, Array<TYPE, FUN> &y );
|
||||
template <class TYPE, class FUN>
|
||||
static void axpy(const TYPE alpha, const Array<TYPE, FUN> &x,
|
||||
Array<TYPE, FUN> &y);
|
||||
|
||||
/*!
|
||||
* Check if two arrays are approximately equal
|
||||
|
@ -95,13 +126,83 @@ public:
|
|||
* @param[in] B The second array
|
||||
* @param[in] tol The tolerance
|
||||
*/
|
||||
template<class TYPE, class FUN>
|
||||
static bool equals( const Array<TYPE, FUN> &A, const Array<TYPE, FUN> &B, TYPE tol );
|
||||
template <class TYPE, class FUN>
|
||||
static bool equals(const Array<TYPE, FUN> &A, const Array<TYPE, FUN> &B,
|
||||
TYPE tol);
|
||||
|
||||
template <class TYPE>
|
||||
static inline void gemmWrapper(char TRANSA, char TRANSB, int M, int N,
|
||||
int K, TYPE alpha, const TYPE *A, int LDA,
|
||||
const TYPE *B, int LDB, TYPE beta, TYPE *C,
|
||||
int LDC);
|
||||
|
||||
/* Specialized Functions */
|
||||
|
||||
/*!
|
||||
* Perform a element-wise operation y = max(x , 0)
|
||||
* @param[in] A The input array
|
||||
* @param[out] B The output array
|
||||
*/
|
||||
template <class TYPE, class FUN, class ALLOC>
|
||||
static void transformReLU(const Array<TYPE, FUN, ALLOC> &A,
|
||||
Array<TYPE, FUN, ALLOC> &B);
|
||||
|
||||
/*!
|
||||
* Perform a element-wise operation B = |A|
|
||||
* @param[in] A The array to operate on
|
||||
* @param[out] B The output array
|
||||
*/
|
||||
template <class TYPE, class FUN, class ALLOC>
|
||||
static void transformAbs(const Array<TYPE, FUN, ALLOC> &A,
|
||||
Array<TYPE, FUN, ALLOC> &B);
|
||||
|
||||
/*!
|
||||
* Perform a element-wise operation B = tanh(A)
|
||||
* @param[in] A The array to operate on
|
||||
* @param[out] B The output array
|
||||
*/
|
||||
template <class TYPE, class FUN, class ALLOC>
|
||||
static void transformTanh(const Array<TYPE, FUN, ALLOC> &A,
|
||||
Array<TYPE, FUN, ALLOC> &B);
|
||||
|
||||
/*!
|
||||
* Perform a element-wise operation B = max(-1 , min(1 , A) )
|
||||
* @param[in] A The array to operate on
|
||||
* @param[out] B The output array
|
||||
*/
|
||||
template <class TYPE, class FUN, class ALLOC>
|
||||
static void transformHardTanh(const Array<TYPE, FUN, ALLOC> &A,
|
||||
Array<TYPE, FUN, ALLOC> &B);
|
||||
|
||||
/*!
|
||||
* Perform a element-wise operation B = 1 / (1 + exp(-A))
|
||||
* @param[in] A The array to operate on
|
||||
* @param[out] B The output array
|
||||
*/
|
||||
template <class TYPE, class FUN, class ALLOC>
|
||||
static void transformSigmoid(const Array<TYPE, FUN, ALLOC> &A,
|
||||
Array<TYPE, FUN, ALLOC> &B);
|
||||
|
||||
/*!
|
||||
* Perform a element-wise operation B = log(exp(A) + 1)
|
||||
* @param[in] A The array to operate on
|
||||
* @param[out] B The output array
|
||||
*/
|
||||
template <class TYPE, class FUN, class ALLOC>
|
||||
static void transformSoftPlus(const Array<TYPE, FUN, ALLOC> &A,
|
||||
Array<TYPE, FUN, ALLOC> &B);
|
||||
|
||||
/*!
|
||||
* Sum the elements of the Array
|
||||
* @param[in] A The array to sum
|
||||
*/
|
||||
template <class TYPE, class FUN, class ALLOC>
|
||||
static TYPE sum(const Array<TYPE, FUN, ALLOC> &A);
|
||||
|
||||
private:
|
||||
FunctionTable();
|
||||
|
||||
template <class T> static inline void rand(size_t N, T *x);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,237 +1,307 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef included_FunctionTable_hpp
|
||||
#define included_FunctionTable_hpp
|
||||
|
||||
#include "common/FunctionTable.h"
|
||||
#include "common/Utilities.h"
|
||||
#include "common/UtilityMacros.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <random>
|
||||
|
||||
//#include <random>
|
||||
|
||||
/********************************************************
|
||||
* Random number initialization *
|
||||
********************************************************/
|
||||
template<class TYPE>
|
||||
static inline typename std::enable_if<std::is_integral<TYPE>::value>::type genRand(
|
||||
size_t N, TYPE* x )
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 gen( rd() );
|
||||
std::uniform_int_distribution<TYPE> dis;
|
||||
for ( size_t i = 0; i < N; i++ )
|
||||
x[i] = dis( gen );
|
||||
}
|
||||
template<class TYPE>
|
||||
static inline typename std::enable_if<std::is_floating_point<TYPE>::value>::type genRand(
|
||||
size_t N, TYPE* x )
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 gen( rd() );
|
||||
std::uniform_real_distribution<TYPE> dis( 0, 1 );
|
||||
for ( size_t i = 0; i < N; i++ )
|
||||
x[i] = dis( gen );
|
||||
}
|
||||
/*template<class TYPE> TYPE genRand();
|
||||
template<class TYPE, class FUN>
|
||||
inline void FunctionTable::rand( Array<TYPE, FUN>& x )
|
||||
inline void FunctionTable::rand( Array<TYPE, FUN> &x )
|
||||
{
|
||||
genRand<TYPE>( x.length(), x.data() );
|
||||
for ( size_t i = 0; i < x.length(); i++ )
|
||||
x( i ) = genRand<TYPE>();
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/********************************************************
|
||||
* Reduction *
|
||||
********************************************************/
|
||||
template<class TYPE, class FUN, typename LAMBDA>
|
||||
inline TYPE FunctionTable::reduce( LAMBDA& op, const Array<TYPE, FUN>& A )
|
||||
{
|
||||
if ( A.length() == 0 )
|
||||
template <class TYPE, class FUN, typename LAMBDA>
|
||||
inline TYPE FunctionTable::reduce(LAMBDA &op, const Array<TYPE, FUN> &A,
|
||||
const TYPE &initialValue) {
|
||||
if (A.length() == 0)
|
||||
return TYPE();
|
||||
const TYPE* x = A.data();
|
||||
TYPE y = x[0];
|
||||
const size_t N = A.length();
|
||||
for ( size_t i = 1; i < N; i++ )
|
||||
y = op( x[i], y );
|
||||
const TYPE *x = A.data();
|
||||
TYPE y = initialValue;
|
||||
for (size_t i = 0; i < A.length(); i++)
|
||||
y = op(x[i], y);
|
||||
return y;
|
||||
}
|
||||
|
||||
template <class TYPE, class FUN, typename LAMBDA>
|
||||
inline TYPE FunctionTable::reduce(LAMBDA &op, const Array<TYPE, FUN> &A,
|
||||
const Array<TYPE, FUN> &B,
|
||||
const TYPE &initialValue) {
|
||||
ARRAY_ASSERT(A.length() == B.length());
|
||||
if (A.length() == 0)
|
||||
return TYPE();
|
||||
const TYPE *x = A.data();
|
||||
const TYPE *y = B.data();
|
||||
TYPE z = initialValue;
|
||||
for (size_t i = 0; i < A.length(); i++)
|
||||
z = op(x[i], y[i], z);
|
||||
return z;
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
* Unary transformation *
|
||||
********************************************************/
|
||||
template<class TYPE, class FUN, typename LAMBDA>
|
||||
inline void FunctionTable::transform( LAMBDA& fun, const Array<TYPE, FUN>& x, Array<TYPE, FUN>& y )
|
||||
{
|
||||
y.resize( x.size() );
|
||||
template <class TYPE, class FUN, typename LAMBDA>
|
||||
inline void FunctionTable::transform(LAMBDA &fun, const Array<TYPE, FUN> &x,
|
||||
Array<TYPE, FUN> &y) {
|
||||
y.resize(x.size());
|
||||
const size_t N = x.length();
|
||||
for ( size_t i = 0; i < N; i++ )
|
||||
y( i ) = fun( x( i ) );
|
||||
for (size_t i = 0; i < N; i++)
|
||||
y(i) = fun(x(i));
|
||||
}
|
||||
template<class TYPE, class FUN, typename LAMBDA>
|
||||
inline void FunctionTable::transform(
|
||||
LAMBDA& fun, const Array<TYPE, FUN>& x, const Array<TYPE, FUN>& y, Array<TYPE, FUN>& z )
|
||||
{
|
||||
if ( x.size() != y.size() )
|
||||
throw std::logic_error( "Sizes of x and y do not match" );
|
||||
z.resize( x.size() );
|
||||
template <class TYPE, class FUN, typename LAMBDA>
|
||||
inline void FunctionTable::transform(LAMBDA &fun, const Array<TYPE, FUN> &x,
|
||||
const Array<TYPE, FUN> &y,
|
||||
Array<TYPE, FUN> &z) {
|
||||
if (x.size() != y.size())
|
||||
throw std::logic_error("Sizes of x and y do not match");
|
||||
z.resize(x.size());
|
||||
const size_t N = x.length();
|
||||
for ( size_t i = 0; i < N; i++ )
|
||||
z( i ) = fun( x( i ), y( i ) );
|
||||
for (size_t i = 0; i < N; i++)
|
||||
z(i) = fun(x(i), y(i));
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* axpy *
|
||||
********************************************************/
|
||||
template<class TYPE>
|
||||
inline void call_axpy( size_t N, const TYPE alpha, const TYPE* x, TYPE* y );
|
||||
template<>
|
||||
inline void call_axpy<float>( size_t, const float, const float*, float* )
|
||||
{
|
||||
throw std::logic_error( "LapackWrappers not configured" );
|
||||
}
|
||||
template<>
|
||||
inline void call_axpy<double>( size_t, const double, const double*, double* )
|
||||
{
|
||||
throw std::logic_error( "LapackWrappers not configured" );
|
||||
}
|
||||
template<class TYPE>
|
||||
inline void call_axpy( size_t N, const TYPE alpha, const TYPE* x, TYPE* y )
|
||||
{
|
||||
for ( size_t i = 0; i < N; i++ )
|
||||
template <class TYPE>
|
||||
void call_axpy(size_t N, const TYPE alpha, const TYPE *x, TYPE *y);
|
||||
template <>
|
||||
void call_axpy<float>(size_t N, const float alpha, const float *x, float *y);
|
||||
template <>
|
||||
void call_axpy<double>(size_t N, const double alpha, const double *x,
|
||||
double *y);
|
||||
template <class TYPE>
|
||||
void call_axpy(size_t N, const TYPE alpha, const TYPE *x, TYPE *y) {
|
||||
for (size_t i = 0; i < N; i++)
|
||||
y[i] += alpha * x[i];
|
||||
}
|
||||
template<class TYPE, class FUN>
|
||||
void FunctionTable::axpy( const TYPE alpha, const Array<TYPE, FUN>& x, Array<TYPE, FUN>& y )
|
||||
{
|
||||
if ( x.size() != y.size() )
|
||||
throw std::logic_error( "Array sizes do not match" );
|
||||
call_axpy( x.length(), alpha, x.data(), y.data() );
|
||||
template <class TYPE, class FUN>
|
||||
void FunctionTable::axpy(const TYPE alpha, const Array<TYPE, FUN> &x,
|
||||
Array<TYPE, FUN> &y) {
|
||||
if (x.size() != y.size())
|
||||
throw std::logic_error("Array sizes do not match");
|
||||
call_axpy(x.length(), alpha, x.data(), y.data());
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* Multiply two arrays *
|
||||
********************************************************/
|
||||
template<class TYPE>
|
||||
inline void call_gemv( size_t M, size_t N, TYPE alpha, TYPE beta, const TYPE* A, const TYPE* x, TYPE* y );
|
||||
template<>
|
||||
inline void call_gemv<double>(
|
||||
size_t, size_t, double, double, const double*, const double*, double* )
|
||||
{
|
||||
throw std::logic_error( "LapackWrappers not configured" );
|
||||
}
|
||||
template<>
|
||||
inline void call_gemv<float>( size_t, size_t, float, float, const float*, const float*, float* )
|
||||
{
|
||||
throw std::logic_error( "LapackWrappers not configured" );
|
||||
}
|
||||
template<class TYPE>
|
||||
inline void call_gemv(
|
||||
size_t M, size_t N, TYPE alpha, TYPE beta, const TYPE* A, const TYPE* x, TYPE* y )
|
||||
{
|
||||
for ( size_t i = 0; i < M; i++ )
|
||||
template <class TYPE>
|
||||
void call_gemv(size_t M, size_t N, TYPE alpha, TYPE beta, const TYPE *A,
|
||||
const TYPE *x, TYPE *y);
|
||||
template <>
|
||||
void call_gemv<double>(size_t M, size_t N, double alpha, double beta,
|
||||
const double *A, const double *x, double *y);
|
||||
template <>
|
||||
void call_gemv<float>(size_t M, size_t N, float alpha, float beta,
|
||||
const float *A, const float *x, float *y);
|
||||
template <class TYPE>
|
||||
void call_gemv(size_t M, size_t N, TYPE alpha, TYPE beta, const TYPE *A,
|
||||
const TYPE *x, TYPE *y) {
|
||||
for (size_t i = 0; i < M; i++)
|
||||
y[i] = beta * y[i];
|
||||
for ( size_t j = 0; j < N; j++ ) {
|
||||
for ( size_t i = 0; i < M; i++ )
|
||||
for (size_t j = 0; j < N; j++) {
|
||||
for (size_t i = 0; i < M; i++)
|
||||
y[i] += alpha * A[i + j * M] * x[j];
|
||||
}
|
||||
}
|
||||
template<class TYPE>
|
||||
inline void call_gemm(
|
||||
size_t M, size_t N, size_t K, TYPE alpha, TYPE beta, const TYPE* A, const TYPE* B, TYPE* C );
|
||||
template<>
|
||||
inline void call_gemm<double>( size_t, size_t, size_t, double, double, const double*, const double*, double* )
|
||||
{
|
||||
throw std::logic_error( "LapackWrappers not configured" );
|
||||
}
|
||||
template<>
|
||||
inline void call_gemm<float>( size_t, size_t, size_t, float, float, const float*, const float*, float* )
|
||||
{
|
||||
throw std::logic_error( "LapackWrappers not configured" );
|
||||
}
|
||||
template<class TYPE>
|
||||
inline void call_gemm(
|
||||
size_t M, size_t N, size_t K, TYPE alpha, TYPE beta, const TYPE* A, const TYPE* B, TYPE* C )
|
||||
{
|
||||
for ( size_t i = 0; i < K * M; i++ )
|
||||
template <class TYPE>
|
||||
void call_gemm(size_t M, size_t N, size_t K, TYPE alpha, TYPE beta,
|
||||
const TYPE *A, const TYPE *B, TYPE *C);
|
||||
template <>
|
||||
void call_gemm<double>(size_t M, size_t N, size_t K, double alpha, double beta,
|
||||
const double *A, const double *B, double *C);
|
||||
template <>
|
||||
void call_gemm<float>(size_t M, size_t N, size_t K, float alpha, float beta,
|
||||
const float *A, const float *B, float *C);
|
||||
template <class TYPE>
|
||||
void call_gemm(size_t M, size_t N, size_t K, TYPE alpha, TYPE beta,
|
||||
const TYPE *A, const TYPE *B, TYPE *C) {
|
||||
for (size_t i = 0; i < K * M; i++)
|
||||
C[i] = beta * C[i];
|
||||
for ( size_t k = 0; k < K; k++ ) {
|
||||
for ( size_t j = 0; j < N; j++ ) {
|
||||
for ( size_t i = 0; i < M; i++ )
|
||||
for (size_t k = 0; k < K; k++) {
|
||||
for (size_t j = 0; j < N; j++) {
|
||||
for (size_t i = 0; i < M; i++)
|
||||
C[i + k * M] += alpha * A[i + j * M] * B[j + k * N];
|
||||
}
|
||||
}
|
||||
}
|
||||
template<class TYPE, class FUN>
|
||||
void FunctionTable::gemm( const TYPE alpha, const Array<TYPE, FUN>& a, const Array<TYPE, FUN>& b,
|
||||
const TYPE beta, Array<TYPE, FUN>& c )
|
||||
{
|
||||
if ( a.ndim() == 2 && b.ndim() == 1 ) {
|
||||
if ( a.size( 1 ) != b.size( 0 ) )
|
||||
throw std::logic_error( "Inner dimensions must match" );
|
||||
call_gemv<TYPE>( a.size( 0 ), a.size( 1 ), alpha, beta, a.data(), b.data(), c.data() );
|
||||
} else if ( a.ndim() <= 2 && b.ndim() <= 2 ) {
|
||||
if ( a.size( 1 ) != b.size( 0 ) )
|
||||
throw std::logic_error( "Inner dimensions must match" );
|
||||
call_gemm<TYPE>(
|
||||
a.size( 0 ), a.size( 1 ), b.size( 1 ), alpha, beta, a.data(), b.data(), c.data() );
|
||||
template <class TYPE, class FUN>
|
||||
void FunctionTable::gemm(const TYPE alpha, const Array<TYPE, FUN> &a,
|
||||
const Array<TYPE, FUN> &b, const TYPE beta,
|
||||
Array<TYPE, FUN> &c) {
|
||||
if (a.size(1) != b.size(0))
|
||||
throw std::logic_error("Inner dimensions must match");
|
||||
if (a.ndim() == 2 && b.ndim() == 1) {
|
||||
call_gemv<TYPE>(a.size(0), a.size(1), alpha, beta, a.data(), b.data(),
|
||||
c.data());
|
||||
} else if (a.ndim() <= 2 && b.ndim() <= 2) {
|
||||
call_gemm<TYPE>(a.size(0), a.size(1), b.size(1), alpha, beta, a.data(),
|
||||
b.data(), c.data());
|
||||
} else {
|
||||
throw std::logic_error( "Not finished yet" );
|
||||
throw std::logic_error("Not finished yet");
|
||||
}
|
||||
}
|
||||
template<class TYPE, class FUN>
|
||||
void FunctionTable::multiply(
|
||||
const Array<TYPE, FUN>& a, const Array<TYPE, FUN>& b, Array<TYPE, FUN>& c )
|
||||
{
|
||||
if ( a.ndim() == 2 && b.ndim() == 1 ) {
|
||||
if ( a.size( 1 ) != b.size( 0 ) )
|
||||
throw std::logic_error( "Inner dimensions must match" );
|
||||
c.resize( a.size( 0 ) );
|
||||
call_gemv<TYPE>( a.size( 0 ), a.size( 1 ), 1, 0, a.data(), b.data(), c.data() );
|
||||
} else if ( a.ndim() <= 2 && b.ndim() <= 2 ) {
|
||||
if ( a.size( 1 ) != b.size( 0 ) )
|
||||
throw std::logic_error( "Inner dimensions must match" );
|
||||
c.resize( a.size( 0 ), b.size( 1 ) );
|
||||
call_gemm<TYPE>(
|
||||
a.size( 0 ), a.size( 1 ), b.size( 1 ), 1, 0, a.data(), b.data(), c.data() );
|
||||
template <class TYPE, class FUN>
|
||||
void FunctionTable::multiply(const Array<TYPE, FUN> &a,
|
||||
const Array<TYPE, FUN> &b, Array<TYPE, FUN> &c) {
|
||||
if (a.size(1) != b.size(0))
|
||||
throw std::logic_error("Inner dimensions must match");
|
||||
if (a.ndim() == 2 && b.ndim() == 1) {
|
||||
c.resize(a.size(0));
|
||||
call_gemv<TYPE>(a.size(0), a.size(1), 1, 0, a.data(), b.data(),
|
||||
c.data());
|
||||
} else if (a.ndim() <= 2 && b.ndim() <= 2) {
|
||||
c.resize(a.size(0), b.size(1));
|
||||
call_gemm<TYPE>(a.size(0), a.size(1), b.size(1), 1, 0, a.data(),
|
||||
b.data(), c.data());
|
||||
} else {
|
||||
throw std::logic_error( "Not finished yet" );
|
||||
throw std::logic_error("Not finished yet");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************
|
||||
* Check if two arrays are equal *
|
||||
********************************************************/
|
||||
template<class TYPE, class FUN>
|
||||
inline typename std::enable_if<!std::is_floating_point<TYPE>::value, bool>::type
|
||||
FunctionTableCompare( const Array<TYPE, FUN>& a, const Array<TYPE, FUN>& b, TYPE )
|
||||
{
|
||||
template <class TYPE, class FUN>
|
||||
inline typename std::enable_if<std::is_integral<TYPE>::value, bool>::type
|
||||
FunctionTableCompare(const Array<TYPE, FUN> &a, const Array<TYPE, FUN> &b,
|
||||
TYPE) {
|
||||
bool pass = true;
|
||||
if ( a.size() != b.size() )
|
||||
throw std::logic_error( "Sizes of x and y do not match" );
|
||||
for ( size_t i = 0; i < a.length(); i++ )
|
||||
pass = pass && a( i ) == b( i );
|
||||
if (a.size() != b.size())
|
||||
throw std::logic_error("Sizes of x and y do not match");
|
||||
for (size_t i = 0; i < a.length(); i++)
|
||||
pass = pass && a(i) == b(i);
|
||||
return pass;
|
||||
}
|
||||
template<class TYPE, class FUN>
|
||||
template <class TYPE, class FUN>
|
||||
inline typename std::enable_if<std::is_floating_point<TYPE>::value, bool>::type
|
||||
FunctionTableCompare( const Array<TYPE, FUN>& a, const Array<TYPE, FUN>& b, TYPE tol )
|
||||
{
|
||||
FunctionTableCompare(const Array<TYPE, FUN> &a, const Array<TYPE, FUN> &b,
|
||||
TYPE tol) {
|
||||
bool pass = true;
|
||||
if ( a.size() != b.size() )
|
||||
throw std::logic_error( "Sizes of x and y do not match" );
|
||||
for ( size_t i = 0; i < a.length(); i++ )
|
||||
pass = pass && ( std::abs( a( i ) - b( i ) ) < tol );
|
||||
if (a.size() != b.size())
|
||||
throw std::logic_error("Sizes of x and y do not match");
|
||||
for (size_t i = 0; i < a.length(); i++)
|
||||
pass = pass && (std::abs(a(i) - b(i)) < tol);
|
||||
return pass;
|
||||
}
|
||||
template<class TYPE, class FUN>
|
||||
bool FunctionTable::equals( const Array<TYPE, FUN>& a, const Array<TYPE, FUN>& b, TYPE tol )
|
||||
{
|
||||
return FunctionTableCompare( a, b, tol );
|
||||
template <class TYPE, class FUN>
|
||||
bool FunctionTable::equals(const Array<TYPE, FUN> &a, const Array<TYPE, FUN> &b,
|
||||
TYPE tol) {
|
||||
return FunctionTableCompare(a, b, tol);
|
||||
}
|
||||
|
||||
/********************************************************
|
||||
* Specialized Functions *
|
||||
********************************************************/
|
||||
template <class TYPE, class FUN, class ALLOC>
|
||||
void FunctionTable::transformReLU(const Array<TYPE, FUN, ALLOC> &A,
|
||||
Array<TYPE, FUN, ALLOC> &B) {
|
||||
const auto &fun = [](const TYPE &a) {
|
||||
return std::max(a, static_cast<TYPE>(0));
|
||||
};
|
||||
transform(fun, A, B);
|
||||
}
|
||||
|
||||
template <class TYPE, class FUN, class ALLOC>
|
||||
void FunctionTable::transformAbs(const Array<TYPE, FUN, ALLOC> &A,
|
||||
Array<TYPE, FUN, ALLOC> &B) {
|
||||
B.resize(A.size());
|
||||
const auto &fun = [](const TYPE &a) { return std::abs(a); };
|
||||
transform(fun, A, B);
|
||||
}
|
||||
template <class TYPE, class FUN, class ALLOC>
|
||||
void FunctionTable::transformTanh(const Array<TYPE, FUN, ALLOC> &A,
|
||||
Array<TYPE, FUN, ALLOC> &B) {
|
||||
B.resize(A.size());
|
||||
const auto &fun = [](const TYPE &a) { return tanh(a); };
|
||||
transform(fun, A, B);
|
||||
}
|
||||
|
||||
template <class TYPE, class FUN, class ALLOC>
|
||||
void FunctionTable::transformHardTanh(const Array<TYPE, FUN, ALLOC> &A,
|
||||
Array<TYPE, FUN, ALLOC> &B) {
|
||||
B.resize(A.size());
|
||||
const auto &fun = [](const TYPE &a) {
|
||||
return std::max(-static_cast<TYPE>(1.0),
|
||||
std::min(static_cast<TYPE>(1.0), a));
|
||||
};
|
||||
transform(fun, A, B);
|
||||
}
|
||||
|
||||
template <class TYPE, class FUN, class ALLOC>
|
||||
void FunctionTable::transformSigmoid(const Array<TYPE, FUN, ALLOC> &A,
|
||||
Array<TYPE, FUN, ALLOC> &B) {
|
||||
B.resize(A.size());
|
||||
const auto &fun = [](const TYPE &a) { return 1.0 / (1.0 + exp(-a)); };
|
||||
transform(fun, A, B);
|
||||
}
|
||||
|
||||
template <class TYPE, class FUN, class ALLOC>
|
||||
void FunctionTable::transformSoftPlus(const Array<TYPE, FUN, ALLOC> &A,
|
||||
Array<TYPE, FUN, ALLOC> &B) {
|
||||
B.resize(A.size());
|
||||
const auto &fun = [](const TYPE &a) { return log1p(exp(a)); };
|
||||
transform(fun, A, B);
|
||||
}
|
||||
|
||||
template <class TYPE, class FUN, class ALLOC>
|
||||
TYPE FunctionTable::sum(const Array<TYPE, FUN, ALLOC> &A) {
|
||||
const auto &fun = [](const TYPE &a, const TYPE &b) { return a + b; };
|
||||
return reduce(fun, A, (TYPE)0);
|
||||
}
|
||||
|
||||
template <class TYPE>
|
||||
inline void FunctionTable::gemmWrapper(char TRANSA, char TRANSB, int M, int N,
|
||||
int K, TYPE alpha, const TYPE *A,
|
||||
int LDA, const TYPE *B, int LDB,
|
||||
TYPE beta, TYPE *C, int LDC) {
|
||||
ERROR("Not finished");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
4058
common/MPI.cpp
4058
common/MPI.cpp
File diff suppressed because it is too large
Load Diff
359
common/MPI.h
359
common/MPI.h
|
@ -22,7 +22,6 @@ redistribution is prohibited.
|
|||
#ifndef included_LBPM_MPI
|
||||
#define included_LBPM_MPI
|
||||
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <complex>
|
||||
|
@ -31,7 +30,6 @@ redistribution is prohibited.
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
// Include mpi.h (or define MPI objects)
|
||||
// clang-format off
|
||||
#ifdef USE_MPI
|
||||
|
@ -48,10 +46,8 @@ redistribution is prohibited.
|
|||
#endif
|
||||
// clang-format on
|
||||
|
||||
|
||||
namespace Utilities {
|
||||
|
||||
|
||||
/**
|
||||
* \class MPI
|
||||
*
|
||||
|
@ -69,8 +65,7 @@ namespace Utilities {
|
|||
* succeed provided that the size of the data type object is a fixed size on
|
||||
* all processors. sizeof(type) must be the same for all elements and processors.
|
||||
*/
|
||||
class MPI final
|
||||
{
|
||||
class MPI final {
|
||||
public:
|
||||
enum class ThreadSupport : int { SINGLE, FUNNELED, SERIALIZED, MULTIPLE };
|
||||
|
||||
|
@ -87,11 +82,9 @@ public: // Constructors
|
|||
*/
|
||||
MPI();
|
||||
|
||||
|
||||
//! Empty destructor
|
||||
~MPI();
|
||||
|
||||
|
||||
/**
|
||||
* \brief Constructor from existing MPI communicator
|
||||
* \details This constructor creates a new communicator from an existing MPI communicator.
|
||||
|
@ -104,8 +97,7 @@ public: // Constructors
|
|||
* \param manage Do we want to manage the comm (free the MPI_Comm when this object leaves
|
||||
* scope)
|
||||
*/
|
||||
MPI( MPI_Comm comm, bool manage = false );
|
||||
|
||||
MPI(MPI_Comm comm, bool manage = false);
|
||||
|
||||
/**
|
||||
* \brief Constructor from existing communicator
|
||||
|
@ -113,30 +105,26 @@ public: // Constructors
|
|||
* This does not create a new internal MPI_Comm, but uses the existing comm.
|
||||
* \param comm Existing communicator
|
||||
*/
|
||||
MPI( const MPI &comm );
|
||||
|
||||
MPI(const MPI &comm);
|
||||
|
||||
/*!
|
||||
* Move constructor
|
||||
* @param rhs Communicator to copy
|
||||
*/
|
||||
MPI( MPI &&rhs );
|
||||
|
||||
MPI(MPI &&rhs);
|
||||
|
||||
/**
|
||||
* \brief Assignment operator
|
||||
* \details This operator overloads the assignment to correctly copy an communicator
|
||||
* \param comm Existing MPI object
|
||||
*/
|
||||
MPI &operator=( const MPI &comm );
|
||||
|
||||
MPI &operator=(const MPI &comm);
|
||||
|
||||
/*!
|
||||
* Move assignment operator
|
||||
* @param rhs Communicator to copy
|
||||
*/
|
||||
MPI &operator=( MPI &&rhs );
|
||||
|
||||
MPI &operator=(MPI &&rhs);
|
||||
|
||||
/**
|
||||
* \brief Reset the object
|
||||
|
@ -144,7 +132,6 @@ public: // Constructors
|
|||
*/
|
||||
void reset();
|
||||
|
||||
|
||||
public: // Member functions
|
||||
/**
|
||||
* \brief Get the node name
|
||||
|
@ -153,18 +140,14 @@ public: // Member functions
|
|||
*/
|
||||
static std::string getNodeName();
|
||||
|
||||
|
||||
//! Function to return the number of processors available
|
||||
static int getNumberOfProcessors();
|
||||
|
||||
|
||||
//! Function to return the affinity of the current process
|
||||
static std::vector<int> getProcessAffinity();
|
||||
|
||||
|
||||
//! Function to set the affinity of the current process
|
||||
static void setProcessAffinity( const std::vector<int> &procs );
|
||||
|
||||
static void setProcessAffinity(const std::vector<int> &procs);
|
||||
|
||||
/**
|
||||
* \brief Load balance the processes within a node
|
||||
|
@ -189,22 +172,21 @@ public: // Member functions
|
|||
* processors).
|
||||
*
|
||||
*/
|
||||
static void balanceProcesses( const MPI &comm = MPI( MPI_COMM_WORLD ), const int method = 1,
|
||||
const std::vector<int> &procs = std::vector<int>(), const int N_min = 1,
|
||||
const int N_max = -1 );
|
||||
|
||||
static void
|
||||
balanceProcesses(const MPI &comm = MPI(MPI_COMM_WORLD),
|
||||
const int method = 1,
|
||||
const std::vector<int> &procs = std::vector<int>(),
|
||||
const int N_min = 1, const int N_max = -1);
|
||||
|
||||
//! Query the level of thread support
|
||||
static ThreadSupport queryThreadSupport();
|
||||
|
||||
|
||||
/**
|
||||
* \brief Generate a random number
|
||||
* \details This generates a random number that is consistent across the comm
|
||||
*/
|
||||
size_t rand() const;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Split an existing communicator
|
||||
* \details This creates a new communicator by splitting an existing communicator.
|
||||
|
@ -222,8 +204,7 @@ public: // Member functions
|
|||
* have the relative rank order as they did in their parent group. (See
|
||||
* MPI_Comm_split)
|
||||
*/
|
||||
MPI split( int color, int key = -1 ) const;
|
||||
|
||||
MPI split(int color, int key = -1) const;
|
||||
|
||||
/**
|
||||
* \brief Split an existing communicator by node
|
||||
|
@ -240,8 +221,7 @@ public: // Member functions
|
|||
* have the relative rank order as they did in their parent group. (See
|
||||
* MPI_Comm_split)
|
||||
*/
|
||||
MPI splitByNode( int key = -1 ) const;
|
||||
|
||||
MPI splitByNode(int key = -1) const;
|
||||
|
||||
/**
|
||||
* \brief Duplicate an existing communicator
|
||||
|
@ -253,7 +233,6 @@ public: // Member functions
|
|||
*/
|
||||
MPI dup() const;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Create a communicator from the intersection of two communicators
|
||||
* \details This creates a new communicator by intersecting two existing communicators.
|
||||
|
@ -265,15 +244,13 @@ public: // Member functions
|
|||
* The communicators partially overlap. This will require communication on the first
|
||||
* communicator.
|
||||
*/
|
||||
static MPI intersect( const MPI &comm1, const MPI &comm2 );
|
||||
|
||||
static MPI intersect(const MPI &comm1, const MPI &comm2);
|
||||
|
||||
/**
|
||||
* Check if the current communicator is NULL
|
||||
*/
|
||||
bool isNull() const { return d_isNull; }
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return the global ranks for the comm
|
||||
* \details This returns a vector which contains the global ranks for each
|
||||
|
@ -283,7 +260,6 @@ public: // Member functions
|
|||
*/
|
||||
std::vector<int> globalRanks() const;
|
||||
|
||||
|
||||
/**
|
||||
* Get the current MPI communicator.
|
||||
* Note: The underlying MPI_Comm object may be free'd by the object when it is no
|
||||
|
@ -294,15 +270,13 @@ public: // Member functions
|
|||
*/
|
||||
const MPI_Comm &getCommunicator() const { return communicator; }
|
||||
|
||||
|
||||
/**
|
||||
* \brief Overload operator ==
|
||||
* \details Overload operator comm1 == comm2. Two MPI objects are == if they share the same
|
||||
* communicator.
|
||||
* Note: this is a local operation.
|
||||
*/
|
||||
bool operator==( const MPI & ) const;
|
||||
|
||||
bool operator==(const MPI &) const;
|
||||
|
||||
/**
|
||||
* \brief Overload operator !=
|
||||
|
@ -310,8 +284,7 @@ public: // Member functions
|
|||
* do not share the same communicator.
|
||||
* Note: this is a local operation.
|
||||
*/
|
||||
bool operator!=( const MPI & ) const;
|
||||
|
||||
bool operator!=(const MPI &) const;
|
||||
|
||||
/**
|
||||
* \brief Overload operator <
|
||||
|
@ -324,8 +297,7 @@ public: // Member functions
|
|||
* Additionally, all processors on the first object MUST call this routine and will be
|
||||
* synchronized through this call (there is an internalallReduce).
|
||||
*/
|
||||
bool operator<( const MPI & ) const;
|
||||
|
||||
bool operator<(const MPI &) const;
|
||||
|
||||
/**
|
||||
* \brief Overload operator <=
|
||||
|
@ -337,8 +309,7 @@ public: // Member functions
|
|||
* call this routine and will be synchronized through this call (there is an internal
|
||||
* allReduce).
|
||||
*/
|
||||
bool operator<=( const MPI & ) const;
|
||||
|
||||
bool operator<=(const MPI &) const;
|
||||
|
||||
/**
|
||||
* \brief Overload operator >
|
||||
|
@ -351,8 +322,7 @@ public: // Member functions
|
|||
* Additionally, all processors on the first object MUST call this routine and will be
|
||||
* synchronized through this call (there is an internal allReduce).
|
||||
*/
|
||||
bool operator>( const MPI & ) const;
|
||||
|
||||
bool operator>(const MPI &) const;
|
||||
|
||||
/**
|
||||
* \brief Overload operator >=
|
||||
|
@ -365,8 +335,7 @@ public: // Member functions
|
|||
* Additionally, all processors on the first object MUST call this routine and will be
|
||||
* synchronized through this call (there is an internal allReduce).
|
||||
*/
|
||||
bool operator>=( const MPI & ) const;
|
||||
|
||||
bool operator>=(const MPI &) const;
|
||||
|
||||
/**
|
||||
* \brief Compare to another communicator
|
||||
|
@ -376,8 +345,7 @@ public: // Member functions
|
|||
* 4 if different contexts but similar groups, and 0 otherwise.
|
||||
* Note: this is a local operation.
|
||||
*/
|
||||
int compare( const MPI & ) const;
|
||||
|
||||
int compare(const MPI &) const;
|
||||
|
||||
/**
|
||||
* Return the processor rank (identifier) from 0 through the number of
|
||||
|
@ -385,19 +353,16 @@ public: // Member functions
|
|||
*/
|
||||
int getRank() const { return comm_rank; }
|
||||
|
||||
|
||||
/**
|
||||
* Return the number of processors.
|
||||
*/
|
||||
int getSize() const { return comm_size; }
|
||||
|
||||
|
||||
/**
|
||||
* Return the maximum tag
|
||||
*/
|
||||
int maxTag() const { return d_maxTag; }
|
||||
|
||||
|
||||
/**
|
||||
* \brief Return a new tag
|
||||
* \details This routine will return an unused tag for communication.
|
||||
|
@ -406,7 +371,6 @@ public: // Member functions
|
|||
*/
|
||||
int newTag();
|
||||
|
||||
|
||||
/**
|
||||
* Call MPI_Abort or exit depending on whether running with one or more
|
||||
* processes and value set by function above, if called. The default is
|
||||
|
@ -416,15 +380,13 @@ public: // Member functions
|
|||
*/
|
||||
void abort() const;
|
||||
|
||||
|
||||
/**
|
||||
* Set boolean flag indicating whether exit or abort is called when running
|
||||
* with one processor. Calling this function influences the behavior of
|
||||
* calls to abort(). By default, the flag is true meaning that
|
||||
* abort() will be called. Passing false means exit(-1) will be called.
|
||||
*/
|
||||
void setCallAbortInSerialInsteadOfExit( bool flag = true );
|
||||
|
||||
void setCallAbortInSerialInsteadOfExit(bool flag = true);
|
||||
|
||||
/**
|
||||
* \brief Boolean all reduce
|
||||
|
@ -432,8 +394,7 @@ public: // Member functions
|
|||
* It returns true iff all processor are true;
|
||||
* \param value The input value for the all reduce
|
||||
*/
|
||||
bool allReduce( const bool value ) const;
|
||||
|
||||
bool allReduce(const bool value) const;
|
||||
|
||||
/**
|
||||
* \brief Boolean any reduce
|
||||
|
@ -441,8 +402,7 @@ public: // Member functions
|
|||
* It returns true if any processor is true;
|
||||
* \param value The input value for the all reduce
|
||||
*/
|
||||
bool anyReduce( const bool value ) const;
|
||||
|
||||
bool anyReduce(const bool value) const;
|
||||
|
||||
/**
|
||||
* \brief Sum Reduce
|
||||
|
@ -450,9 +410,7 @@ public: // Member functions
|
|||
* It returns the sum across all processors;
|
||||
* \param value The input value for the all reduce
|
||||
*/
|
||||
template<class type>
|
||||
type sumReduce( const type value ) const;
|
||||
|
||||
template <class type> type sumReduce(const type value) const;
|
||||
|
||||
/**
|
||||
* \brief Sum Reduce
|
||||
|
@ -462,9 +420,7 @@ public: // Member functions
|
|||
* \param x The input/output array for the reduce
|
||||
* \param n The number of values in the array (must match on all nodes)
|
||||
*/
|
||||
template<class type>
|
||||
void sumReduce( type *x, const int n = 1 ) const;
|
||||
|
||||
template <class type> void sumReduce(type *x, const int n = 1) const;
|
||||
|
||||
/**
|
||||
* \brief Sum Reduce
|
||||
|
@ -475,9 +431,8 @@ public: // Member functions
|
|||
* \param y The output array for the reduce
|
||||
* \param n The number of values in the array (must match on all nodes)
|
||||
*/
|
||||
template<class type>
|
||||
void sumReduce( const type *x, type *y, const int n = 1 ) const;
|
||||
|
||||
template <class type>
|
||||
void sumReduce(const type *x, type *y, const int n = 1) const;
|
||||
|
||||
/**
|
||||
* \brief Min Reduce
|
||||
|
@ -485,9 +440,7 @@ public: // Member functions
|
|||
* It returns the minimum value across all processors;
|
||||
* \param value The input value for the all reduce
|
||||
*/
|
||||
template<class type>
|
||||
type minReduce( const type value ) const;
|
||||
|
||||
template <class type> type minReduce(const type value) const;
|
||||
|
||||
/**
|
||||
* \brief Sum Reduce
|
||||
|
@ -503,9 +456,8 @@ public: // Member functions
|
|||
* \param rank_of_min Optional array indicating the rank of the processor containing the
|
||||
* minimum value
|
||||
*/
|
||||
template<class type>
|
||||
void minReduce( type *x, const int n = 1, int *rank_of_min = nullptr ) const;
|
||||
|
||||
template <class type>
|
||||
void minReduce(type *x, const int n = 1, int *rank_of_min = nullptr) const;
|
||||
|
||||
/**
|
||||
* \brief Sum Reduce
|
||||
|
@ -522,9 +474,9 @@ public: // Member functions
|
|||
* \param rank_of_min Optional array indicating the rank of the processor containing the
|
||||
* minimum value
|
||||
*/
|
||||
template<class type>
|
||||
void minReduce( const type *x, type *y, const int n = 1, int *rank_of_min = nullptr ) const;
|
||||
|
||||
template <class type>
|
||||
void minReduce(const type *x, type *y, const int n = 1,
|
||||
int *rank_of_min = nullptr) const;
|
||||
|
||||
/**
|
||||
* \brief Max Reduce
|
||||
|
@ -532,9 +484,7 @@ public: // Member functions
|
|||
* It returns the maximum value across all processors;
|
||||
* \param value The input value for the all reduce
|
||||
*/
|
||||
template<class type>
|
||||
type maxReduce( const type value ) const;
|
||||
|
||||
template <class type> type maxReduce(const type value) const;
|
||||
|
||||
/**
|
||||
* \brief Sum Reduce
|
||||
|
@ -550,9 +500,8 @@ public: // Member functions
|
|||
* \param rank_of_max Optional array indicating the rank of the processor containing the
|
||||
* minimum value
|
||||
*/
|
||||
template<class type>
|
||||
void maxReduce( type *x, const int n = 1, int *rank_of_max = nullptr ) const;
|
||||
|
||||
template <class type>
|
||||
void maxReduce(type *x, const int n = 1, int *rank_of_max = nullptr) const;
|
||||
|
||||
/**
|
||||
* \brief Sum Reduce
|
||||
|
@ -569,9 +518,9 @@ public: // Member functions
|
|||
* \param rank_of_max Optional array indicating the rank of the processor containing the
|
||||
* minimum value
|
||||
*/
|
||||
template<class type>
|
||||
void maxReduce( const type *x, type *y, const int n = 1, int *rank_of_max = nullptr ) const;
|
||||
|
||||
template <class type>
|
||||
void maxReduce(const type *x, type *y, const int n = 1,
|
||||
int *rank_of_max = nullptr) const;
|
||||
|
||||
/**
|
||||
* \brief Scan Sum Reduce
|
||||
|
@ -581,9 +530,8 @@ public: // Member functions
|
|||
* \param y The output array for the scan
|
||||
* \param n The number of values in the array (must match on all nodes)
|
||||
*/
|
||||
template<class type>
|
||||
void sumScan( const type *x, type *y, const int n = 1 ) const;
|
||||
|
||||
template <class type>
|
||||
void sumScan(const type *x, type *y, const int n = 1) const;
|
||||
|
||||
/**
|
||||
* \brief Scan Min Reduce
|
||||
|
@ -593,9 +541,8 @@ public: // Member functions
|
|||
* \param y The output array for the scan
|
||||
* \param n The number of values in the array (must match on all nodes)
|
||||
*/
|
||||
template<class type>
|
||||
void minScan( const type *x, type *y, const int n = 1 ) const;
|
||||
|
||||
template <class type>
|
||||
void minScan(const type *x, type *y, const int n = 1) const;
|
||||
|
||||
/**
|
||||
* \brief Scan Max Reduce
|
||||
|
@ -605,9 +552,8 @@ public: // Member functions
|
|||
* \param y The output array for the scan
|
||||
* \param n The number of values in the array (must match on all nodes)
|
||||
*/
|
||||
template<class type>
|
||||
void maxScan( const type *x, type *y, const int n = 1 ) const;
|
||||
|
||||
template <class type>
|
||||
void maxScan(const type *x, type *y, const int n = 1) const;
|
||||
|
||||
/**
|
||||
* \brief Broadcast
|
||||
|
@ -615,9 +561,7 @@ public: // Member functions
|
|||
* \param value The input value for the broadcast.
|
||||
* \param root The processor performing the broadcast
|
||||
*/
|
||||
template<class type>
|
||||
type bcast( const type &value, const int root ) const;
|
||||
|
||||
template <class type> type bcast(const type &value, const int root) const;
|
||||
|
||||
/**
|
||||
* \brief Broadcast
|
||||
|
@ -626,16 +570,14 @@ public: // Member functions
|
|||
* \param n The number of values in the array (must match on all nodes)
|
||||
* \param root The processor performing the broadcast
|
||||
*/
|
||||
template<class type>
|
||||
void bcast( type *value, const int n, const int root ) const;
|
||||
|
||||
template <class type>
|
||||
void bcast(type *value, const int n, const int root) const;
|
||||
|
||||
/**
|
||||
* Perform a global barrier across all processors.
|
||||
*/
|
||||
void barrier() const;
|
||||
|
||||
|
||||
/*!
|
||||
* @brief This function sends an MPI message with an array to another processor.
|
||||
*
|
||||
|
@ -652,9 +594,9 @@ public: // Member functions
|
|||
* to be sent with this message. Default tag is 0.
|
||||
* The matching recv must share this tag.
|
||||
*/
|
||||
template<class type>
|
||||
void send( const type *buf, const int length, const int recv, int tag = 0 ) const;
|
||||
|
||||
template <class type>
|
||||
void send(const type *buf, const int length, const int recv,
|
||||
int tag = 0) const;
|
||||
|
||||
/*!
|
||||
* @brief This function sends an MPI message with an array of bytes
|
||||
|
@ -669,8 +611,8 @@ public: // Member functions
|
|||
* to be sent with this message. Default tag is 0.
|
||||
* The matching recv must share this tag.
|
||||
*/
|
||||
void sendBytes( const void *buf, const int N_bytes, const int recv, int tag = 0 ) const;
|
||||
|
||||
void sendBytes(const void *buf, const int N_bytes, const int recv,
|
||||
int tag = 0) const;
|
||||
|
||||
/*!
|
||||
* @brief This function sends an MPI message with an array
|
||||
|
@ -684,10 +626,9 @@ public: // Member functions
|
|||
* @param tag Integer argument specifying an integer tag
|
||||
* to be sent with this message.
|
||||
*/
|
||||
template<class type>
|
||||
MPI_Request Isend(
|
||||
const type *buf, const int length, const int recv_proc, const int tag ) const;
|
||||
|
||||
template <class type>
|
||||
MPI_Request Isend(const type *buf, const int length, const int recv_proc,
|
||||
const int tag) const;
|
||||
|
||||
/*!
|
||||
* @brief This function sends an MPI message with an array of bytes
|
||||
|
@ -701,9 +642,8 @@ public: // Member functions
|
|||
* @param tag Integer argument specifying an integer tag
|
||||
* to be sent with this message.
|
||||
*/
|
||||
MPI_Request IsendBytes(
|
||||
const void *buf, const int N_bytes, const int recv_proc, const int tag ) const;
|
||||
|
||||
MPI_Request IsendBytes(const void *buf, const int N_bytes,
|
||||
const int recv_proc, const int tag) const;
|
||||
|
||||
/*!
|
||||
* @brief This function receives an MPI message with a data
|
||||
|
@ -721,14 +661,12 @@ public: // Member functions
|
|||
* @param tag Optional integer argument specifying a tag which must be matched
|
||||
* by the tag of the incoming message. Default tag is 0.
|
||||
*/
|
||||
template<class type>
|
||||
inline void recv( type *buf, int length, const int send, int tag ) const
|
||||
{
|
||||
template <class type>
|
||||
inline void recv(type *buf, int length, const int send, int tag) const {
|
||||
int length2 = length;
|
||||
recv( buf, length2, send, false, tag );
|
||||
recv(buf, length2, send, false, tag);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* @brief This function receives an MPI message with a data
|
||||
* array from another processor.
|
||||
|
@ -748,9 +686,9 @@ public: // Member functions
|
|||
* @param tag Optional integer argument specifying a tag which must be matched
|
||||
* by the tag of the incoming message. Default tag is 0.
|
||||
*/
|
||||
template<class type>
|
||||
void recv( type *buf, int &length, const int send, const bool get_length, int tag ) const;
|
||||
|
||||
template <class type>
|
||||
void recv(type *buf, int &length, const int send, const bool get_length,
|
||||
int tag) const;
|
||||
|
||||
/*!
|
||||
* @brief This function receives an MPI message with an array of
|
||||
|
@ -765,8 +703,7 @@ public: // Member functions
|
|||
* must be matched by the tag of the incoming message. Default
|
||||
* tag is 0.
|
||||
*/
|
||||
void recvBytes( void *buf, int &N_bytes, const int send, int tag = 0 ) const;
|
||||
|
||||
void recvBytes(void *buf, int &N_bytes, const int send, int tag = 0) const;
|
||||
|
||||
/*!
|
||||
* @brief This function receives an MPI message with a data
|
||||
|
@ -778,9 +715,9 @@ public: // Member functions
|
|||
* @param tag Optional integer argument specifying a tag which must
|
||||
* be matched by the tag of the incoming message.
|
||||
*/
|
||||
template<class type>
|
||||
MPI_Request Irecv( type *buf, const int length, const int send_proc, const int tag ) const;
|
||||
|
||||
template <class type>
|
||||
MPI_Request Irecv(type *buf, const int length, const int send_proc,
|
||||
const int tag) const;
|
||||
|
||||
/*!
|
||||
* @brief This function receives an MPI message with an array of
|
||||
|
@ -794,35 +731,30 @@ public: // Member functions
|
|||
* @param tag Integer argument specifying a tag which must
|
||||
* be matched by the tag of the incoming message.
|
||||
*/
|
||||
MPI_Request IrecvBytes(
|
||||
void *buf, const int N_bytes, const int send_proc, const int tag ) const;
|
||||
|
||||
MPI_Request IrecvBytes(void *buf, const int N_bytes, const int send_proc,
|
||||
const int tag) const;
|
||||
|
||||
/*!
|
||||
* @brief This function sends and recieves data using a blocking call
|
||||
*/
|
||||
template<class type>
|
||||
void sendrecv( const type *sendbuf, int sendcount, int dest, int sendtag, type *recvbuf,
|
||||
int recvcount, int source, int recvtag ) const;
|
||||
|
||||
template <class type>
|
||||
void sendrecv(const type *sendbuf, int sendcount, int dest, int sendtag,
|
||||
type *recvbuf, int recvcount, int source, int recvtag) const;
|
||||
|
||||
/*!
|
||||
* Each processor sends every other processor a single value.
|
||||
* @param[in] x Input value for allGather
|
||||
* @return Output array for allGather
|
||||
*/
|
||||
template<class type>
|
||||
std::vector<type> allGather( const type &x ) const;
|
||||
|
||||
template <class type> std::vector<type> allGather(const type &x) const;
|
||||
|
||||
/*!
|
||||
* Each processor sends every other processor an array
|
||||
* @param[in] x Input array for allGather
|
||||
* @return Output array for allGather
|
||||
*/
|
||||
template<class type>
|
||||
std::vector<type> allGather( const std::vector<type> &x_in ) const;
|
||||
|
||||
template <class type>
|
||||
std::vector<type> allGather(const std::vector<type> &x) const;
|
||||
|
||||
/*!
|
||||
* Each processor sends every other processor a single value.
|
||||
|
@ -832,9 +764,7 @@ public: // Member functions
|
|||
* @param x_out Output array for allGather (must be preallocated to the size of the
|
||||
* communicator)
|
||||
*/
|
||||
template<class type>
|
||||
void allGather( const type &x_in, type *x_out ) const;
|
||||
|
||||
template <class type> void allGather(const type &x_in, type *x_out) const;
|
||||
|
||||
/*!
|
||||
* Each processor sends an array of data to all other processors.
|
||||
|
@ -861,27 +791,24 @@ public: // Member functions
|
|||
* internally
|
||||
* and the sizes and displacements will be returned (if desired).
|
||||
*/
|
||||
template<class type>
|
||||
int allGather( const type *send_data, const int send_cnt, type *recv_data,
|
||||
int *recv_cnt = nullptr, int *recv_disp = nullptr, bool known_recv = false ) const;
|
||||
|
||||
template <class type>
|
||||
int allGather(const type *send_data, const int send_cnt, type *recv_data,
|
||||
int *recv_cnt = nullptr, int *recv_disp = nullptr,
|
||||
bool known_recv = false) const;
|
||||
|
||||
/*!
|
||||
* This function combines sets from different processors to create a single master set
|
||||
* @param set Input/Output std::set for the gather.
|
||||
*/
|
||||
template<class type>
|
||||
void setGather( std::set<type> &set ) const;
|
||||
|
||||
template <class type> void setGather(std::set<type> &set) const;
|
||||
|
||||
/*!
|
||||
* This function combines std::maps from different processors to create a single master std::map
|
||||
* If two or more ranks share the same key, the lowest rank will be used
|
||||
* @param map Input/Output std::map for the gather.
|
||||
*/
|
||||
template<class KEY, class DATA>
|
||||
void mapGather( std::map<KEY, DATA> &map ) const;
|
||||
|
||||
template <class KEY, class DATA>
|
||||
void mapGather(std::map<KEY, DATA> &map) const;
|
||||
|
||||
/*!
|
||||
* Each processor sends an array of n values to each processor.
|
||||
|
@ -894,9 +821,8 @@ public: // Member functions
|
|||
* @param send_data Input array (nxN)
|
||||
* @param recv_data Output array of received values (nxN)
|
||||
*/
|
||||
template<class type>
|
||||
void allToAll( const int n, const type *send_data, type *recv_data ) const;
|
||||
|
||||
template <class type>
|
||||
void allToAll(const int n, const type *send_data, type *recv_data) const;
|
||||
|
||||
/*!
|
||||
* Each processor sends an array of data to the different processors.
|
||||
|
@ -926,11 +852,11 @@ public: // Member functions
|
|||
* internally
|
||||
* and the sizes and displacements will be returned (if desired).
|
||||
*/
|
||||
template<class type>
|
||||
int allToAll( const type *send_data, const int send_cnt[], const int send_disp[],
|
||||
type *recv_data, int *recv_cnt = nullptr, int *recv_disp = nullptr,
|
||||
bool known_recv = false ) const;
|
||||
|
||||
template <class type>
|
||||
int allToAll(const type *send_data, const int send_cnt[],
|
||||
const int send_disp[], type *recv_data,
|
||||
int *recv_cnt = nullptr, int *recv_disp = nullptr,
|
||||
bool known_recv = false) const;
|
||||
|
||||
/*!
|
||||
* \brief Send a list of proccesor ids to communicate
|
||||
|
@ -942,8 +868,7 @@ public: // Member functions
|
|||
* \param ranks List of ranks that the current rank wants to communicate with
|
||||
* \return List of ranks that want to communicate with the current processor
|
||||
*/
|
||||
std::vector<int> commRanks( const std::vector<int> &ranks ) const;
|
||||
|
||||
std::vector<int> commRanks(const std::vector<int> &ranks) const;
|
||||
|
||||
/*!
|
||||
* \brief Wait for a communication to finish
|
||||
|
@ -951,8 +876,7 @@ public: // Member functions
|
|||
* Note: this does not require a communicator.
|
||||
* \param request Communication request to wait for (returned for Isend or Irecv)
|
||||
*/
|
||||
static void wait( MPI_Request request );
|
||||
|
||||
static void wait(MPI_Request request);
|
||||
|
||||
/*!
|
||||
* \brief Wait for any communication to finish.
|
||||
|
@ -962,8 +886,7 @@ public: // Member functions
|
|||
* \param count Number of communications to check
|
||||
* \param request Array of communication requests to wait for (returned for Isend or Irecv)
|
||||
*/
|
||||
static int waitAny( int count, MPI_Request *request );
|
||||
|
||||
static int waitAny(int count, MPI_Request *request);
|
||||
|
||||
/*!
|
||||
* \brief Wait for all communications to finish.
|
||||
|
@ -972,8 +895,7 @@ public: // Member functions
|
|||
* \param count Number of communications to check
|
||||
* \param request Array of communication requests to wait for (returned for Isend or Irecv)
|
||||
*/
|
||||
static void waitAll( int count, MPI_Request *request );
|
||||
|
||||
static void waitAll(int count, MPI_Request *request);
|
||||
|
||||
/*!
|
||||
* \brief Wait for some communications to finish.
|
||||
|
@ -983,8 +905,7 @@ public: // Member functions
|
|||
* \param count Number of communications to check
|
||||
* \param request Array of communication requests to wait for (returned for Isend or Irecv)
|
||||
*/
|
||||
static std::vector<int> waitSome( int count, MPI_Request *request );
|
||||
|
||||
static std::vector<int> waitSome(int count, MPI_Request *request);
|
||||
|
||||
/*!
|
||||
* \brief Nonblocking test for a message
|
||||
|
@ -995,8 +916,7 @@ public: // Member functions
|
|||
* \param source source rank (-1: any source)
|
||||
* \param tag tag (-1: any tag)
|
||||
*/
|
||||
int Iprobe( int source = -1, int tag = -1 ) const;
|
||||
|
||||
int Iprobe(int source = -1, int tag = -1) const;
|
||||
|
||||
/*!
|
||||
* \brief Blocking test for a message
|
||||
|
@ -1006,8 +926,7 @@ public: // Member functions
|
|||
* \param source source rank (-1: any source)
|
||||
* \param tag tag (-1: any tag)
|
||||
*/
|
||||
int probe( int source = -1, int tag = -1 ) const;
|
||||
|
||||
int probe(int source = -1, int tag = -1) const;
|
||||
|
||||
/*!
|
||||
* \brief Start a serial region
|
||||
|
@ -1018,14 +937,12 @@ public: // Member functions
|
|||
*/
|
||||
void serializeStart();
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Stop a serial region
|
||||
* \details Stop a serial region. See serializeStart for more information.
|
||||
*/
|
||||
void serializeStop();
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Elapsed time
|
||||
* \details This function returns the elapsed time on the calling processor
|
||||
|
@ -1036,21 +953,18 @@ public: // Member functions
|
|||
*/
|
||||
static double time();
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Timer resolution
|
||||
* \details This function returns the timer resolution used by "time"
|
||||
*/
|
||||
static double tick();
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Change the level of the internal timers
|
||||
* \details This function changes the level of the timers used to profile MPI
|
||||
* \param level New level of the timers
|
||||
*/
|
||||
static void changeProfileLevel( int level ) { profile_level = level; }
|
||||
|
||||
static void changeProfileLevel(int level) { profile_level = level; }
|
||||
|
||||
//! Return the total number of MPI_Comm objects that have been created
|
||||
static size_t MPI_Comm_created() { return N_MPI_Comm_created; }
|
||||
|
@ -1068,51 +982,51 @@ public: // Member functions
|
|||
static bool MPI_Active();
|
||||
|
||||
//! Start MPI
|
||||
static void start_MPI( int argc_in, char *argv_in[], int profile_level = 0 );
|
||||
static void start_MPI(int argc_in, char *argv_in[], int profile_level = 0);
|
||||
|
||||
//! Stop MPI
|
||||
static void stop_MPI();
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Load balance
|
||||
* \details This function will return a new communicator in which the ranks match
|
||||
* the performance and the work load.
|
||||
*/
|
||||
MPI loadBalance( double localPerformance, std::vector<double> work );
|
||||
MPI loadBalance(double localPerformance, std::vector<double> work);
|
||||
|
||||
private: // Private helper functions for templated MPI operations;
|
||||
template<class type>
|
||||
void call_sumReduce( type *x, const int n = 1 ) const;
|
||||
template<class type>
|
||||
void call_sumReduce( const type *x, type *y, const int n = 1 ) const;
|
||||
template<class type>
|
||||
void call_minReduce( type *x, const int n = 1, int *rank_of_min = nullptr ) const;
|
||||
template<class type>
|
||||
void call_minReduce(
|
||||
const type *x, type *y, const int n = 1, int *rank_of_min = nullptr ) const;
|
||||
template<class type>
|
||||
void call_maxReduce( type *x, const int n = 1, int *rank_of_max = nullptr ) const;
|
||||
template<class type>
|
||||
void call_maxReduce(
|
||||
const type *x, type *y, const int n = 1, int *rank_of_max = nullptr ) const;
|
||||
template<class type>
|
||||
void call_bcast( type *x, const int n, const int root ) const;
|
||||
template<class type>
|
||||
void call_allGather( const type &x_in, type *x_out ) const;
|
||||
template<class type>
|
||||
void call_allGather(
|
||||
const type *x_in, int size_in, type *x_out, int *size_out, int *disp_out ) const;
|
||||
template<class type>
|
||||
void call_sumScan( const type *x, type *y, int n = 1 ) const;
|
||||
template<class type>
|
||||
void call_minScan( const type *x, type *y, int n = 1 ) const;
|
||||
template<class type>
|
||||
void call_maxScan( const type *x, type *y, int n = 1 ) const;
|
||||
template<class type>
|
||||
void call_allToAll( const type *send_data, const int send_cnt[], const int send_disp[],
|
||||
type *recv_data, const int *recv_cnt, const int *recv_disp ) const;
|
||||
|
||||
template <class type> void call_sumReduce(type *x, const int n = 1) const;
|
||||
template <class type>
|
||||
void call_sumReduce(const type *x, type *y, const int n = 1) const;
|
||||
template <class type>
|
||||
void call_minReduce(type *x, const int n = 1,
|
||||
int *rank_of_min = nullptr) const;
|
||||
template <class type>
|
||||
void call_minReduce(const type *x, type *y, const int n = 1,
|
||||
int *rank_of_min = nullptr) const;
|
||||
template <class type>
|
||||
void call_maxReduce(type *x, const int n = 1,
|
||||
int *rank_of_max = nullptr) const;
|
||||
template <class type>
|
||||
void call_maxReduce(const type *x, type *y, const int n = 1,
|
||||
int *rank_of_max = nullptr) const;
|
||||
template <class type>
|
||||
void call_bcast(type *x, const int n, const int root) const;
|
||||
template <class type>
|
||||
void call_allGather(const type &x_in, type *x_out) const;
|
||||
template <class type>
|
||||
void call_allGather(const type *x_in, int size_in, type *x_out,
|
||||
int *size_out, int *disp_out) const;
|
||||
template <class type>
|
||||
void call_sumScan(const type *x, type *y, int n = 1) const;
|
||||
template <class type>
|
||||
void call_minScan(const type *x, type *y, int n = 1) const;
|
||||
template <class type>
|
||||
void call_maxScan(const type *x, type *y, int n = 1) const;
|
||||
template <class type>
|
||||
void call_allToAll(const type *send_data, const int send_cnt[],
|
||||
const int send_disp[], type *recv_data,
|
||||
const int *recv_cnt, const int *recv_disp) const;
|
||||
|
||||
private: // data members
|
||||
// The internal MPI communicator
|
||||
|
@ -1157,14 +1071,11 @@ private: // data members
|
|||
static volatile unsigned int N_MPI_Comm_destroyed;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Utilities
|
||||
|
||||
|
||||
// Include the default instantiations
|
||||
// \cond HIDDEN_SYMBOLS
|
||||
#include "common/MPI.I"
|
||||
// \endcond
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,112 +5,108 @@
|
|||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
// Read a file into memory
|
||||
std::vector<char> readFile( const std::string& filename )
|
||||
{
|
||||
auto fid = fopen( filename.c_str(), "rb" );
|
||||
INSIST( fid, "File does not exist: " + filename );
|
||||
fseek( fid, 0, SEEK_END );
|
||||
std::vector<char> readFile(const std::string &filename) {
|
||||
auto fid = fopen(filename.c_str(), "rb");
|
||||
INSIST(fid, "File does not exist: " + filename);
|
||||
fseek(fid, 0, SEEK_END);
|
||||
size_t bytes = ftell(fid);
|
||||
fseek( fid, 0, SEEK_SET );
|
||||
std::vector<char> data( bytes );
|
||||
size_t bytes2 = fread( data.data(), 1, bytes, fid );
|
||||
ASSERT( bytes == bytes2 );
|
||||
fclose( fid );
|
||||
fseek(fid, 0, SEEK_SET);
|
||||
std::vector<char> data(bytes);
|
||||
size_t bytes2 = fread(data.data(), 1, bytes, fid);
|
||||
ASSERT(bytes == bytes2);
|
||||
fclose(fid);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
// Decompress a gzip buffer
|
||||
std::vector<char> gunzip( const std::vector<char>& in )
|
||||
{
|
||||
std::vector<char> gunzip(const std::vector<char> &in) {
|
||||
z_stream stream;
|
||||
std::vector<char> out( 1000000 );
|
||||
stream.next_in = (Bytef*) in.data();
|
||||
std::vector<char> out(1000000);
|
||||
stream.next_in = (Bytef *)in.data();
|
||||
stream.avail_in = in.size();
|
||||
stream.total_in = 0;
|
||||
stream.zalloc = Z_NULL;
|
||||
stream.zfree = Z_NULL;
|
||||
stream.opaque = Z_NULL;
|
||||
stream.next_out = (Bytef*) out.data();
|
||||
stream.next_out = (Bytef *)out.data();
|
||||
stream.avail_out = out.size();
|
||||
stream.total_out = 0;
|
||||
ASSERT( inflateInit2(&stream, 16+MAX_WBITS) == Z_OK );
|
||||
ASSERT(inflateInit2(&stream, 16 + MAX_WBITS) == Z_OK);
|
||||
bool finished = inflate(&stream, Z_SYNC_FLUSH) == Z_STREAM_END;
|
||||
while ( !finished && stream.msg == Z_NULL ) {
|
||||
out.resize( 2 * out.size() );
|
||||
stream.next_out = (Bytef*) &out[stream.total_out];
|
||||
while (!finished && stream.msg == Z_NULL) {
|
||||
out.resize(2 * out.size());
|
||||
stream.next_out = (Bytef *)&out[stream.total_out];
|
||||
stream.avail_out = out.size() - stream.total_out;
|
||||
finished = inflate(&stream, Z_SYNC_FLUSH) == Z_STREAM_END;
|
||||
}
|
||||
ASSERT( stream.msg == Z_NULL );
|
||||
out.resize( stream.total_out );
|
||||
ASSERT(stream.msg == Z_NULL);
|
||||
out.resize(stream.total_out);
|
||||
inflateEnd(&stream);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
// Read the compressed micro CT data
|
||||
Array<uint8_t> readMicroCT( const std::string& filename )
|
||||
{
|
||||
auto in = readFile( filename );
|
||||
auto out = gunzip( in );
|
||||
ASSERT( out.size() == 1024*1024*1024 );
|
||||
Array<uint8_t> data( 1024, 1024, 1024 );
|
||||
memcpy( data.data(), out.data(), data.length() );
|
||||
Array<uint8_t> readMicroCT(const std::string &filename) {
|
||||
auto in = readFile(filename);
|
||||
auto out = gunzip(in);
|
||||
ASSERT(out.size() == 1024 * 1024 * 1024);
|
||||
Array<uint8_t> data(1024, 1024, 1024);
|
||||
memcpy(data.data(), out.data(), data.length());
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
// Read the compressed micro CT data and distribute
|
||||
Array<uint8_t> readMicroCT( const Database& domain, const Utilities::MPI& comm )
|
||||
{
|
||||
Array<uint8_t> readMicroCT(const Database &domain, const Utilities::MPI &comm) {
|
||||
// Get the local problem info
|
||||
auto n = domain.getVector<int>( "n" );
|
||||
auto n = domain.getVector<int>("n");
|
||||
int rank = comm.getRank();
|
||||
auto nproc = domain.getVector<int>( "nproc" );
|
||||
RankInfoStruct rankInfo( rank, nproc[0], nproc[1], nproc[2] );
|
||||
|
||||
auto nproc = domain.getVector<int>("nproc");
|
||||
RankInfoStruct rankInfo(rank, nproc[0], nproc[1], nproc[2]);
|
||||
|
||||
// Determine the largest file number to get
|
||||
int Nfx = ( n[0] * rankInfo.nx + 1023 ) / 1024;
|
||||
int Nfy = ( n[1] * rankInfo.ny + 1023 ) / 1024;
|
||||
int Nfz = ( n[2] * rankInfo.nz + 1023 ) / 1024;
|
||||
int Nfx = (n[0] * rankInfo.nx + 1023) / 1024;
|
||||
int Nfy = (n[1] * rankInfo.ny + 1023) / 1024;
|
||||
int Nfz = (n[2] * rankInfo.nz + 1023) / 1024;
|
||||
|
||||
// Load one of the files if rank < largest file
|
||||
Array<uint8_t> data;
|
||||
RankInfoStruct srcRankInfo( rank, Nfx, Nfy, Nfz );
|
||||
if ( srcRankInfo.ix >= 0 ) {
|
||||
auto filename = domain.getScalar<std::string>( "Filename" );
|
||||
char tmp[100];
|
||||
if ( filename.find( "0x_0y_0z.gbd.gz" ) != std::string::npos ) {
|
||||
sprintf( tmp, "%ix_%iy_%iz.gbd.gz", srcRankInfo.ix, srcRankInfo.jy, srcRankInfo.kz );
|
||||
filename = filename.replace( filename.find( "0x_0y_0z.gbd.gz" ), 15, std::string( tmp ) );
|
||||
} else if ( filename.find( "x0_y0_z0.gbd.gz" ) != std::string::npos ) {
|
||||
sprintf( tmp, "x%i_y%i_z%i.gbd.gz", srcRankInfo.ix, srcRankInfo.jy, srcRankInfo.kz );
|
||||
filename = filename.replace( filename.find( "x0_y0_z0.gbd.gz" ), 15, std::string( tmp ) );
|
||||
} else {
|
||||
ERROR( "Invalid name for first file" );
|
||||
}
|
||||
data = readMicroCT( filename );
|
||||
RankInfoStruct srcRankInfo(rank, Nfx, Nfy, Nfz);
|
||||
if (srcRankInfo.ix >= 0) {
|
||||
auto filename = domain.getScalar<std::string>("Filename");
|
||||
char tmp[100];
|
||||
if (filename.find("0x_0y_0z.gbd.gz") != std::string::npos) {
|
||||
sprintf(tmp, "%ix_%iy_%iz.gbd.gz", srcRankInfo.ix, srcRankInfo.jy,
|
||||
srcRankInfo.kz);
|
||||
filename = filename.replace(filename.find("0x_0y_0z.gbd.gz"), 15,
|
||||
std::string(tmp));
|
||||
} else if (filename.find("x0_y0_z0.gbd.gz") != std::string::npos) {
|
||||
sprintf(tmp, "x%i_y%i_z%i.gbd.gz", srcRankInfo.ix, srcRankInfo.jy,
|
||||
srcRankInfo.kz);
|
||||
filename = filename.replace(filename.find("x0_y0_z0.gbd.gz"), 15,
|
||||
std::string(tmp));
|
||||
} else {
|
||||
ERROR("Invalid name for first file");
|
||||
}
|
||||
data = readMicroCT(filename);
|
||||
}
|
||||
|
||||
// Redistribute the data
|
||||
data = redistribute( srcRankInfo, data, rankInfo, { n[0], n[1], n[2] }, comm );
|
||||
data = redistribute(srcRankInfo, data, rankInfo, {n[0], n[1], n[2]}, comm);
|
||||
|
||||
// Relabel the data
|
||||
auto ReadValues = domain.getVector<int>( "ReadValues" );
|
||||
auto WriteValues = domain.getVector<int>( "WriteValues" );
|
||||
ASSERT( ReadValues.size() == WriteValues.size() );
|
||||
// Relabel the data
|
||||
auto ReadValues = domain.getVector<int>("ReadValues");
|
||||
auto WriteValues = domain.getVector<int>("WriteValues");
|
||||
ASSERT(ReadValues.size() == WriteValues.size());
|
||||
int readMaxValue = 0;
|
||||
for ( auto v : ReadValues )
|
||||
readMaxValue = std::max( data.max()+1, v );
|
||||
std::vector<int> map( readMaxValue + 1, -1 );
|
||||
for ( size_t i=0; i<ReadValues.size(); i++ )
|
||||
for (auto v : ReadValues)
|
||||
readMaxValue = std::max(data.max() + 1, v);
|
||||
std::vector<int> map(readMaxValue + 1, -1);
|
||||
for (size_t i = 0; i < ReadValues.size(); i++)
|
||||
map[ReadValues[i]] = WriteValues[i];
|
||||
for ( size_t i=0; i<data.length(); i++ ) {
|
||||
for (size_t i = 0; i < data.length(); i++) {
|
||||
int t = data(i);
|
||||
ASSERT( t >= 0 && t <= readMaxValue );
|
||||
ASSERT(t >= 0 && t <= readMaxValue);
|
||||
data(i) = map[t];
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
#ifndef READMICROCT_H
|
||||
#define READMICROCT_H
|
||||
|
||||
|
||||
#include "common/Array.h"
|
||||
#include "common/Communication.h"
|
||||
#include "common/Database.h"
|
||||
#include "common/MPI.h"
|
||||
|
||||
Array<uint8_t> readMicroCT(const std::string &filename);
|
||||
|
||||
Array<uint8_t> readMicroCT( const std::string& filename );
|
||||
|
||||
Array<uint8_t> readMicroCT( const Database& domain, const Utilities::MPI& comm );
|
||||
|
||||
Array<uint8_t> readMicroCT(const Database &domain, const Utilities::MPI &comm);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "common/ScaLBL.h"
|
||||
|
||||
#include <chrono>
|
||||
|
@ -1356,6 +1372,14 @@ void ScaLBL_Communicator::SolidNeumannD3Q7(double *fq, double *BoundaryValue){
|
|||
ScaLBL_Solid_Neumann_D3Q7(fq,BoundaryValue,bb_dist,bb_interactions,n_bb_d3q7);
|
||||
}
|
||||
|
||||
void ScaLBL_Communicator::SolidDirichletAndNeumannD3Q7(double *fq, double *BoundaryValue, int *BoundaryLabel){
|
||||
// fq is a D3Q7 distribution
|
||||
// BoundaryValues is a list of values to assign at bounce-back solid sites
|
||||
// BoundaryLabel: is a list of integer labels indicating the type of BCs
|
||||
// 1-> Dirichlet BC; 2-> Neumann BC.
|
||||
ScaLBL_Solid_DirichletAndNeumann_D3Q7(fq,BoundaryValue,BoundaryLabel,bb_dist,bb_interactions,n_bb_d3q7);
|
||||
}
|
||||
|
||||
void ScaLBL_Communicator::SolidSlippingVelocityBCD3Q19(double *fq, double *zeta_potential, double *ElectricField, double *SolidGrad,
|
||||
double epsilon_LB, double tau, double rho0, double den_scale,double h, double time_conv){
|
||||
// fq is a D3Q19 distribution
|
||||
|
@ -2300,24 +2324,70 @@ void ScaLBL_Communicator::D3Q7_Ion_Concentration_BC_Z(int *neighborList, double
|
|||
}
|
||||
}
|
||||
|
||||
void ScaLBL_Communicator::D3Q7_Ion_Flux_BC_z(int *neighborList, double *fq, double Cin, double tau, double *VelocityZ, int time){
|
||||
void ScaLBL_Communicator::D3Q7_Ion_Flux_Diff_BC_z(int *neighborList, double *fq, double Cin, double tau, double *VelocityZ, int time){
|
||||
if (kproc == 0) {
|
||||
if (time%2==0){
|
||||
ScaLBL_D3Q7_AAeven_Ion_Flux_BC_z(dvcSendList_z, fq, Cin, tau, VelocityZ, sendCount_z, N);
|
||||
ScaLBL_D3Q7_AAeven_Ion_Flux_Diff_BC_z(dvcSendList_z, fq, Cin, tau, VelocityZ, sendCount_z, N);
|
||||
}
|
||||
else{
|
||||
ScaLBL_D3Q7_AAodd_Ion_Flux_BC_z(neighborList, dvcSendList_z, fq, Cin, tau, VelocityZ, sendCount_z, N);
|
||||
ScaLBL_D3Q7_AAodd_Ion_Flux_Diff_BC_z(neighborList, dvcSendList_z, fq, Cin, tau, VelocityZ, sendCount_z, N);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScaLBL_Communicator::D3Q7_Ion_Flux_BC_Z(int *neighborList, double *fq, double Cout, double tau, double *VelocityZ, int time){
|
||||
void ScaLBL_Communicator::D3Q7_Ion_Flux_Diff_BC_Z(int *neighborList, double *fq, double Cout, double tau, double *VelocityZ, int time){
|
||||
if (kproc == nprocz-1){
|
||||
if (time%2==0){
|
||||
ScaLBL_D3Q7_AAeven_Ion_Flux_BC_Z(dvcSendList_Z, fq, Cout, tau, VelocityZ, sendCount_Z, N);
|
||||
ScaLBL_D3Q7_AAeven_Ion_Flux_Diff_BC_Z(dvcSendList_Z, fq, Cout, tau, VelocityZ, sendCount_Z, N);
|
||||
}
|
||||
else{
|
||||
ScaLBL_D3Q7_AAodd_Ion_Flux_BC_Z(neighborList, dvcSendList_Z, fq, Cout, tau, VelocityZ, sendCount_Z, N);
|
||||
ScaLBL_D3Q7_AAodd_Ion_Flux_Diff_BC_Z(neighborList, dvcSendList_Z, fq, Cout, tau, VelocityZ, sendCount_Z, N);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScaLBL_Communicator::D3Q7_Ion_Flux_DiffAdvc_BC_z(int *neighborList, double *fq, double Cin, double tau, double *VelocityZ, int time){
|
||||
if (kproc == 0) {
|
||||
if (time%2==0){
|
||||
ScaLBL_D3Q7_AAeven_Ion_Flux_DiffAdvc_BC_z(dvcSendList_z, fq, Cin, tau, VelocityZ, sendCount_z, N);
|
||||
}
|
||||
else{
|
||||
ScaLBL_D3Q7_AAodd_Ion_Flux_DiffAdvc_BC_z(neighborList, dvcSendList_z, fq, Cin, tau, VelocityZ, sendCount_z, N);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScaLBL_Communicator::D3Q7_Ion_Flux_DiffAdvc_BC_Z(int *neighborList, double *fq, double Cout, double tau, double *VelocityZ, int time){
|
||||
if (kproc == nprocz-1){
|
||||
if (time%2==0){
|
||||
ScaLBL_D3Q7_AAeven_Ion_Flux_DiffAdvc_BC_Z(dvcSendList_Z, fq, Cout, tau, VelocityZ, sendCount_Z, N);
|
||||
}
|
||||
else{
|
||||
ScaLBL_D3Q7_AAodd_Ion_Flux_DiffAdvc_BC_Z(neighborList, dvcSendList_Z, fq, Cout, tau, VelocityZ, sendCount_Z, N);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScaLBL_Communicator::D3Q7_Ion_Flux_DiffAdvcElec_BC_z(int *neighborList, double *fq, double Cin, double tau, double *VelocityZ, double *ElectricField_Z,
|
||||
double Di, double zi, double Vt, int time){
|
||||
if (kproc == 0) {
|
||||
if (time%2==0){
|
||||
ScaLBL_D3Q7_AAeven_Ion_Flux_DiffAdvcElec_BC_z(dvcSendList_z, fq, Cin, tau, VelocityZ, ElectricField_Z, Di, zi, Vt, sendCount_z, N);
|
||||
}
|
||||
else{
|
||||
ScaLBL_D3Q7_AAodd_Ion_Flux_DiffAdvcElec_BC_z(neighborList, dvcSendList_z, fq, Cin, tau, VelocityZ, ElectricField_Z, Di, zi, Vt, sendCount_z, N);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScaLBL_Communicator::D3Q7_Ion_Flux_DiffAdvcElec_BC_Z(int *neighborList, double *fq, double Cout, double tau, double *VelocityZ, double *ElectricField_Z,
|
||||
double Di, double zi, double Vt, int time){
|
||||
if (kproc == nprocz-1){
|
||||
if (time%2==0){
|
||||
ScaLBL_D3Q7_AAeven_Ion_Flux_DiffAdvcElec_BC_Z(dvcSendList_Z, fq, Cout, tau, VelocityZ, ElectricField_Z, Di, zi, Vt, sendCount_Z, N);
|
||||
}
|
||||
else{
|
||||
ScaLBL_D3Q7_AAodd_Ion_Flux_DiffAdvcElec_BC_Z(neighborList, dvcSendList_Z, fq, Cout, tau, VelocityZ, ElectricField_Z, Di, zi, Vt, sendCount_Z, N);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
407
common/ScaLBL.h
407
common/ScaLBL.h
|
@ -1,5 +1,21 @@
|
|||
/* ScaLBL.h
|
||||
* Header file for Scalable Lattice Boltzmann Library
|
||||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** @file ScaLBL.h */
|
||||
/* \details Header file for Scalable Lattice Boltzmann Library
|
||||
* Separate implementations for GPU and CPU must both follow the conventions defined in this header
|
||||
* This libarry contains the essential components of the LBM
|
||||
* - streaming implementations
|
||||
|
@ -11,48 +27,194 @@
|
|||
#define ScalLBL_H
|
||||
#include "common/Domain.h"
|
||||
|
||||
/**
|
||||
* \brief Set compute device
|
||||
* @param rank rank of MPI process
|
||||
*/
|
||||
extern "C" int ScaLBL_SetDevice(int rank);
|
||||
|
||||
/**
|
||||
* \brief Allocate memory
|
||||
* @param address memory address
|
||||
* @param size size in bytes
|
||||
*/
|
||||
extern "C" void ScaLBL_AllocateDeviceMemory(void** address, size_t size);
|
||||
|
||||
/**
|
||||
* \brief Free memory
|
||||
* @param pointer pointer to memory to free
|
||||
*/
|
||||
extern "C" void ScaLBL_FreeDeviceMemory(void* pointer);
|
||||
|
||||
/**
|
||||
* \brief Copy memory from host to device
|
||||
* \details Device memory should be close to simulation (based on NUMA cost)
|
||||
* Host memory may be a shared memory region (with possibly higher NUMA cost for simulation)
|
||||
* Analysis routine should minimize NUMA for host memory (based on process placement)
|
||||
* @param dest memory location to copy to
|
||||
* @param source memory region to copy from
|
||||
* @param size size of the region to copy in bytes
|
||||
*/
|
||||
extern "C" void ScaLBL_CopyToDevice(void* dest, const void* source, size_t size);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Copy memory from device to host
|
||||
* \details Device memory should be close to simulation (based on NUMA cost)
|
||||
* Host memory may be a shared memory region (with possibly higher NUMA cost for simulation)
|
||||
* Analysis routine should minimize NUMA for host memory (based on process placement)
|
||||
* @param dest memory location to copy to
|
||||
* @param source memory region to copy from
|
||||
* @param size size of the region to copy in bytes
|
||||
*/
|
||||
extern "C" void ScaLBL_CopyToHost(void* dest, const void* source, size_t size);
|
||||
|
||||
/**
|
||||
=* \brief Allocate zero copy memory buffer (i.e. shared memory)
|
||||
* @param address memory address
|
||||
* @param size size in bytes
|
||||
*/
|
||||
extern "C" void ScaLBL_AllocateZeroCopy(void** address, size_t size);
|
||||
|
||||
/**
|
||||
* \brief Copy memory from host to zero copy buffer
|
||||
* \details Device memory should be close to simulation (based on NUMA cost)
|
||||
* Host memory may be a shared memory region (with possibly higher NUMA cost for simulation)
|
||||
* Analysis routine should minimize NUMA for host memory (based on process placement)
|
||||
* @param dest memory location to copy to
|
||||
* @param source memory region to copy from
|
||||
* @param size size of the region to copy in bytes
|
||||
*/
|
||||
extern "C" void ScaLBL_CopyToZeroCopy(void* dest, const void* source, size_t size);
|
||||
|
||||
/**
|
||||
* \brief Device barrier routine
|
||||
*/
|
||||
extern "C" void ScaLBL_DeviceBarrier();
|
||||
|
||||
/**
|
||||
* \brief Pack D3Q19 distributions for communication
|
||||
* @param q - index for distribution based on D3Q19 discrete velocity structure
|
||||
* @param list - list of distributions to communicate
|
||||
* @param start - index to start parsing the list
|
||||
* @param count - number of values to pack
|
||||
* @param sendbuf - memory buffer to hold values that will be sent
|
||||
* @param dist - memory buffer to hold the distributions
|
||||
* @param N - size of the distributions (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q19_Pack(int q, int *list, int start, int count, double *sendbuf, double *dist, int N);
|
||||
|
||||
/**
|
||||
* \brief Unpack D3Q19 distributions after communication
|
||||
* @param q - index for distribution based on D3Q19 discrete velocity structure
|
||||
* @param list - list of distributions to communicate
|
||||
* @param start - index to start parsing the list
|
||||
* @param count - number of values to unppack
|
||||
* @param recvbuf - memory buffer where recieved values have been stored
|
||||
* @param dist - memory buffer to hold the distributions
|
||||
* @param N - size of the distributions (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q19_Unpack(int q, int *list, int start, int count, double *recvbuf, double *dist, int N);
|
||||
|
||||
/**
|
||||
* \brief Unpack D3Q7 distributions after communication
|
||||
* @param q - index for distribution based on D3Q19 discrete velocity structure
|
||||
* @param list - list of distributions to communicate
|
||||
* @param start - index to start parsing the list
|
||||
* @param count - number of values to unppack
|
||||
* @param recvbuf - memory buffer where recieved values have been stored
|
||||
* @param dist - memory buffer to hold the distributions
|
||||
* @param N - size of the distributions (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q7_Unpack(int q, int *list, int start, int count, double *recvbuf, double *dist, int N);
|
||||
|
||||
/**
|
||||
* \brief Pack halo for scalar field to be prepare for communication
|
||||
* @param list - list of distributions to communicate
|
||||
* @param count - number of values to ppack
|
||||
* @param sendbuf - memory buffer to pack values into
|
||||
* @param Data - scalar field
|
||||
* @param N - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_Scalar_Pack(int *list, int count, double *sendbuf, double *Data, int N);
|
||||
|
||||
/**
|
||||
* \brief Pack halo for scalar field to be prepare for communication
|
||||
* @param list - list of distributions to communicate
|
||||
* @param count - number of values to unppack
|
||||
* @param recvbuf - memory buffer where recieved values have been stored
|
||||
* @param Data - scalar field
|
||||
* @param N - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_Scalar_Unpack(int *list, int count, double *recvbuf, double *Data, int N);
|
||||
|
||||
/**
|
||||
* \brief Unpack values and compute Shan-Chen type of gradient
|
||||
* @param weight - weight value for gradient sum
|
||||
* @param Cqx - contribution to x-part of gradient
|
||||
* @param Cqy - contribution to y-part of gradient
|
||||
* @param Cqz - contribution to z-part of gradient
|
||||
* @param list - list of distributions to communicate
|
||||
* @param start - location to start reading the list
|
||||
* @param count - number of values to unppack
|
||||
* @param recvbuf - memory buffer where recieved values have been stored
|
||||
* @param phi - scalar field
|
||||
* @param grad - gradient
|
||||
* @param N - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_Gradient_Unpack(double weight, double Cqx, double Cqy, double Cqz,
|
||||
int *list, int start, int count, double *recvbuf, double *phi, double *grad, int N);
|
||||
|
||||
extern "C" void ScaLBL_PackDenD3Q7(int *list, int count, double *sendbuf, int number, double *Data, int N);
|
||||
|
||||
extern "C" void ScaLBL_UnpackDenD3Q7(int *list, int count, double *recvbuf, int number, double *Data, int N);
|
||||
|
||||
/**
|
||||
* \brief Initialize D3Q19 distributions
|
||||
* @param Dist - D3Q19 distributions
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q19_Init(double *Dist, int Np);
|
||||
|
||||
/**
|
||||
* \brief Compute momentum from D3Q19 distribution
|
||||
* @param dist - D3Q19 distributions
|
||||
* @param vel - memory buffer to store the momentum that is computed
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q19_Momentum(double *dist, double *vel, int Np);
|
||||
|
||||
/**
|
||||
* \brief compute pressure from D3Q19 distribution
|
||||
* @param dist - D3Q19 distributions
|
||||
* @param press - memory buffer to store the pressure field that is computed
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q19_Pressure(double *dist, double *press, int Np);
|
||||
|
||||
// BGK MODEL
|
||||
/**
|
||||
* \brief BGK collision based on AA even access pattern for D3Q19
|
||||
* @param dist - D3Q19 distributions
|
||||
* @param start - lattice node to start loop
|
||||
* @param finish - lattice node to finish loop
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
* @param rlx - relaxation parameter
|
||||
* @param Fx - force in x direction
|
||||
* @param Fy - force in y direction
|
||||
* @param Fz - force in z direction
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q19_AAeven_BGK(double *dist, int start, int finish, int Np, double rlx, double Fx, double Fy, double Fz);
|
||||
|
||||
/**
|
||||
* \brief BGK collision based on AA odd access pattern for D3Q19
|
||||
* @param neighborList - neighbors based on D3Q19 lattice structure
|
||||
* @param dist - D3Q19 distributions
|
||||
* @param start - lattice node to start loop
|
||||
* @param finish - lattice node to finish loop
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
* @param rlx - relaxation parameter
|
||||
* @param Fx - force in x direction
|
||||
* @param Fy - force in y direction
|
||||
* @param Fz - force in z direction
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q19_AAodd_BGK(int *neighborList, double *dist, int start, int finish, int Np, double rlx, double Fx, double Fy, double Fz);
|
||||
|
||||
// GREYSCALE MODEL (Single-component)
|
||||
|
@ -88,12 +250,12 @@ extern "C" void ScaLBL_D3Q19_AAodd_GreyscaleColor(int *d_neighborList, int *Map,
|
|||
double Fx, double Fy, double Fz, int strideY, int strideZ, int start, int finish, int Np);
|
||||
|
||||
extern "C" void ScaLBL_D3Q19_AAeven_GreyscaleColor_CP(int *Map, double *dist, double *Aq, double *Bq, double *Den,
|
||||
double *Phi, double *GreySolidW, double *GreySn, double *GreySw, double *Poros,double *Perm,double *Vel, double *Pressure,
|
||||
double *Phi, double *GreySolidW, double *GreySn, double *GreySw, double *GreyKn, double *GreyKw, double *Poros,double *Perm,double *Vel, double *MobilityRatio, double *Pressure,
|
||||
double rhoA, double rhoB, double tauA, double tauB,double tauA_eff,double tauB_eff, double alpha, double beta,
|
||||
double Fx, double Fy, double Fz, bool RecoloringOff, int strideY, int strideZ, int start, int finish, int Np);
|
||||
|
||||
extern "C" void ScaLBL_D3Q19_AAodd_GreyscaleColor_CP(int *d_neighborList, int *Map, double *dist, double *Aq, double *Bq, double *Den,
|
||||
double *Phi, double *GreySolidW, double *GreySn, double *GreySw, double *Poros,double *Perm,double *Vel,double *Pressure,
|
||||
double *Phi, double *GreySolidW, double *GreySn, double *GreySw, double *GreyKn, double *GreyKw, double *Poros, double *Perm,double *Vel, double *MobilityRatio, double *Pressure,
|
||||
double rhoA, double rhoB, double tauA, double tauB, double tauA_eff,double tauB_eff, double alpha, double beta,
|
||||
double Fx, double Fy, double Fz, bool RecoloringOff, int strideY, int strideZ, int start, int finish, int Np);
|
||||
|
||||
|
@ -107,10 +269,10 @@ extern "C" void ScaLBL_D3Q7_AAodd_IonConcentration(int *neighborList, double *di
|
|||
extern "C" void ScaLBL_D3Q7_AAeven_IonConcentration(double *dist, double *Den, int start, int finish, int Np);
|
||||
|
||||
|
||||
extern "C" void ScaLBL_D3Q7_AAodd_Ion(int *neighborList, double *dist, double *Den, double *Velocity, double *ElectricField,
|
||||
extern "C" void ScaLBL_D3Q7_AAodd_Ion(int *neighborList, double *dist, double *Den, double *FluxDiffusive, double *FluxAdvective, double *FluxElectrical, double *Velocity, double *ElectricField,
|
||||
double Di, int zi, double rlx, double Vt, int start, int finish, int Np);
|
||||
|
||||
extern "C" void ScaLBL_D3Q7_AAeven_Ion(double *dist, double *Den, double *Velocity, double *ElectricField,
|
||||
extern "C" void ScaLBL_D3Q7_AAeven_Ion(double *dist, double *Den, double *FluxDiffusive, double *FluxAdvective, double *FluxElectrical, double *Velocity, double *ElectricField,
|
||||
double Di, int zi, double rlx, double Vt, int start, int finish, int Np);
|
||||
|
||||
extern "C" void ScaLBL_D3Q7_Ion_Init(double *dist, double *Den, double DenInit, int Np);
|
||||
|
@ -120,24 +282,73 @@ extern "C" void ScaLBL_D3Q7_Ion_ChargeDensity(double *Den, double *ChargeDensity
|
|||
|
||||
// LBM Poisson solver
|
||||
|
||||
/**
|
||||
* \brief Poisson-Boltzmann collision based on AA odd access pattern for D3Q19
|
||||
* @param neighborList - neighbors based on D3Q19 lattice structure
|
||||
* @param Map - mapping between sparse and dense representations
|
||||
* @param dist - D3Q7 distributions
|
||||
* @param Den_charge - charge density
|
||||
* @param Psi -
|
||||
* @param ElectricField - electric field
|
||||
* @param tau - relaxation time
|
||||
* @param epsilon_LB -
|
||||
* @param start - lattice node to start loop
|
||||
* @param finish - lattice node to finish loop
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q7_AAodd_Poisson(int *neighborList,int *Map, double *dist, double *Den_charge, double *Psi, double *ElectricField, double tau, double epsilon_LB,
|
||||
int start, int finish, int Np);
|
||||
|
||||
extern "C" void ScaLBL_D3Q7_AAeven_Poisson(int *Map, double *dist, double *Den_charge, double *Psi, double *ElectricField, double tau, double epsilon_LB,
|
||||
int start, int finish, int Np);
|
||||
|
||||
/**
|
||||
* \brief Poisson-Boltzmann collision based on AA even access pattern for D3Q7
|
||||
* @param Map - mapping between sparse and dense representations
|
||||
* @param dist - D3Q7 distributions
|
||||
* @param Den_charge - charge density
|
||||
* @param Psi -
|
||||
* @param ElectricField - electric field
|
||||
* @param tau - relaxation time
|
||||
* @param epsilon_LB -
|
||||
* @param start - lattice node to start loop
|
||||
* @param finish - lattice node to finish loop
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q7_AAeven_Poisson(int *Map, double *dist, double *Den_charge, double *Psi, double *ElectricField, double tau,
|
||||
double epsilon_LB, int start, int finish, int Np);
|
||||
/**
|
||||
* \brief Poisson-Boltzmann solver / solve electric potential based on AA odd access pattern for D3Q7
|
||||
* @param neighborList - neighbors based on D3Q19 lattice structure
|
||||
* @param Map - mapping between sparse and dense representations
|
||||
* @param dist - D3Q7 distributions
|
||||
* @param Psi -
|
||||
* @param start - lattice node to start loop
|
||||
* @param finish - lattice node to finish loop
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q7_AAodd_Poisson_ElectricPotential(int *neighborList,int *Map, double *dist, double *Psi, int start, int finish, int Np);
|
||||
|
||||
/**
|
||||
* \brief Poisson-Boltzmann solver / solve electric potential based on AA odd access pattern for D3Q7
|
||||
* @param Map - mapping between sparse and dense representations
|
||||
* @param dist - D3Q7 distributions
|
||||
* @param Psi -
|
||||
* @param start - lattice node to start loop
|
||||
* @param finish - lattice node to finish loop
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q7_AAeven_Poisson_ElectricPotential(int *Map, double *dist, double *Psi, int start, int finish, int Np);
|
||||
|
||||
/**
|
||||
* \brief Initialize Poisson-Boltzmann solver
|
||||
* @param Map - mapping between sparse and dense representations
|
||||
* @param dist - D3Q7 distributions
|
||||
* @param Psi -
|
||||
* @param start - lattice node to start loop
|
||||
* @param finish - lattice node to finish loop
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q7_Poisson_Init(int *Map, double *dist, double *Psi, int start, int finish, int Np);
|
||||
|
||||
//maybe deprecated
|
||||
//extern "C" void ScaLBL_D3Q7_Poisson_ElectricField(int *neighborList, int *Map, signed char *ID, double *Psi, double *ElectricField, int SolidBC,
|
||||
// int strideY, int strideZ,int start, int finish, int Np);
|
||||
|
||||
// LBM Stokes Model (adapted from MRT model)
|
||||
|
||||
extern "C" void ScaLBL_D3Q19_AAeven_StokesMRT(double *dist, double *Velocity, double *ChargeDensity, double *ElectricField, double rlx_setA, double rlx_setB,
|
||||
double Gx, double Gy, double Gz,double rho0, double den_scale, double h, double time_conv, int start, int finish, int Np);
|
||||
|
||||
|
@ -147,27 +358,138 @@ extern "C" void ScaLBL_D3Q19_AAodd_StokesMRT(int *neighborList, double *dist, do
|
|||
extern "C" void ScaLBL_PhaseField_InitFromRestart(double *Den, double *Aq, double *Bq, int start, int finish, int Np);
|
||||
|
||||
// MRT MODEL
|
||||
/**
|
||||
* \brief MRT collision based on AA even access pattern for D3Q19
|
||||
* @param dist - D3Q19 distributions
|
||||
* @param start - lattice node to start loop
|
||||
* @param finish - lattice node to finish loop
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
* @param rlx_setA - relaxation parameter for viscous modes
|
||||
* @param rlx_setB - relaxation parameter for non-viscous modes
|
||||
* @param Fx - force in x direction
|
||||
* @param Fy - force in y direction
|
||||
* @param Fz - force in z direction
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q19_AAeven_MRT(double *dist, int start, int finish, int Np, double rlx_setA, double rlx_setB, double Fx,
|
||||
double Fy, double Fz);
|
||||
|
||||
extern "C" void ScaLBL_D3Q19_AAodd_MRT(int *d_neighborList, double *dist, int start, int finish, int Np,
|
||||
/**
|
||||
* \brief MRT collision based on AA even access pattern for D3Q19
|
||||
* @param neighborList - index of neighbors based on D3Q19 lattice structure
|
||||
* @param dist - D3Q19 distributions
|
||||
* @param start - lattice node to start loop
|
||||
* @param finish - lattice node to finish loop
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
* @param rlx_setA - relaxation parameter for viscous modes
|
||||
* @param rlx_setB - relaxation parameter for non-viscous modes
|
||||
* @param Fx - force in x direction
|
||||
* @param Fy - force in y direction
|
||||
* @param Fz - force in z direction
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q19_AAodd_MRT(int *neighborList, double *dist, int start, int finish, int Np,
|
||||
double rlx_setA, double rlx_setB, double Fx, double Fy, double Fz);
|
||||
|
||||
// COLOR MODEL
|
||||
/**
|
||||
* \brief Color model collision based on AA even access pattern for D3Q19
|
||||
* @param Map - mapping between sparse and dense data structures
|
||||
* @param dist - D3Q19 distributions
|
||||
* @param Aq - D3Q7 distribution for component A
|
||||
* @param Bq - D3Q7 distribution for component B
|
||||
* @param Den - density field
|
||||
* @param Phi - phase indicator field
|
||||
* @param Vel - velocity field
|
||||
* @param rhoA - density of component A
|
||||
* @param rhoB - density of component B
|
||||
* @param tauA - relaxation time for component A
|
||||
* @param tauB - relaxation time for component B
|
||||
* @param alpha - parameter to control interfacial tension
|
||||
* @param beta - parameter to control interface width
|
||||
* @param Fx - force in x direction
|
||||
* @param Fy - force in y direction
|
||||
* @param Fz - force in z direction
|
||||
* @param strideY - stride in y-direction for gradient computation
|
||||
* @param strideZ - stride in z-direction for gradient computation
|
||||
* @param start - lattice node to start loop
|
||||
* @param finish - lattice node to finish loop
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q19_AAeven_Color(int *Map, double *dist, double *Aq, double *Bq, double *Den, double *Phi,
|
||||
double *Vel, double rhoA, double rhoB, double tauA, double tauB, double alpha, double beta,
|
||||
double Fx, double Fy, double Fz, int strideY, int strideZ, int start, int finish, int Np);
|
||||
|
||||
extern "C" void ScaLBL_D3Q19_AAodd_Color(int *d_neighborList, int *Map, double *dist, double *Aq, double *Bq, double *Den,
|
||||
/**
|
||||
* \brief Color model collision based on AA even access pattern for D3Q19
|
||||
* @param NeighborList - neighbors based on D3Q19 lattice structure
|
||||
* @param Map - mapping between sparse and dense data structures
|
||||
* @param dist - D3Q19 distributions
|
||||
* @param Aq - D3Q7 distribution for component A
|
||||
* @param Bq - D3Q7 distribution for component B
|
||||
* @param Den - density field
|
||||
* @param Phi - phase indicator field
|
||||
* @param Vel - velocity field
|
||||
* @param rhoA - density of component A
|
||||
* @param rhoB - density of component B
|
||||
* @param tauA - relaxation time for component A
|
||||
* @param tauB - relaxation time for component B
|
||||
* @param alpha - parameter to control interfacial tension
|
||||
* @param beta - parameter to control interface width
|
||||
* @param Fx - force in x direction
|
||||
* @param Fy - force in y direction
|
||||
* @param Fz - force in z direction
|
||||
* @param strideY - stride in y-direction for gradient computation
|
||||
* @param strideZ - stride in z-direction for gradient computation
|
||||
* @param start - lattice node to start loop
|
||||
* @param finish - lattice node to finish loop
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q19_AAodd_Color(int *NeighborList, int *Map, double *dist, double *Aq, double *Bq, double *Den,
|
||||
double *Phi, double *Vel, double rhoA, double rhoB, double tauA, double tauB, double alpha, double beta,
|
||||
double Fx, double Fy, double Fz, int strideY, int strideZ, int start, int finish, int Np);
|
||||
|
||||
/**
|
||||
* \brief Compute phase field based on AA odd access pattern for D3Q19
|
||||
* @param NeighborList - neighbors based on D3Q19 lattice structure
|
||||
* @param Map - mapping between sparse and dense data structures
|
||||
* @param Aq - D3Q7 distribution for component A
|
||||
* @param Bq - D3Q7 distribution for component B
|
||||
* @param Den - density field
|
||||
* @param Phi - phase indicator field
|
||||
* @param start - lattice node to start loop
|
||||
* @param finish - lattice node to finish loop
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q7_AAodd_PhaseField(int *NeighborList, int *Map, double *Aq, double *Bq,
|
||||
double *Den, double *Phi, int start, int finish, int Np);
|
||||
|
||||
/**
|
||||
* \brief Compute phase field based on AA even access pattern for D3Q19
|
||||
* @param Map - mapping between sparse and dense data structures
|
||||
* @param Aq - D3Q7 distribution for component A
|
||||
* @param Bq - D3Q7 distribution for component B
|
||||
* @param Den - density field
|
||||
* @param Phi - phase indicator field
|
||||
* @param start - lattice node to start loop
|
||||
* @param finish - lattice node to finish loop
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_D3Q7_AAeven_PhaseField(int *Map, double *Aq, double *Bq, double *Den, double *Phi,
|
||||
int start, int finish, int Np);
|
||||
|
||||
/**
|
||||
* \brief Initialize phase field for color model
|
||||
* @param Map - mapping between sparse and dense data structures
|
||||
* @param Phi - phase indicator field
|
||||
* @param Den - density field
|
||||
* @param Aq - D3Q7 distribution for component A
|
||||
* @param Bq - D3Q7 distribution for component B
|
||||
* @param start - lattice node to start loop
|
||||
* @param finish - lattice node to finish loop
|
||||
* @param Np - size of local sub-domain (derived from Domain structure)
|
||||
*/
|
||||
extern "C" void ScaLBL_PhaseField_Init(int *Map, double *Phi, double *Den, double *Aq, double *Bq, int start, int finish, int Np);
|
||||
|
||||
|
||||
extern "C" void ScaLBL_D3Q7_AAodd_Color(int *neighborList, int *Map, double *Aq, double *Bq, double *Den,
|
||||
double *Phi, double *ColorGrad, double *Vel, double rhoA, double rhoB, double beta, int start, int finish, int Np);
|
||||
|
||||
|
@ -178,7 +500,6 @@ extern "C" void ScaLBL_D3Q19_Gradient(int *Map, double *Phi, double *ColorGrad,
|
|||
|
||||
extern "C" void ScaLBL_D3Q19_MixedGradient(int *Map, double *Phi, double *Gradient, int start, int finish, int Np, int Nx, int Ny, int Nz);
|
||||
|
||||
extern "C" void ScaLBL_PhaseField_Init(int *Map, double *Phi, double *Den, double *Aq, double *Bq, int start, int finish, int Np);
|
||||
|
||||
// Density functional hydrodynamics LBM
|
||||
extern "C" void ScaLBL_DFH_Init(double *Phi, double *Den, double *Aq, double *Bq, int start, int finish, int Np);
|
||||
|
@ -288,6 +609,8 @@ extern "C" void ScaLBL_Solid_Dirichlet_D3Q7(double *dist,double *BoundaryValue,i
|
|||
|
||||
extern "C" void ScaLBL_Solid_Neumann_D3Q7(double *dist,double *BoundaryValue,int *BounceBackDist_list,int *BounceBackSolid_list,int N);
|
||||
|
||||
extern "C" void ScaLBL_Solid_DirichletAndNeumann_D3Q7(double *dist,double *BoundaryValue,int *BoundaryLabel,int *BounceBackDist_list,int *BounceBackSolid_list,int N);
|
||||
|
||||
extern "C" void ScaLBL_Solid_SlippingVelocityBC_D3Q19(double *dist, double *zeta_potential, double *ElectricField, double *SolidGrad,
|
||||
double epsilon_LB, double tau, double rho0,double den_scale, double h, double time_conv,
|
||||
int *BounceBackDist_list, int *BounceBackSolid_list, int *FluidBoundary_list,
|
||||
|
@ -314,20 +637,39 @@ extern "C" void ScaLBL_D3Q7_AAodd_Ion_Concentration_BC_z(int *d_neighborList, in
|
|||
|
||||
extern "C" void ScaLBL_D3Q7_AAodd_Ion_Concentration_BC_Z(int *d_neighborList, int *list, double *dist, double Cout, int count, int Np);
|
||||
|
||||
extern "C" void ScaLBL_D3Q7_AAeven_Ion_Flux_BC_z(int *list, double *dist, double Cin, double tau, double *VelocityZ, int count, int Np);
|
||||
extern "C" void ScaLBL_D3Q7_AAeven_Ion_Flux_Diff_BC_z(int *list, double *dist, double Cin, double tau, double *VelocityZ, int count, int Np);
|
||||
extern "C" void ScaLBL_D3Q7_AAeven_Ion_Flux_Diff_BC_Z(int *list, double *dist, double Cout, double tau, double *VelocityZ, int count, int Np);
|
||||
extern "C" void ScaLBL_D3Q7_AAodd_Ion_Flux_Diff_BC_z(int *d_neighborList, int *list, double *dist, double Cin, double tau, double *VelocityZ, int count, int Np);
|
||||
extern "C" void ScaLBL_D3Q7_AAodd_Ion_Flux_Diff_BC_Z(int *d_neighborList, int *list, double *dist, double Cout, double tau, double *VelocityZ, int count, int Np);
|
||||
|
||||
extern "C" void ScaLBL_D3Q7_AAeven_Ion_Flux_BC_Z(int *list, double *dist, double Cout, double tau, double *VelocityZ, int count, int Np);
|
||||
extern "C" void ScaLBL_D3Q7_AAeven_Ion_Flux_DiffAdvc_BC_z(int *list, double *dist, double Cin, double tau, double *VelocityZ, int count, int Np);
|
||||
extern "C" void ScaLBL_D3Q7_AAeven_Ion_Flux_DiffAdvc_BC_Z(int *list, double *dist, double Cout, double tau, double *VelocityZ, int count, int Np);
|
||||
extern "C" void ScaLBL_D3Q7_AAodd_Ion_Flux_DiffAdvc_BC_z(int *d_neighborList, int *list, double *dist, double Cin, double tau, double *VelocityZ, int count, int Np);
|
||||
extern "C" void ScaLBL_D3Q7_AAodd_Ion_Flux_DiffAdvc_BC_Z(int *d_neighborList, int *list, double *dist, double Cout, double tau, double *VelocityZ, int count, int Np);
|
||||
|
||||
extern "C" void ScaLBL_D3Q7_AAodd_Ion_Flux_BC_z(int *d_neighborList, int *list, double *dist, double Cin, double tau, double *VelocityZ, int count, int Np);
|
||||
|
||||
extern "C" void ScaLBL_D3Q7_AAodd_Ion_Flux_BC_Z(int *d_neighborList, int *list, double *dist, double Cout, double tau, double *VelocityZ, int count, int Np);
|
||||
extern "C" void ScaLBL_D3Q7_AAeven_Ion_Flux_DiffAdvcElec_BC_z(int *list, double *dist, double Cin, double tau, double *VelocityZ,double *ElectricField,double Di,double zi,double Vt,int count,int Np);
|
||||
extern "C" void ScaLBL_D3Q7_AAeven_Ion_Flux_DiffAdvcElec_BC_Z(int *list, double *dist, double Cout, double tau, double *VelocityZ,double *ElectricField,double Di,double zi,double Vt,int count,int Np);
|
||||
extern "C" void ScaLBL_D3Q7_AAodd_Ion_Flux_DiffAdvcElec_BC_z(int *d_neighborList, int *list, double *dist, double Cin, double tau, double *VelocityZ,double *ElectricField,double Di,double zi,double Vt, int count, int Np);
|
||||
extern "C" void ScaLBL_D3Q7_AAodd_Ion_Flux_DiffAdvcElec_BC_Z(int *d_neighborList, int *list, double *dist, double Cout, double tau, double *VelocityZ,double *ElectricField,double Di,double zi,double Vt, int count, int Np);
|
||||
|
||||
/**
|
||||
* \class ScaLBL_Communicator
|
||||
*
|
||||
* @brief Generalized communication routines for lattice Boltzmann methods.
|
||||
*
|
||||
*/
|
||||
class ScaLBL_Communicator{
|
||||
public:
|
||||
//......................................................................................
|
||||
ScaLBL_Communicator(std::shared_ptr <Domain> Dm);
|
||||
/**
|
||||
*\brief Constructor
|
||||
* @param Dm - Domain information
|
||||
*/
|
||||
ScaLBL_Communicator(std::shared_ptr <Domain> Dm);
|
||||
|
||||
//ScaLBL_Communicator(Domain &Dm, IntArray &Map);
|
||||
/**
|
||||
*\brief Destructor
|
||||
*/
|
||||
~ScaLBL_Communicator();
|
||||
//......................................................................................
|
||||
unsigned long int CommunicationCount,SendCount,RecvCount;
|
||||
|
@ -376,6 +718,7 @@ public:
|
|||
void SetupBounceBackList(IntArray &Map, signed char *id, int Np, bool SlippingVelBC=false);
|
||||
void SolidDirichletD3Q7(double *fq, double *BoundaryValue);
|
||||
void SolidNeumannD3Q7(double *fq, double *BoundaryValue);
|
||||
void SolidDirichletAndNeumannD3Q7(double *fq, double *BoundaryValue, int *BoundaryLabel);
|
||||
void SolidSlippingVelocityBCD3Q19(double *fq, double *zeta_potential, double *ElectricField, double *SolidGrad,
|
||||
double epslion_LB, double tau, double rho0, double den_scale,double h, double time_conv);
|
||||
|
||||
|
@ -393,8 +736,12 @@ public:
|
|||
void Poisson_D3Q7_BC_Z(int *Map, double *Psi, double Vout);
|
||||
void D3Q7_Ion_Concentration_BC_z(int *neighborList, double *fq, double Cin, int time);
|
||||
void D3Q7_Ion_Concentration_BC_Z(int *neighborList, double *fq, double Cout, int time);
|
||||
void D3Q7_Ion_Flux_BC_z(int *neighborList, double *fq, double Cin, double tau, double *VelocityZ, int time);
|
||||
void D3Q7_Ion_Flux_BC_Z(int *neighborList, double *fq, double Cout, double tau, double *VelocityZ, int time);
|
||||
void D3Q7_Ion_Flux_Diff_BC_z(int *neighborList, double *fq, double Cin, double tau, double *VelocityZ, int time);
|
||||
void D3Q7_Ion_Flux_Diff_BC_Z(int *neighborList, double *fq, double Cout, double tau, double *VelocityZ, int time);
|
||||
void D3Q7_Ion_Flux_DiffAdvc_BC_z(int *neighborList, double *fq, double Cin, double tau, double *VelocityZ, int time);
|
||||
void D3Q7_Ion_Flux_DiffAdvc_BC_Z(int *neighborList, double *fq, double Cout, double tau, double *VelocityZ, int time);
|
||||
void D3Q7_Ion_Flux_DiffAdvcElec_BC_z(int *neighborList,double *fq,double Cin,double tau,double *VelocityZ,double *ElectricField_Z,double Di,double zi,double Vt, int time);
|
||||
void D3Q7_Ion_Flux_DiffAdvcElec_BC_Z(int *neighborList,double *fq,double Cout,double tau,double *VelocityZ,double *ElectricField_Z,double Di,double zi,double Vt, int time);
|
||||
void GreyscaleSC_BC_z(int *Map, double *DenA, double *DenB, double vA, double vB);
|
||||
void GreyscaleSC_BC_Z(int *Map, double *DenA, double *DenB, double vA, double vB);
|
||||
void GreyscaleSC_Pressure_BC_z(int *neighborList, double *fqA, double *fqB, double dinA, double dinB, int time);
|
||||
|
@ -458,6 +805,4 @@ private:
|
|||
//......................................................................................
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,35 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
|
@ -15,245 +47,277 @@
|
|||
#include "common/SpherePack.h"
|
||||
|
||||
// Inline function to read line without a return argument
|
||||
static inline void fgetl( char * str, int num, FILE * stream )
|
||||
{
|
||||
char* ptr = fgets( str, num, stream );
|
||||
if ( 0 ) {char *temp = (char *)&ptr; temp++;}
|
||||
static inline void fgetl(char *str, int num, FILE *stream) {
|
||||
char *ptr = fgets(str, num, stream);
|
||||
if (0) {
|
||||
char *temp = (char *)&ptr;
|
||||
temp++;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteLocalSolidID(char *FILENAME, char *ID, int N)
|
||||
{
|
||||
char value;
|
||||
ofstream File(FILENAME,ios::binary);
|
||||
for (int n=0; n<N; n++){
|
||||
value = ID[n];
|
||||
File.write((char*) &value, sizeof(value));
|
||||
}
|
||||
File.close();
|
||||
void WriteLocalSolidID(char *FILENAME, char *ID, int N) {
|
||||
char value;
|
||||
ofstream File(FILENAME, ios::binary);
|
||||
for (int n = 0; n < N; n++) {
|
||||
value = ID[n];
|
||||
File.write((char *)&value, sizeof(value));
|
||||
}
|
||||
File.close();
|
||||
}
|
||||
|
||||
void WriteLocalSolidDistance(char *FILENAME, double *Distance, int N)
|
||||
{
|
||||
double value;
|
||||
ofstream File(FILENAME,ios::binary);
|
||||
for (int n=0; n<N; n++){
|
||||
value = Distance[n];
|
||||
File.write((char*) &value, sizeof(value));
|
||||
}
|
||||
File.close();
|
||||
void WriteLocalSolidDistance(char *FILENAME, double *Distance, int N) {
|
||||
double value;
|
||||
ofstream File(FILENAME, ios::binary);
|
||||
for (int n = 0; n < N; n++) {
|
||||
value = Distance[n];
|
||||
File.write((char *)&value, sizeof(value));
|
||||
}
|
||||
File.close();
|
||||
}
|
||||
|
||||
void ReadSpherePacking(int nspheres, double *List_cx, double *List_cy, double *List_cz, double *List_rad)
|
||||
{
|
||||
// Read in the full sphere pack
|
||||
//...... READ IN THE SPHERES...................................
|
||||
cout << "Reading the packing file..." << endl;
|
||||
FILE *fid = fopen("pack.out","rb");
|
||||
INSIST(fid!=NULL,"Error opening pack.out");
|
||||
//.........Trash the header lines..........
|
||||
char line[100];
|
||||
fgetl(line, 100, fid);
|
||||
fgetl(line, 100, fid);
|
||||
fgetl(line, 100, fid);
|
||||
fgetl(line, 100, fid);
|
||||
fgetl(line, 100, fid);
|
||||
//........read the spheres..................
|
||||
// We will read until a blank like or end-of-file is reached
|
||||
int count = 0;
|
||||
while ( !feof(fid) && fgets(line,100,fid)!=NULL ) {
|
||||
char* line2 = line;
|
||||
List_cx[count] = strtod(line2,&line2);
|
||||
List_cy[count] = strtod(line2,&line2);
|
||||
List_cz[count] = strtod(line2,&line2);
|
||||
List_rad[count] = strtod(line2,&line2);
|
||||
count++;
|
||||
}
|
||||
cout << "Number of spheres extracted is: " << count << endl;
|
||||
INSIST( count==nspheres, "Specified number of spheres is probably incorrect!" );
|
||||
// .............................................................
|
||||
void ReadSpherePacking(int nspheres, double *List_cx, double *List_cy,
|
||||
double *List_cz, double *List_rad) {
|
||||
// Read in the full sphere pack
|
||||
//...... READ IN THE SPHERES...................................
|
||||
cout << "Reading the packing file..." << endl;
|
||||
FILE *fid = fopen("pack.out", "rb");
|
||||
INSIST(fid != NULL, "Error opening pack.out");
|
||||
//.........Trash the header lines..........
|
||||
char line[100];
|
||||
fgetl(line, 100, fid);
|
||||
fgetl(line, 100, fid);
|
||||
fgetl(line, 100, fid);
|
||||
fgetl(line, 100, fid);
|
||||
fgetl(line, 100, fid);
|
||||
//........read the spheres..................
|
||||
// We will read until a blank like or end-of-file is reached
|
||||
int count = 0;
|
||||
while (!feof(fid) && fgets(line, 100, fid) != NULL) {
|
||||
char *line2 = line;
|
||||
List_cx[count] = strtod(line2, &line2);
|
||||
List_cy[count] = strtod(line2, &line2);
|
||||
List_cz[count] = strtod(line2, &line2);
|
||||
List_rad[count] = strtod(line2, &line2);
|
||||
count++;
|
||||
}
|
||||
cout << "Number of spheres extracted is: " << count << endl;
|
||||
INSIST(count == nspheres,
|
||||
"Specified number of spheres is probably incorrect!");
|
||||
// .............................................................
|
||||
}
|
||||
|
||||
void AssignLocalSolidID(char *ID, int nspheres, double *List_cx, double *List_cy, double *List_cz, double *List_rad,
|
||||
double Lx, double Ly, double Lz, int Nx, int Ny, int Nz,
|
||||
int iproc, int jproc, int kproc, int nprocx, int nprocy, int nprocz)
|
||||
{
|
||||
// Use sphere lists to determine which nodes are in porespace
|
||||
// Write out binary file for nodes
|
||||
char value;
|
||||
int N = Nx*Ny*Nz; // Domain size, including the halo
|
||||
double hx,hy,hz;
|
||||
double x,y,z;
|
||||
double cx,cy,cz,r;
|
||||
int imin,imax,jmin,jmax,kmin,kmax;
|
||||
int p,i,j,k,n;
|
||||
//............................................
|
||||
double min_x,min_y,min_z;
|
||||
// double max_x,max_y,max_z;
|
||||
//............................................
|
||||
// Lattice spacing for the entire domain
|
||||
// It should generally be true that hx=hy=hz
|
||||
// Otherwise, you will end up with ellipsoids
|
||||
hx = Lx/(Nx*nprocx-1);
|
||||
hy = Ly/(Ny*nprocy-1);
|
||||
hz = Lz/(Nz*nprocz-1);
|
||||
//............................................
|
||||
// Get maximum and minimum for this domain
|
||||
// Halo is included !
|
||||
min_x = double(iproc*Nx-1)*hx;
|
||||
min_y = double(jproc*Ny-1)*hy;
|
||||
min_z = double(kproc*Nz-1)*hz;
|
||||
// max_x = ((iproc+1)*Nx+1)*hx;
|
||||
// max_y = ((jproc+1)*Ny+1)*hy;
|
||||
// max_z = ((kproc+1)*Nz+1)*hz;
|
||||
//............................................
|
||||
void AssignLocalSolidID(char *ID, int nspheres, double *List_cx,
|
||||
double *List_cy, double *List_cz, double *List_rad,
|
||||
double Lx, double Ly, double Lz, int Nx, int Ny, int Nz,
|
||||
int iproc, int jproc, int kproc, int nprocx, int nprocy,
|
||||
int nprocz) {
|
||||
// Use sphere lists to determine which nodes are in porespace
|
||||
// Write out binary file for nodes
|
||||
char value;
|
||||
int N = Nx * Ny * Nz; // Domain size, including the halo
|
||||
double hx, hy, hz;
|
||||
double x, y, z;
|
||||
double cx, cy, cz, r;
|
||||
int imin, imax, jmin, jmax, kmin, kmax;
|
||||
int p, i, j, k, n;
|
||||
//............................................
|
||||
double min_x, min_y, min_z;
|
||||
// double max_x,max_y,max_z;
|
||||
//............................................
|
||||
// Lattice spacing for the entire domain
|
||||
// It should generally be true that hx=hy=hz
|
||||
// Otherwise, you will end up with ellipsoids
|
||||
hx = Lx / (Nx * nprocx - 1);
|
||||
hy = Ly / (Ny * nprocy - 1);
|
||||
hz = Lz / (Nz * nprocz - 1);
|
||||
//............................................
|
||||
// Get maximum and minimum for this domain
|
||||
// Halo is included !
|
||||
min_x = double(iproc * Nx - 1) * hx;
|
||||
min_y = double(jproc * Ny - 1) * hy;
|
||||
min_z = double(kproc * Nz - 1) * hz;
|
||||
// max_x = ((iproc+1)*Nx+1)*hx;
|
||||
// max_y = ((jproc+1)*Ny+1)*hy;
|
||||
// max_z = ((kproc+1)*Nz+1)*hz;
|
||||
//............................................
|
||||
|
||||
//............................................
|
||||
// Pre-initialize local ID
|
||||
for (n=0;n<N;n++){
|
||||
ID[n]=1;
|
||||
}
|
||||
//............................................
|
||||
//............................................
|
||||
// Pre-initialize local ID
|
||||
for (n = 0; n < N; n++) {
|
||||
ID[n] = 1;
|
||||
}
|
||||
//............................................
|
||||
|
||||
//............................................
|
||||
// .........Loop over the spheres.............
|
||||
for (p=0;p<nspheres;p++){
|
||||
// Get the sphere from the list, map to local min
|
||||
cx = List_cx[p] - min_x;
|
||||
cy = List_cy[p] - min_y;
|
||||
cz = List_cz[p] - min_z;
|
||||
r = List_rad[p];
|
||||
// Check if
|
||||
// Range for this sphere in global indexing
|
||||
imin = int ((cx-r)/hx)-1;
|
||||
imax = int ((cx+r)/hx)+1;
|
||||
jmin = int ((cy-r)/hy)-1;
|
||||
jmax = int ((cy+r)/hy)+1;
|
||||
kmin = int ((cz-r)/hz)-1;
|
||||
kmax = int ((cz+r)/hz)+1;
|
||||
// Obviously we have to do something at the edges
|
||||
if (imin<0) imin = 0;
|
||||
if (imin>Nx) imin = Nx;
|
||||
if (imax<0) imax = 0;
|
||||
if (imax>Nx) imax = Nx;
|
||||
if (jmin<0) jmin = 0;
|
||||
if (jmin>Ny) jmin = Ny;
|
||||
if (jmax<0) jmax = 0;
|
||||
if (jmax>Ny) jmax = Ny;
|
||||
if (kmin<0) kmin = 0;
|
||||
if (kmin>Nz) kmin = Nz;
|
||||
if (kmax<0) kmax = 0;
|
||||
if (kmax>Nz) kmax = Nz;
|
||||
// Loop over the domain for this sphere (may be null)
|
||||
for (i=imin;i<imax;i++){
|
||||
for (j=jmin;j<jmax;j++){
|
||||
for (k=kmin;k<kmax;k++){
|
||||
// Initialize ID value to 'fluid (=1)'
|
||||
x = i*hx;
|
||||
y = j*hy;
|
||||
z = k*hz;
|
||||
value = 1;
|
||||
// if inside sphere, set to zero
|
||||
if ( (cx-x)*(cx-x)+(cy-y)*(cy-y)+(cz-z)*(cz-z) < r*r){
|
||||
value=0;
|
||||
}
|
||||
// get the position in the list
|
||||
n = k*Nx*Ny+j*Nx+i;
|
||||
if ( ID[n] != 0 ){
|
||||
ID[n] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//............................................
|
||||
// .........Loop over the spheres.............
|
||||
for (p = 0; p < nspheres; p++) {
|
||||
// Get the sphere from the list, map to local min
|
||||
cx = List_cx[p] - min_x;
|
||||
cy = List_cy[p] - min_y;
|
||||
cz = List_cz[p] - min_z;
|
||||
r = List_rad[p];
|
||||
// Check if
|
||||
// Range for this sphere in global indexing
|
||||
imin = int((cx - r) / hx) - 1;
|
||||
imax = int((cx + r) / hx) + 1;
|
||||
jmin = int((cy - r) / hy) - 1;
|
||||
jmax = int((cy + r) / hy) + 1;
|
||||
kmin = int((cz - r) / hz) - 1;
|
||||
kmax = int((cz + r) / hz) + 1;
|
||||
// Obviously we have to do something at the edges
|
||||
if (imin < 0)
|
||||
imin = 0;
|
||||
if (imin > Nx)
|
||||
imin = Nx;
|
||||
if (imax < 0)
|
||||
imax = 0;
|
||||
if (imax > Nx)
|
||||
imax = Nx;
|
||||
if (jmin < 0)
|
||||
jmin = 0;
|
||||
if (jmin > Ny)
|
||||
jmin = Ny;
|
||||
if (jmax < 0)
|
||||
jmax = 0;
|
||||
if (jmax > Ny)
|
||||
jmax = Ny;
|
||||
if (kmin < 0)
|
||||
kmin = 0;
|
||||
if (kmin > Nz)
|
||||
kmin = Nz;
|
||||
if (kmax < 0)
|
||||
kmax = 0;
|
||||
if (kmax > Nz)
|
||||
kmax = Nz;
|
||||
// Loop over the domain for this sphere (may be null)
|
||||
for (i = imin; i < imax; i++) {
|
||||
for (j = jmin; j < jmax; j++) {
|
||||
for (k = kmin; k < kmax; k++) {
|
||||
// Initialize ID value to 'fluid (=1)'
|
||||
x = i * hx;
|
||||
y = j * hy;
|
||||
z = k * hz;
|
||||
value = 1;
|
||||
// if inside sphere, set to zero
|
||||
if ((cx - x) * (cx - x) + (cy - y) * (cy - y) +
|
||||
(cz - z) * (cz - z) <
|
||||
r * r) {
|
||||
value = 0;
|
||||
}
|
||||
// get the position in the list
|
||||
n = k * Nx * Ny + j * Nx + i;
|
||||
if (ID[n] != 0) {
|
||||
ID[n] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SignedDistance(double *Distance, int nspheres, double *List_cx, double *List_cy, double *List_cz, double *List_rad,
|
||||
double Lx, double Ly, double Lz, int Nx, int Ny, int Nz,
|
||||
int iproc, int jproc, int kproc, int nprocx, int nprocy, int nprocz)
|
||||
{
|
||||
// Use sphere lists to determine which nodes are in porespace
|
||||
// Write out binary file for nodes
|
||||
int N = Nx*Ny*Nz; // Domain size, including the halo
|
||||
double hx,hy,hz;
|
||||
double x,y,z;
|
||||
double cx,cy,cz,r;
|
||||
int imin,imax,jmin,jmax,kmin,kmax;
|
||||
int p,i,j,k,n;
|
||||
//............................................
|
||||
double min_x,min_y,min_z;
|
||||
double distance;
|
||||
//............................................
|
||||
// Lattice spacing for the entire domain
|
||||
// It should generally be true that hx=hy=hz
|
||||
// Otherwise, you will end up with ellipsoids
|
||||
hx = Lx/((Nx-2)*nprocx-1);
|
||||
hy = Ly/((Ny-2)*nprocy-1);
|
||||
hz = Lz/((Nz-2)*nprocz-1);
|
||||
//............................................
|
||||
// Get maximum and minimum for this domain
|
||||
// Halo is included !
|
||||
min_x = double(iproc*(Nx-2)-1)*hx;
|
||||
min_y = double(jproc*(Ny-2)-1)*hy;
|
||||
min_z = double(kproc*(Nz-2)-1)*hz;
|
||||
//............................................
|
||||
void SignedDistance(double *Distance, int nspheres, double *List_cx,
|
||||
double *List_cy, double *List_cz, double *List_rad,
|
||||
double Lx, double Ly, double Lz, int Nx, int Ny, int Nz,
|
||||
int iproc, int jproc, int kproc, int nprocx, int nprocy,
|
||||
int nprocz) {
|
||||
// Use sphere lists to determine which nodes are in porespace
|
||||
// Write out binary file for nodes
|
||||
int N = Nx * Ny * Nz; // Domain size, including the halo
|
||||
double hx, hy, hz;
|
||||
double x, y, z;
|
||||
double cx, cy, cz, r;
|
||||
int imin, imax, jmin, jmax, kmin, kmax;
|
||||
int p, i, j, k, n;
|
||||
//............................................
|
||||
double min_x, min_y, min_z;
|
||||
double distance;
|
||||
//............................................
|
||||
// Lattice spacing for the entire domain
|
||||
// It should generally be true that hx=hy=hz
|
||||
// Otherwise, you will end up with ellipsoids
|
||||
hx = Lx / ((Nx - 2) * nprocx - 1);
|
||||
hy = Ly / ((Ny - 2) * nprocy - 1);
|
||||
hz = Lz / ((Nz - 2) * nprocz - 1);
|
||||
//............................................
|
||||
// Get maximum and minimum for this domain
|
||||
// Halo is included !
|
||||
min_x = double(iproc * (Nx - 2) - 1) * hx;
|
||||
min_y = double(jproc * (Ny - 2) - 1) * hy;
|
||||
min_z = double(kproc * (Nz - 2) - 1) * hz;
|
||||
//............................................
|
||||
|
||||
//............................................
|
||||
// Pre-initialize Distance
|
||||
for (n=0;n<N;n++){
|
||||
Distance[n]=100.0;
|
||||
}
|
||||
//............................................
|
||||
//............................................
|
||||
// Pre-initialize Distance
|
||||
for (n = 0; n < N; n++) {
|
||||
Distance[n] = 100.0;
|
||||
}
|
||||
//............................................
|
||||
|
||||
//............................................
|
||||
// .........Loop over the spheres.............
|
||||
for (p=0;p<nspheres;p++){
|
||||
// Get the sphere from the list, map to local min
|
||||
cx = List_cx[p] - min_x;
|
||||
cy = List_cy[p] - min_y;
|
||||
cz = List_cz[p] - min_z;
|
||||
r = List_rad[p];
|
||||
// Check if
|
||||
// Range for this sphere in global indexing
|
||||
imin = int ((cx-2*r)/hx);
|
||||
imax = int ((cx+2*r)/hx)+2;
|
||||
jmin = int ((cy-2*r)/hy);
|
||||
jmax = int ((cy+2*r)/hy)+2;
|
||||
kmin = int ((cz-2*r)/hz);
|
||||
kmax = int ((cz+2*r)/hz)+2;
|
||||
// Obviously we have to do something at the edges
|
||||
if (imin<0) imin = 0;
|
||||
if (imin>Nx) imin = Nx;
|
||||
if (imax<0) imax = 0;
|
||||
if (imax>Nx) imax = Nx;
|
||||
if (jmin<0) jmin = 0;
|
||||
if (jmin>Ny) jmin = Ny;
|
||||
if (jmax<0) jmax = 0;
|
||||
if (jmax>Ny) jmax = Ny;
|
||||
if (kmin<0) kmin = 0;
|
||||
if (kmin>Nz) kmin = Nz;
|
||||
if (kmax<0) kmax = 0;
|
||||
if (kmax>Nz) kmax = Nz;
|
||||
// Loop over the domain for this sphere (may be null)
|
||||
for (i=imin;i<imax;i++){
|
||||
for (j=jmin;j<jmax;j++){
|
||||
for (k=kmin;k<kmax;k++){
|
||||
// x,y,z is distance in physical units
|
||||
x = i*hx;
|
||||
y = j*hy;
|
||||
z = k*hz;
|
||||
// if inside sphere, set to zero
|
||||
// get the position in the list
|
||||
n = k*Nx*Ny+j*Nx+i;
|
||||
// Compute the distance
|
||||
distance = sqrt((cx-x)*(cx-x)+(cy-y)*(cy-y)+(cz-z)*(cz-z)) - r;
|
||||
// Assign the minimum distance
|
||||
if (distance < Distance[n]) Distance[n] = distance;
|
||||
//............................................
|
||||
// .........Loop over the spheres.............
|
||||
for (p = 0; p < nspheres; p++) {
|
||||
// Get the sphere from the list, map to local min
|
||||
cx = List_cx[p] - min_x;
|
||||
cy = List_cy[p] - min_y;
|
||||
cz = List_cz[p] - min_z;
|
||||
r = List_rad[p];
|
||||
// Check if
|
||||
// Range for this sphere in global indexing
|
||||
imin = int((cx - 2 * r) / hx);
|
||||
imax = int((cx + 2 * r) / hx) + 2;
|
||||
jmin = int((cy - 2 * r) / hy);
|
||||
jmax = int((cy + 2 * r) / hy) + 2;
|
||||
kmin = int((cz - 2 * r) / hz);
|
||||
kmax = int((cz + 2 * r) / hz) + 2;
|
||||
// Obviously we have to do something at the edges
|
||||
if (imin < 0)
|
||||
imin = 0;
|
||||
if (imin > Nx)
|
||||
imin = Nx;
|
||||
if (imax < 0)
|
||||
imax = 0;
|
||||
if (imax > Nx)
|
||||
imax = Nx;
|
||||
if (jmin < 0)
|
||||
jmin = 0;
|
||||
if (jmin > Ny)
|
||||
jmin = Ny;
|
||||
if (jmax < 0)
|
||||
jmax = 0;
|
||||
if (jmax > Ny)
|
||||
jmax = Ny;
|
||||
if (kmin < 0)
|
||||
kmin = 0;
|
||||
if (kmin > Nz)
|
||||
kmin = Nz;
|
||||
if (kmax < 0)
|
||||
kmax = 0;
|
||||
if (kmax > Nz)
|
||||
kmax = Nz;
|
||||
// Loop over the domain for this sphere (may be null)
|
||||
for (i = imin; i < imax; i++) {
|
||||
for (j = jmin; j < jmax; j++) {
|
||||
for (k = kmin; k < kmax; k++) {
|
||||
// x,y,z is distance in physical units
|
||||
x = i * hx;
|
||||
y = j * hy;
|
||||
z = k * hz;
|
||||
// if inside sphere, set to zero
|
||||
// get the position in the list
|
||||
n = k * Nx * Ny + j * Nx + i;
|
||||
// Compute the distance
|
||||
distance = sqrt((cx - x) * (cx - x) + (cy - y) * (cy - y) +
|
||||
(cz - z) * (cz - z)) -
|
||||
r;
|
||||
// Assign the minimum distance
|
||||
if (distance < Distance[n])
|
||||
Distance[n] = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Map the distance to lattice units
|
||||
for (n=0; n<N; n++) Distance[n] = Distance[n]/hx;
|
||||
// Map the distance to lattice units
|
||||
for (n = 0; n < N; n++)
|
||||
Distance[n] = Distance[n] / hx;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SpherePack_INC
|
||||
#define SpherePack_INC
|
||||
|
||||
|
@ -24,14 +40,19 @@ void WriteLocalSolidID(char *FILENAME, char *ID, int N);
|
|||
|
||||
void WriteLocalSolidDistance(char *FILENAME, double *Distance, int N);
|
||||
|
||||
void ReadSpherePacking(int nspheres, double *List_cx, double *List_cy, double *List_cz, double *List_rad);
|
||||
void ReadSpherePacking(int nspheres, double *List_cx, double *List_cy,
|
||||
double *List_cz, double *List_rad);
|
||||
|
||||
void AssignLocalSolidID(char *ID, int nspheres, double *List_cx, double *List_cy, double *List_cz, double *List_rad,
|
||||
double Lx, double Ly, double Lz, int Nx, int Ny, int Nz,
|
||||
int iproc, int jproc, int kproc, int nprocx, int nprocy, int nprocz);
|
||||
void AssignLocalSolidID(char *ID, int nspheres, double *List_cx,
|
||||
double *List_cy, double *List_cz, double *List_rad,
|
||||
double Lx, double Ly, double Lz, int Nx, int Ny, int Nz,
|
||||
int iproc, int jproc, int kproc, int nprocx, int nprocy,
|
||||
int nprocz);
|
||||
|
||||
void SignedDistance(double *Distance, int nspheres, double *List_cx, double *List_cy, double *List_cz, double *List_rad,
|
||||
double Lx, double Ly, double Lz, int Nx, int Ny, int Nz,
|
||||
int iproc, int jproc, int kproc, int nprocx, int nprocy, int nprocz);
|
||||
void SignedDistance(double *Distance, int nspheres, double *List_cx,
|
||||
double *List_cy, double *List_cz, double *List_rad,
|
||||
double Lx, double Ly, double Lz, int Nx, int Ny, int Nz,
|
||||
int iproc, int jproc, int kproc, int nprocx, int nprocy,
|
||||
int nprocz);
|
||||
|
||||
#endif
|
||||
|
|
342
common/UnitTest.cpp
Executable file → Normal file
342
common/UnitTest.cpp
Executable file → Normal file
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "common/UnitTest.h"
|
||||
#include "common/Utilities.h"
|
||||
#include <cstring>
|
||||
|
@ -6,373 +22,361 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#define pout std::cout
|
||||
#define printp printf
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Constructor/Destructor *
|
||||
********************************************************************/
|
||||
UnitTest::UnitTest()
|
||||
{
|
||||
UnitTest::UnitTest() {
|
||||
#ifdef USE_MPI
|
||||
comm = MPI_COMM_WORLD;
|
||||
#endif
|
||||
}
|
||||
UnitTest::~UnitTest() { reset(); }
|
||||
void UnitTest::reset()
|
||||
{
|
||||
void UnitTest::reset() {
|
||||
mutex.lock();
|
||||
// Clear the data forcing a reallocation
|
||||
std::vector<std::string>().swap( pass_messages );
|
||||
std::vector<std::string>().swap( fail_messages );
|
||||
std::vector<std::string>().swap( expected_fail_messages );
|
||||
std::vector<std::string>().swap(pass_messages);
|
||||
std::vector<std::string>().swap(fail_messages);
|
||||
std::vector<std::string>().swap(expected_fail_messages);
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Add a pass, fail, expected failure message in a thread-safe way *
|
||||
********************************************************************/
|
||||
void UnitTest::passes( const std::string &in )
|
||||
{
|
||||
void UnitTest::passes(const std::string &in) {
|
||||
mutex.lock();
|
||||
pass_messages.push_back( in );
|
||||
pass_messages.push_back(in);
|
||||
mutex.unlock();
|
||||
}
|
||||
void UnitTest::failure( const std::string &in )
|
||||
{
|
||||
void UnitTest::failure(const std::string &in) {
|
||||
mutex.lock();
|
||||
fail_messages.push_back( in );
|
||||
fail_messages.push_back(in);
|
||||
mutex.unlock();
|
||||
}
|
||||
void UnitTest::expected_failure( const std::string &in )
|
||||
{
|
||||
void UnitTest::expected_failure(const std::string &in) {
|
||||
mutex.lock();
|
||||
expected_fail_messages.push_back( in );
|
||||
expected_fail_messages.push_back(in);
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Print a global report *
|
||||
* Note: only rank 0 will print, all messages will be aggregated *
|
||||
********************************************************************/
|
||||
inline std::vector<int> UnitTest::allGather( int value ) const
|
||||
{
|
||||
inline std::vector<int> UnitTest::allGather(int value) const {
|
||||
int size = getSize();
|
||||
std::vector<int> data( size, value );
|
||||
std::vector<int> data(size, value);
|
||||
#ifdef USE_MPI
|
||||
if ( size > 1 )
|
||||
MPI_Allgather( &value, 1, MPI_INT, data.data(), 1, MPI_INT, comm );
|
||||
if (size > 1)
|
||||
MPI_Allgather(&value, 1, MPI_INT, data.data(), 1, MPI_INT, comm);
|
||||
#endif
|
||||
return data;
|
||||
}
|
||||
inline void UnitTest::barrier() const
|
||||
{
|
||||
inline void UnitTest::barrier() const {
|
||||
#ifdef USE_MPI
|
||||
if ( getSize() > 1 )
|
||||
MPI_Barrier( comm );
|
||||
if (getSize() > 1)
|
||||
MPI_Barrier(comm);
|
||||
#endif
|
||||
}
|
||||
static inline void print_messages( const std::vector<std::vector<std::string>> &messages )
|
||||
{
|
||||
if ( messages.size() > 1 ) {
|
||||
for ( size_t i = 0; i < messages.size(); i++ ) {
|
||||
if ( !messages[i].empty() ) {
|
||||
printp( " Proccessor %i:\n", static_cast<int>( i ) );
|
||||
for ( const auto &j : messages[i] )
|
||||
static inline void
|
||||
print_messages(const std::vector<std::vector<std::string>> &messages) {
|
||||
if (messages.size() > 1) {
|
||||
for (size_t i = 0; i < messages.size(); i++) {
|
||||
if (!messages[i].empty()) {
|
||||
printp(" Proccessor %i:\n", static_cast<int>(i));
|
||||
for (const auto &j : messages[i])
|
||||
pout << " " << j << std::endl;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for ( const auto &j : messages[0] )
|
||||
for (const auto &j : messages[0])
|
||||
pout << " " << j << std::endl;
|
||||
}
|
||||
}
|
||||
void UnitTest::report( const int level0 ) const
|
||||
{
|
||||
void UnitTest::report(const int level0) const {
|
||||
mutex.lock();
|
||||
int size = getSize();
|
||||
int rank = getRank();
|
||||
// Broadcast the print level from rank 0
|
||||
int level = level0;
|
||||
#ifdef USE_MPI
|
||||
if ( getSize() > 1 )
|
||||
MPI_Bcast( &level, 1, MPI_INT, 0, comm );
|
||||
if (getSize() > 1)
|
||||
MPI_Bcast(&level, 1, MPI_INT, 0, comm);
|
||||
#endif
|
||||
if ( level < 0 || level > 2 )
|
||||
ERROR( "Invalid print level" );
|
||||
if (level < 0 || level > 2)
|
||||
ERROR("Invalid print level");
|
||||
// Perform a global all gather to get the number of failures per processor
|
||||
auto N_pass = allGather( pass_messages.size() );
|
||||
auto N_fail = allGather( fail_messages.size() );
|
||||
auto N_expected_fail = allGather( expected_fail_messages.size() );
|
||||
int N_pass_tot = 0;
|
||||
int N_fail_tot = 0;
|
||||
auto N_pass = allGather(pass_messages.size());
|
||||
auto N_fail = allGather(fail_messages.size());
|
||||
auto N_expected_fail = allGather(expected_fail_messages.size());
|
||||
int N_pass_tot = 0;
|
||||
int N_fail_tot = 0;
|
||||
int N_expected_fail_tot = 0;
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
N_pass_tot += N_pass[i];
|
||||
N_fail_tot += N_fail[i];
|
||||
N_expected_fail_tot += N_expected_fail[i];
|
||||
}
|
||||
// Send all messages to rank 0 (if needed)
|
||||
std::vector<std::vector<std::string>> pass_messages_rank( size );
|
||||
std::vector<std::vector<std::string>> fail_messages_rank( size );
|
||||
std::vector<std::vector<std::string>> expected_fail_rank( size );
|
||||
std::vector<std::vector<std::string>> pass_messages_rank(size);
|
||||
std::vector<std::vector<std::string>> fail_messages_rank(size);
|
||||
std::vector<std::vector<std::string>> expected_fail_rank(size);
|
||||
// Get the pass messages
|
||||
if ( ( level == 1 && N_pass_tot <= 20 ) || level == 2 )
|
||||
pass_messages_rank = UnitTest::gatherMessages( pass_messages, 1 );
|
||||
if ((level == 1 && N_pass_tot <= 20) || level == 2)
|
||||
pass_messages_rank = UnitTest::gatherMessages(pass_messages, 1);
|
||||
// Get the fail messages
|
||||
if ( level == 1 || level == 2 )
|
||||
fail_messages_rank = UnitTest::gatherMessages( fail_messages, 2 );
|
||||
if (level == 1 || level == 2)
|
||||
fail_messages_rank = UnitTest::gatherMessages(fail_messages, 2);
|
||||
// Get the expected_fail messages
|
||||
if ( ( level == 1 && N_expected_fail_tot <= 50 ) || level == 2 )
|
||||
expected_fail_rank = UnitTest::gatherMessages( expected_fail_messages, 2 );
|
||||
if ((level == 1 && N_expected_fail_tot <= 50) || level == 2)
|
||||
expected_fail_rank =
|
||||
UnitTest::gatherMessages(expected_fail_messages, 2);
|
||||
// Print the results of all messages (only rank 0 will print)
|
||||
if ( rank == 0 ) {
|
||||
if (rank == 0) {
|
||||
pout << std::endl;
|
||||
// Print the passed tests
|
||||
pout << "Tests passed" << std::endl;
|
||||
if ( level == 0 || ( level == 1 && N_pass_tot > 20 ) ) {
|
||||
if (level == 0 || (level == 1 && N_pass_tot > 20)) {
|
||||
// We want to print a summary
|
||||
if ( size > 8 ) {
|
||||
if (size > 8) {
|
||||
// Print 1 summary for all processors
|
||||
printp( " %i tests passed (use report level 2 for more detail)\n", N_pass_tot );
|
||||
printp(" %i tests passed (use report level 2 for more "
|
||||
"detail)\n",
|
||||
N_pass_tot);
|
||||
} else {
|
||||
// Print a summary for each processor
|
||||
for ( int i = 0; i < size; i++ )
|
||||
printp( " %i tests passed (proc %i) (use report level 2 for more detail)\n",
|
||||
N_pass[i], i );
|
||||
for (int i = 0; i < size; i++)
|
||||
printp(" %i tests passed (proc %i) (use report level 2 "
|
||||
"for more detail)\n",
|
||||
N_pass[i], i);
|
||||
}
|
||||
} else {
|
||||
// We want to print all messages
|
||||
for ( int i = 0; i < size; i++ )
|
||||
ASSERT( (int) pass_messages_rank[i].size() == N_pass[i] );
|
||||
print_messages( pass_messages_rank );
|
||||
for (int i = 0; i < size; i++)
|
||||
ASSERT((int)pass_messages_rank[i].size() == N_pass[i]);
|
||||
print_messages(pass_messages_rank);
|
||||
}
|
||||
pout << std::endl;
|
||||
// Print the tests that failed
|
||||
pout << "Tests failed" << std::endl;
|
||||
if ( level == 0 ) {
|
||||
if (level == 0) {
|
||||
// We want to print a summary
|
||||
if ( size > 8 ) {
|
||||
if (size > 8) {
|
||||
// Print 1 summary for all processors
|
||||
printp( " %i tests failed (use report level 2 for more detail)\n", N_fail_tot );
|
||||
printp(" %i tests failed (use report level 2 for more "
|
||||
"detail)\n",
|
||||
N_fail_tot);
|
||||
} else {
|
||||
// Print a summary for each processor
|
||||
for ( int i = 0; i < size; i++ )
|
||||
printp( " %i tests failed (proc %i) (use report level 2 for more detail)\n",
|
||||
N_fail[i], i );
|
||||
for (int i = 0; i < size; i++)
|
||||
printp(" %i tests failed (proc %i) (use report level 2 "
|
||||
"for more detail)\n",
|
||||
N_fail[i], i);
|
||||
}
|
||||
} else {
|
||||
// We want to print all messages
|
||||
for ( int i = 0; i < size; i++ )
|
||||
ASSERT( (int) fail_messages_rank[i].size() == N_fail[i] );
|
||||
print_messages( fail_messages_rank );
|
||||
for (int i = 0; i < size; i++)
|
||||
ASSERT((int)fail_messages_rank[i].size() == N_fail[i]);
|
||||
print_messages(fail_messages_rank);
|
||||
}
|
||||
pout << std::endl;
|
||||
// Print the tests that expected failed
|
||||
pout << "Tests expected failed" << std::endl;
|
||||
if ( level == 0 || ( level == 1 && N_expected_fail_tot > 50 ) ) {
|
||||
if (level == 0 || (level == 1 && N_expected_fail_tot > 50)) {
|
||||
// We want to print a summary
|
||||
if ( size > 8 ) {
|
||||
if (size > 8) {
|
||||
// Print 1 summary for all processors
|
||||
printp( " %i tests expected failed (use report level 2 for more detail)\n",
|
||||
N_expected_fail_tot );
|
||||
printp(" %i tests expected failed (use report level 2 for "
|
||||
"more detail)\n",
|
||||
N_expected_fail_tot);
|
||||
} else {
|
||||
// Print a summary for each processor
|
||||
for ( int i = 0; i < size; i++ )
|
||||
printp( " %i tests expected failed (proc %i) (use report level 2 for more "
|
||||
"detail)\n",
|
||||
N_expected_fail[i], i );
|
||||
for (int i = 0; i < size; i++)
|
||||
printp(" %i tests expected failed (proc %i) (use "
|
||||
"report level 2 for more "
|
||||
"detail)\n",
|
||||
N_expected_fail[i], i);
|
||||
}
|
||||
} else {
|
||||
// We want to print all messages
|
||||
for ( int i = 0; i < size; i++ )
|
||||
ASSERT( (int) expected_fail_rank[i].size() == N_expected_fail[i] );
|
||||
print_messages( expected_fail_rank );
|
||||
for (int i = 0; i < size; i++)
|
||||
ASSERT((int)expected_fail_rank[i].size() == N_expected_fail[i]);
|
||||
print_messages(expected_fail_rank);
|
||||
}
|
||||
pout << std::endl;
|
||||
}
|
||||
// Add a barrier to synchronize all processors (rank 0 is much slower)
|
||||
barrier();
|
||||
Utilities::sleep_ms( 10 ); // Need a brief pause to allow any printing to finish
|
||||
Utilities::sleep_ms(
|
||||
10); // Need a brief pause to allow any printing to finish
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Gather the messages to rank 0 *
|
||||
********************************************************************/
|
||||
std::vector<std::vector<std::string>> UnitTest::gatherMessages(
|
||||
const std::vector<std::string> &local_messages, int tag ) const
|
||||
{
|
||||
std::vector<std::vector<std::string>>
|
||||
UnitTest::gatherMessages(const std::vector<std::string> &local_messages,
|
||||
int tag) const {
|
||||
const int rank = getRank();
|
||||
const int size = getSize();
|
||||
std::vector<std::vector<std::string>> messages( size );
|
||||
if ( rank == 0 ) {
|
||||
std::vector<std::vector<std::string>> messages(size);
|
||||
if (rank == 0) {
|
||||
// Rank 0 should receive all messages
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
if ( i == 0 )
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (i == 0)
|
||||
messages[i] = local_messages;
|
||||
else
|
||||
messages[i] = unpack_message_stream( i, tag );
|
||||
messages[i] = unpack_message_stream(i, tag);
|
||||
}
|
||||
} else {
|
||||
// All other ranks send their message (use non-blocking communication)
|
||||
pack_message_stream( local_messages, 0, tag );
|
||||
pack_message_stream(local_messages, 0, tag);
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Pack and send the given messages *
|
||||
********************************************************************/
|
||||
void UnitTest::pack_message_stream(
|
||||
const std::vector<std::string> &messages, const int rank, const int tag ) const
|
||||
{
|
||||
void UnitTest::pack_message_stream(const std::vector<std::string> &messages,
|
||||
const int rank, const int tag) const {
|
||||
#ifdef USE_MPI
|
||||
// Get the size of the messages
|
||||
auto N_messages = (int) messages.size();
|
||||
auto *msg_size = new int[N_messages];
|
||||
auto N_messages = (int)messages.size();
|
||||
auto *msg_size = new int[N_messages];
|
||||
int msg_size_tot = 0;
|
||||
for ( int i = 0; i < N_messages; i++ ) {
|
||||
msg_size[i] = (int) messages[i].size();
|
||||
for (int i = 0; i < N_messages; i++) {
|
||||
msg_size[i] = (int)messages[i].size();
|
||||
msg_size_tot += msg_size[i];
|
||||
}
|
||||
// Allocate space for the message stream
|
||||
size_t size_data = ( N_messages + 1 ) * sizeof( int ) + msg_size_tot;
|
||||
auto *data = new char[size_data];
|
||||
size_t size_data = (N_messages + 1) * sizeof(int) + msg_size_tot;
|
||||
auto *data = new char[size_data];
|
||||
// Pack the message stream
|
||||
memcpy( data, &N_messages, sizeof( int ) );
|
||||
memcpy( &data[sizeof( int )], msg_size, N_messages * sizeof( int ) );
|
||||
size_t k = ( N_messages + 1 ) * sizeof( int );
|
||||
for ( int i = 0; i < N_messages; i++ ) {
|
||||
messages[i].copy( &data[k], msg_size[i] );
|
||||
memcpy(data, &N_messages, sizeof(int));
|
||||
memcpy(&data[sizeof(int)], msg_size, N_messages * sizeof(int));
|
||||
size_t k = (N_messages + 1) * sizeof(int);
|
||||
for (int i = 0; i < N_messages; i++) {
|
||||
messages[i].copy(&data[k], msg_size[i]);
|
||||
k += msg_size[i];
|
||||
}
|
||||
// Send the message stream (using a non-blocking send)
|
||||
MPI_Request request;
|
||||
MPI_Isend( data, size_data, MPI_CHAR, rank, tag, comm, &request );
|
||||
MPI_Isend(data, size_data, MPI_CHAR, rank, tag, comm, &request);
|
||||
// Wait for the communication to send and free the temporary memory
|
||||
MPI_Status status;
|
||||
MPI_Wait( &request, &status );
|
||||
MPI_Wait(&request, &status);
|
||||
delete[] data;
|
||||
delete[] msg_size;
|
||||
#else
|
||||
NULL_USE( messages );
|
||||
NULL_USE( rank );
|
||||
NULL_USE( tag );
|
||||
NULL_USE(messages);
|
||||
NULL_USE(rank);
|
||||
NULL_USE(tag);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Receive and unpack a message stream *
|
||||
********************************************************************/
|
||||
std::vector<std::string> UnitTest::unpack_message_stream( const int rank, const int tag ) const
|
||||
{
|
||||
std::vector<std::string> UnitTest::unpack_message_stream(const int rank,
|
||||
const int tag) const {
|
||||
#ifdef USE_MPI
|
||||
// Probe the message to get the message size
|
||||
MPI_Status status;
|
||||
MPI_Probe( rank, tag, comm, &status );
|
||||
MPI_Probe(rank, tag, comm, &status);
|
||||
int size_data = -1;
|
||||
MPI_Get_count( &status, MPI_BYTE, &size_data );
|
||||
ASSERT( size_data >= 0 );
|
||||
MPI_Get_count(&status, MPI_BYTE, &size_data);
|
||||
ASSERT(size_data >= 0);
|
||||
// Allocate memory to receive the data
|
||||
auto *data = new char[size_data];
|
||||
// receive the data (using a non-blocking receive)
|
||||
MPI_Request request;
|
||||
MPI_Irecv( data, size_data, MPI_CHAR, rank, tag, comm, &request );
|
||||
MPI_Irecv(data, size_data, MPI_CHAR, rank, tag, comm, &request);
|
||||
// Wait for the communication to be received
|
||||
MPI_Wait( &request, &status );
|
||||
MPI_Wait(&request, &status);
|
||||
// Unpack the message stream
|
||||
int N_messages = 0;
|
||||
memcpy( &N_messages, data, sizeof( int ) );
|
||||
if ( N_messages == 0 ) {
|
||||
memcpy(&N_messages, data, sizeof(int));
|
||||
if (N_messages == 0) {
|
||||
delete[] data;
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
std::vector<int> msg_size( N_messages );
|
||||
std::vector<std::string> messages( N_messages );
|
||||
memcpy( msg_size.data(), &data[sizeof( int )], N_messages * sizeof( int ) );
|
||||
int k = ( N_messages + 1 ) * sizeof( int );
|
||||
for ( int i = 0; i < N_messages; i++ ) {
|
||||
messages[i] = std::string( &data[k], msg_size[i] );
|
||||
std::vector<int> msg_size(N_messages);
|
||||
std::vector<std::string> messages(N_messages);
|
||||
memcpy(msg_size.data(), &data[sizeof(int)], N_messages * sizeof(int));
|
||||
int k = (N_messages + 1) * sizeof(int);
|
||||
for (int i = 0; i < N_messages; i++) {
|
||||
messages[i] = std::string(&data[k], msg_size[i]);
|
||||
k += msg_size[i];
|
||||
}
|
||||
delete[] data;
|
||||
return messages;
|
||||
#else
|
||||
NULL_USE( rank );
|
||||
NULL_USE( tag );
|
||||
NULL_USE(rank);
|
||||
NULL_USE(tag);
|
||||
return std::vector<std::string>();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Other functions *
|
||||
********************************************************************/
|
||||
int UnitTest::getRank() const
|
||||
{
|
||||
int UnitTest::getRank() const {
|
||||
int rank = 0;
|
||||
#ifdef USE_MPI
|
||||
int flag = 0;
|
||||
MPI_Initialized( &flag );
|
||||
if ( flag )
|
||||
MPI_Comm_rank( comm, &rank );
|
||||
MPI_Initialized(&flag);
|
||||
if (flag)
|
||||
MPI_Comm_rank(comm, &rank);
|
||||
#endif
|
||||
return rank;
|
||||
}
|
||||
int UnitTest::getSize() const
|
||||
{
|
||||
int UnitTest::getSize() const {
|
||||
int size = 1;
|
||||
#ifdef USE_MPI
|
||||
int flag = 0;
|
||||
MPI_Initialized( &flag );
|
||||
if ( flag )
|
||||
MPI_Comm_size( comm, &size );
|
||||
MPI_Initialized(&flag);
|
||||
if (flag)
|
||||
MPI_Comm_size(comm, &size);
|
||||
#endif
|
||||
return size;
|
||||
}
|
||||
size_t UnitTest::NumPassGlobal() const
|
||||
{
|
||||
size_t UnitTest::NumPassGlobal() const {
|
||||
size_t num = pass_messages.size();
|
||||
#ifdef USE_MPI
|
||||
if ( getSize() > 1 ) {
|
||||
auto send = static_cast<int>( num );
|
||||
int sum = 0;
|
||||
MPI_Allreduce( &send, &sum, 1, MPI_INT, MPI_SUM, comm );
|
||||
num = static_cast<size_t>( sum );
|
||||
if (getSize() > 1) {
|
||||
auto send = static_cast<int>(num);
|
||||
int sum = 0;
|
||||
MPI_Allreduce(&send, &sum, 1, MPI_INT, MPI_SUM, comm);
|
||||
num = static_cast<size_t>(sum);
|
||||
}
|
||||
#endif
|
||||
return num;
|
||||
}
|
||||
size_t UnitTest::NumFailGlobal() const
|
||||
{
|
||||
size_t UnitTest::NumFailGlobal() const {
|
||||
size_t num = fail_messages.size();
|
||||
#ifdef USE_MPI
|
||||
if ( getSize() > 1 ) {
|
||||
auto send = static_cast<int>( num );
|
||||
int sum = 0;
|
||||
MPI_Allreduce( &send, &sum, 1, MPI_INT, MPI_SUM, comm );
|
||||
num = static_cast<size_t>( sum );
|
||||
if (getSize() > 1) {
|
||||
auto send = static_cast<int>(num);
|
||||
int sum = 0;
|
||||
MPI_Allreduce(&send, &sum, 1, MPI_INT, MPI_SUM, comm);
|
||||
num = static_cast<size_t>(sum);
|
||||
}
|
||||
#endif
|
||||
return num;
|
||||
}
|
||||
size_t UnitTest::NumExpectedFailGlobal() const
|
||||
{
|
||||
size_t UnitTest::NumExpectedFailGlobal() const {
|
||||
size_t num = expected_fail_messages.size();
|
||||
#ifdef USE_MPI
|
||||
if ( getSize() > 1 ) {
|
||||
auto send = static_cast<int>( num );
|
||||
int sum = 0;
|
||||
MPI_Allreduce( &send, &sum, 1, MPI_INT, MPI_SUM, comm );
|
||||
num = static_cast<size_t>( sum );
|
||||
if (getSize() > 1) {
|
||||
auto send = static_cast<int>(num);
|
||||
int sum = 0;
|
||||
MPI_Allreduce(&send, &sum, 1, MPI_INT, MPI_SUM, comm);
|
||||
num = static_cast<size_t>(sum);
|
||||
}
|
||||
#endif
|
||||
return num;
|
||||
|
|
49
common/UnitTest.h
Executable file → Normal file
49
common/UnitTest.h
Executable file → Normal file
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef included_UnitTest
|
||||
#define included_UnitTest
|
||||
|
||||
|
@ -9,7 +25,6 @@
|
|||
#include "mpi.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Class UnitTest is simple utility for running unit tests.
|
||||
* It provides basic routines for tracing success or failure of tests,
|
||||
|
@ -28,8 +43,7 @@
|
|||
* \endcode
|
||||
|
||||
*/
|
||||
class UnitTest
|
||||
{
|
||||
class UnitTest {
|
||||
public:
|
||||
//! Constructor
|
||||
UnitTest();
|
||||
|
@ -38,13 +52,13 @@ public:
|
|||
virtual ~UnitTest();
|
||||
|
||||
//! Indicate a passed test (thread-safe)
|
||||
virtual void passes( const std::string &in );
|
||||
virtual void passes(const std::string &in);
|
||||
|
||||
//! Indicate a failed test (thread-safe)
|
||||
virtual void failure( const std::string &in );
|
||||
virtual void failure(const std::string &in);
|
||||
|
||||
//! Indicate an expected failed test (thread-safe)
|
||||
virtual void expected_failure( const std::string &in );
|
||||
virtual void expected_failure(const std::string &in);
|
||||
|
||||
//! Return the number of passed tests locally
|
||||
virtual size_t NumPassLocal() const { return pass_messages.size(); }
|
||||
|
@ -53,7 +67,9 @@ public:
|
|||
virtual size_t NumFailLocal() const { return fail_messages.size(); }
|
||||
|
||||
//! Return the number of expected failed tests locally
|
||||
virtual size_t NumExpectedFailLocal() const { return expected_fail_messages.size(); }
|
||||
virtual size_t NumExpectedFailLocal() const {
|
||||
return expected_fail_messages.size();
|
||||
}
|
||||
|
||||
//! Return the number of passed tests locally
|
||||
virtual size_t NumPassGlobal() const;
|
||||
|
@ -82,7 +98,7 @@ public:
|
|||
* failed tests (if <=50) or the number passed otherwise.
|
||||
* 2: Report all passed, failed, and expected failed tests.
|
||||
*/
|
||||
virtual void report( const int level = 1 ) const;
|
||||
virtual void report(const int level = 1) const;
|
||||
|
||||
//! Clear the messages
|
||||
void reset();
|
||||
|
@ -98,23 +114,24 @@ protected:
|
|||
|
||||
private:
|
||||
// Make the copy constructor private
|
||||
UnitTest( const UnitTest & ) {}
|
||||
UnitTest(const UnitTest &) {}
|
||||
|
||||
// Function to pack the messages into a single data stream and send to the given processor
|
||||
// Note: This function does not return until the message stream has been sent
|
||||
void pack_message_stream(
|
||||
const std::vector<std::string> &messages, const int rank, const int tag ) const;
|
||||
void pack_message_stream(const std::vector<std::string> &messages,
|
||||
const int rank, const int tag) const;
|
||||
|
||||
// Function to unpack the messages from a single data stream
|
||||
// Note: This function does not return until the message stream has been received
|
||||
std::vector<std::string> unpack_message_stream( const int rank, const int tag ) const;
|
||||
std::vector<std::string> unpack_message_stream(const int rank,
|
||||
const int tag) const;
|
||||
|
||||
// Helper functions
|
||||
inline void barrier() const;
|
||||
inline std::vector<int> allGather( int value ) const;
|
||||
inline std::vector<std::vector<std::string>> gatherMessages(
|
||||
const std::vector<std::string> &local_messages, int tag ) const;
|
||||
inline std::vector<int> allGather(int value) const;
|
||||
inline std::vector<std::vector<std::string>>
|
||||
gatherMessages(const std::vector<std::string> &local_messages,
|
||||
int tag) const;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
184
common/Units.cpp
184
common/Units.cpp
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "common/Units.h"
|
||||
#include "common/Utilities.h"
|
||||
|
||||
|
@ -5,134 +21,126 @@
|
|||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
|
||||
constexpr double Units::d_pow10[22];
|
||||
constexpr char Units::d_prefixSymbol[];
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Constructors *
|
||||
********************************************************************/
|
||||
Units::Units() : d_prefix( UnitPrefix::unknown ), d_unit( UnitValue::unknown ) {}
|
||||
Units::Units( UnitPrefix p, UnitValue u ) : d_prefix( p ), d_unit( u ) {}
|
||||
Units::Units( const std::string& unit )
|
||||
: d_prefix( UnitPrefix::unknown ), d_unit( UnitValue::unknown )
|
||||
{
|
||||
Units::Units() : d_prefix(UnitPrefix::unknown), d_unit(UnitValue::unknown) {}
|
||||
Units::Units(UnitPrefix p, UnitValue u) : d_prefix(p), d_unit(u) {}
|
||||
Units::Units(const std::string &unit)
|
||||
: d_prefix(UnitPrefix::unknown), d_unit(UnitValue::unknown) {
|
||||
// Parse the string to get it into a more friendly format
|
||||
auto tmp = unit;
|
||||
tmp.erase( std::remove( tmp.begin(), tmp.end(), ' ' ), tmp.end() );
|
||||
tmp.erase(std::remove(tmp.begin(), tmp.end(), ' '), tmp.end());
|
||||
// Check if the character '-' is present indicating a seperation between the prefix and unit
|
||||
size_t index = tmp.find( '-' );
|
||||
if ( index != std::string::npos ) {
|
||||
d_prefix = getUnitPrefix( tmp.substr( 0, index ) );
|
||||
d_unit = getUnitValue( tmp.substr( index + 1 ) );
|
||||
size_t index = tmp.find('-');
|
||||
if (index != std::string::npos) {
|
||||
d_prefix = getUnitPrefix(tmp.substr(0, index));
|
||||
d_unit = getUnitValue(tmp.substr(index + 1));
|
||||
} else {
|
||||
if ( tmp.size() <= 1 ) {
|
||||
if (tmp.size() <= 1) {
|
||||
d_prefix = UnitPrefix::none;
|
||||
d_unit = getUnitValue( tmp );
|
||||
} else if ( tmp.substr( 0, 2 ) == "da" ) {
|
||||
d_unit = getUnitValue(tmp);
|
||||
} else if (tmp.substr(0, 2) == "da") {
|
||||
d_prefix = UnitPrefix::deca;
|
||||
d_unit = getUnitValue( tmp.substr( 2 ) );
|
||||
d_unit = getUnitValue(tmp.substr(2));
|
||||
} else {
|
||||
d_prefix = getUnitPrefix( tmp.substr( 0, 1 ) );
|
||||
d_unit = getUnitValue( tmp.substr( 1 ) );
|
||||
if ( d_prefix == UnitPrefix::unknown || d_unit == UnitValue::unknown ) {
|
||||
d_prefix = getUnitPrefix(tmp.substr(0, 1));
|
||||
d_unit = getUnitValue(tmp.substr(1));
|
||||
if (d_prefix == UnitPrefix::unknown ||
|
||||
d_unit == UnitValue::unknown) {
|
||||
d_prefix = UnitPrefix::none;
|
||||
d_unit = getUnitValue( tmp );
|
||||
d_unit = getUnitValue(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Get prefix *
|
||||
********************************************************************/
|
||||
Units::UnitPrefix Units::getUnitPrefix( const std::string& str ) noexcept
|
||||
{
|
||||
Units::UnitPrefix Units::getUnitPrefix(const std::string &str) noexcept {
|
||||
Units::UnitPrefix value = UnitPrefix::unknown;
|
||||
if ( str.empty() ) {
|
||||
if (str.empty()) {
|
||||
value = UnitPrefix::none;
|
||||
} else if ( str == "yotta" || str == "Y" ) {
|
||||
} else if (str == "yotta" || str == "Y") {
|
||||
value = UnitPrefix::yotta;
|
||||
} else if ( str == "zetta" || str == "Z" ) {
|
||||
} else if (str == "zetta" || str == "Z") {
|
||||
value = UnitPrefix::zetta;
|
||||
} else if ( str == "exa" || str == "E" ) {
|
||||
} else if (str == "exa" || str == "E") {
|
||||
value = UnitPrefix::exa;
|
||||
} else if ( str == "peta" || str == "P" ) {
|
||||
} else if (str == "peta" || str == "P") {
|
||||
value = UnitPrefix::peta;
|
||||
} else if ( str == "tera" || str == "T" ) {
|
||||
} else if (str == "tera" || str == "T") {
|
||||
value = UnitPrefix::tera;
|
||||
} else if ( str == "giga" || str == "G" ) {
|
||||
} else if (str == "giga" || str == "G") {
|
||||
value = UnitPrefix::giga;
|
||||
} else if ( str == "mega" || str == "M" ) {
|
||||
} else if (str == "mega" || str == "M") {
|
||||
value = UnitPrefix::mega;
|
||||
} else if ( str == "kilo" || str == "k" ) {
|
||||
} else if (str == "kilo" || str == "k") {
|
||||
value = UnitPrefix::kilo;
|
||||
} else if ( str == "hecto" || str == "h" ) {
|
||||
} else if (str == "hecto" || str == "h") {
|
||||
value = UnitPrefix::hecto;
|
||||
} else if ( str == "deca" || str == "da" ) {
|
||||
} else if (str == "deca" || str == "da") {
|
||||
value = UnitPrefix::deca;
|
||||
} else if ( str == "deci" || str == "d" ) {
|
||||
} else if (str == "deci" || str == "d") {
|
||||
value = UnitPrefix::deci;
|
||||
} else if ( str == "centi" || str == "c" ) {
|
||||
} else if (str == "centi" || str == "c") {
|
||||
value = UnitPrefix::centi;
|
||||
} else if ( str == "milli" || str == "m" ) {
|
||||
} else if (str == "milli" || str == "m") {
|
||||
value = UnitPrefix::milli;
|
||||
} else if ( str == "micro" || str == "u" ) {
|
||||
} else if (str == "micro" || str == "u") {
|
||||
value = UnitPrefix::micro;
|
||||
} else if ( str == "nano" || str == "n" ) {
|
||||
} else if (str == "nano" || str == "n") {
|
||||
value = UnitPrefix::nano;
|
||||
} else if ( str == "pico" || str == "p" ) {
|
||||
} else if (str == "pico" || str == "p") {
|
||||
value = UnitPrefix::pico;
|
||||
} else if ( str == "femto" || str == "f" ) {
|
||||
} else if (str == "femto" || str == "f") {
|
||||
value = UnitPrefix::femto;
|
||||
} else if ( str == "atto" || str == "a" ) {
|
||||
} else if (str == "atto" || str == "a") {
|
||||
value = UnitPrefix::atto;
|
||||
} else if ( str == "zepto" || str == "z" ) {
|
||||
} else if (str == "zepto" || str == "z") {
|
||||
value = UnitPrefix::zepto;
|
||||
} else if ( str == "yocto" || str == "y" ) {
|
||||
} else if (str == "yocto" || str == "y") {
|
||||
value = UnitPrefix::yocto;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Get unit value *
|
||||
********************************************************************/
|
||||
Units::UnitValue Units::getUnitValue( const std::string& str ) noexcept
|
||||
{
|
||||
Units::UnitValue Units::getUnitValue(const std::string &str) noexcept {
|
||||
Units::UnitValue value = UnitValue::unknown;
|
||||
if ( str == "meter" || str == "m" ) {
|
||||
if (str == "meter" || str == "m") {
|
||||
value = UnitValue::meter;
|
||||
} else if ( str == "gram" || str == "g" ) {
|
||||
} else if (str == "gram" || str == "g") {
|
||||
value = UnitValue::gram;
|
||||
} else if ( str == "second" || str == "s" ) {
|
||||
} else if (str == "second" || str == "s") {
|
||||
value = UnitValue::second;
|
||||
} else if ( str == "ampere" || str == "A" ) {
|
||||
} else if (str == "ampere" || str == "A") {
|
||||
value = UnitValue::ampere;
|
||||
} else if ( str == "kelvin" || str == "K" ) {
|
||||
} else if (str == "kelvin" || str == "K") {
|
||||
value = UnitValue::kelvin;
|
||||
} else if ( str == "joule" || str == "J" ) {
|
||||
} else if (str == "joule" || str == "J") {
|
||||
value = UnitValue::joule;
|
||||
} else if ( str == "ergs" || str == "erg" ) {
|
||||
} else if (str == "ergs" || str == "erg") {
|
||||
value = UnitValue::erg;
|
||||
} else if ( str == "degree" || str == "degrees" ) {
|
||||
} else if (str == "degree" || str == "degrees") {
|
||||
value = UnitValue::degree;
|
||||
} else if ( str == "radian" || str == "radians" ) {
|
||||
} else if (str == "radian" || str == "radians") {
|
||||
value = UnitValue::radian;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Get unit type *
|
||||
********************************************************************/
|
||||
Units::UnitType Units::getUnitType( UnitValue u ) noexcept
|
||||
{
|
||||
switch ( u ) {
|
||||
Units::UnitType Units::getUnitType(UnitValue u) noexcept {
|
||||
switch (u) {
|
||||
case UnitValue::meter:
|
||||
return UnitType::length;
|
||||
case UnitValue::gram:
|
||||
|
@ -154,72 +162,66 @@ Units::UnitType Units::getUnitType( UnitValue u ) noexcept
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Convert to another unit system *
|
||||
********************************************************************/
|
||||
double Units::convert( const Units& rhs ) const noexcept
|
||||
{
|
||||
if ( this->operator==( rhs ) )
|
||||
double Units::convert(const Units &rhs) const noexcept {
|
||||
if (this->operator==(rhs))
|
||||
return 1;
|
||||
// Convert the prefix
|
||||
double cp = convert( d_prefix ) / convert( rhs.d_prefix );
|
||||
if ( d_unit == rhs.d_unit )
|
||||
double cp = convert(d_prefix) / convert(rhs.d_prefix);
|
||||
if (d_unit == rhs.d_unit)
|
||||
return cp; // Only need to convert prefix
|
||||
// Convert the unit
|
||||
if ( getUnitType( d_unit ) != getUnitType( rhs.d_unit ) )
|
||||
if (getUnitType(d_unit) != getUnitType(rhs.d_unit))
|
||||
return 0; // Invalid conversion
|
||||
double cu = 0;
|
||||
if ( d_unit == UnitValue::joule && rhs.d_unit == UnitValue::erg )
|
||||
if (d_unit == UnitValue::joule && rhs.d_unit == UnitValue::erg)
|
||||
cu = 1e7;
|
||||
else if ( d_unit == UnitValue::erg && rhs.d_unit == UnitValue::joule )
|
||||
else if (d_unit == UnitValue::erg && rhs.d_unit == UnitValue::joule)
|
||||
cu = 1e-7;
|
||||
else if ( d_unit == UnitValue::degree && rhs.d_unit == UnitValue::radian )
|
||||
else if (d_unit == UnitValue::degree && rhs.d_unit == UnitValue::radian)
|
||||
cu = 0.017453292519943;
|
||||
else if ( d_unit == UnitValue::radian && rhs.d_unit == UnitValue::degree )
|
||||
else if (d_unit == UnitValue::radian && rhs.d_unit == UnitValue::degree)
|
||||
cu = 57.295779513082323;
|
||||
// Return the total conversion
|
||||
return cp * cu;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Write a string for the units *
|
||||
********************************************************************/
|
||||
std::string Units::str() const
|
||||
{
|
||||
ASSERT( !isNull() );
|
||||
return std::string( str( d_prefix ).data() ) + str( d_unit );
|
||||
std::string Units::str() const {
|
||||
ASSERT(!isNull());
|
||||
return std::string(str(d_prefix).data()) + str(d_unit);
|
||||
}
|
||||
std::array<char, 3> Units::str( UnitPrefix p ) noexcept
|
||||
{
|
||||
std::array<char, 3> Units::str(UnitPrefix p) noexcept {
|
||||
std::array<char, 3> str;
|
||||
str[0] = d_prefixSymbol[static_cast<int8_t>( p )];
|
||||
str[0] = d_prefixSymbol[static_cast<int8_t>(p)];
|
||||
str[1] = 0;
|
||||
str[2] = 0;
|
||||
if ( p == UnitPrefix::deca )
|
||||
if (p == UnitPrefix::deca)
|
||||
str[1] = 'a';
|
||||
return str;
|
||||
}
|
||||
std::string Units::str( UnitValue u )
|
||||
{
|
||||
if ( u == UnitValue::meter ) {
|
||||
std::string Units::str(UnitValue u) {
|
||||
if (u == UnitValue::meter) {
|
||||
return "m";
|
||||
} else if ( u == UnitValue::gram ) {
|
||||
} else if (u == UnitValue::gram) {
|
||||
return "g";
|
||||
} else if ( u == UnitValue::second ) {
|
||||
} else if (u == UnitValue::second) {
|
||||
return "s";
|
||||
} else if ( u == UnitValue::ampere ) {
|
||||
} else if (u == UnitValue::ampere) {
|
||||
return "A";
|
||||
} else if ( u == UnitValue::kelvin ) {
|
||||
} else if (u == UnitValue::kelvin) {
|
||||
return "K";
|
||||
} else if ( u == UnitValue::joule ) {
|
||||
} else if (u == UnitValue::joule) {
|
||||
return "J";
|
||||
} else if ( u == UnitValue::erg ) {
|
||||
} else if (u == UnitValue::erg) {
|
||||
return "erg";
|
||||
} else if ( u == UnitValue::degree ) {
|
||||
} else if (u == UnitValue::degree) {
|
||||
return "degree";
|
||||
} else if ( u == UnitValue::radian ) {
|
||||
} else if (u == UnitValue::radian) {
|
||||
return "radian";
|
||||
}
|
||||
return "unknown";
|
||||
|
|
101
common/Units.h
101
common/Units.h
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef included_Units
|
||||
#define included_Units
|
||||
|
||||
|
@ -8,34 +24,32 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
//! Unit system class
|
||||
class Units final
|
||||
{
|
||||
class Units final {
|
||||
public:
|
||||
//! Enum to hold prefix
|
||||
enum class UnitPrefix : int8_t {
|
||||
yocto = 0,
|
||||
zepto = 1,
|
||||
atto = 2,
|
||||
femto = 3,
|
||||
pico = 4,
|
||||
nano = 5,
|
||||
micro = 6,
|
||||
milli = 7,
|
||||
centi = 8,
|
||||
deci = 9,
|
||||
none = 10,
|
||||
deca = 11,
|
||||
hecto = 12,
|
||||
kilo = 13,
|
||||
mega = 14,
|
||||
giga = 15,
|
||||
tera = 16,
|
||||
peta = 17,
|
||||
exa = 18,
|
||||
zetta = 19,
|
||||
yotta = 20,
|
||||
yocto = 0,
|
||||
zepto = 1,
|
||||
atto = 2,
|
||||
femto = 3,
|
||||
pico = 4,
|
||||
nano = 5,
|
||||
micro = 6,
|
||||
milli = 7,
|
||||
centi = 8,
|
||||
deci = 9,
|
||||
none = 10,
|
||||
deca = 11,
|
||||
hecto = 12,
|
||||
kilo = 13,
|
||||
mega = 14,
|
||||
giga = 15,
|
||||
tera = 16,
|
||||
peta = 17,
|
||||
exa = 18,
|
||||
zetta = 19,
|
||||
yotta = 20,
|
||||
unknown = 21
|
||||
};
|
||||
|
||||
|
@ -65,16 +79,15 @@ public:
|
|||
unknown
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
//! Constructor
|
||||
Units();
|
||||
|
||||
//! Constructor
|
||||
explicit Units( const std::string& unit );
|
||||
explicit Units(const std::string &unit);
|
||||
|
||||
//! Constructor
|
||||
explicit Units( UnitPrefix, UnitValue );
|
||||
explicit Units(UnitPrefix, UnitValue);
|
||||
|
||||
//! Get the prefix
|
||||
inline UnitPrefix getPrefix() const noexcept { return d_prefix; }
|
||||
|
@ -83,57 +96,57 @@ public:
|
|||
inline UnitValue getUnit() const noexcept { return d_unit; }
|
||||
|
||||
//! Get the unit
|
||||
inline UnitType getUnitType() const noexcept { return getUnitType( d_unit ); }
|
||||
inline UnitType getUnitType() const noexcept { return getUnitType(d_unit); }
|
||||
|
||||
//! Get the unit
|
||||
static UnitType getUnitType( UnitValue ) noexcept;
|
||||
static UnitType getUnitType(UnitValue) noexcept;
|
||||
|
||||
//! Get the prefix from a string
|
||||
static UnitPrefix getUnitPrefix( const std::string& ) noexcept;
|
||||
static UnitPrefix getUnitPrefix(const std::string &) noexcept;
|
||||
|
||||
//! Get the unit value from a string
|
||||
static UnitValue getUnitValue( const std::string& ) noexcept;
|
||||
static UnitValue getUnitValue(const std::string &) noexcept;
|
||||
|
||||
//! Convert to the given unit system
|
||||
double convert( const Units& ) const noexcept;
|
||||
double convert(const Units &) const noexcept;
|
||||
|
||||
//! Convert a prefix to a scalar
|
||||
static inline double convert( UnitPrefix x ) noexcept
|
||||
{
|
||||
return d_pow10[static_cast<int8_t>( x )];
|
||||
static inline double convert(UnitPrefix x) noexcept {
|
||||
return d_pow10[static_cast<int8_t>(x)];
|
||||
}
|
||||
|
||||
//! Get a string representation of the units
|
||||
std::string str() const;
|
||||
|
||||
//! Get a string representation for the prefix
|
||||
static std::array<char, 3> str( UnitPrefix ) noexcept;
|
||||
static std::array<char, 3> str(UnitPrefix) noexcept;
|
||||
|
||||
//! Get a string representation for the unit value
|
||||
static std::string str( UnitValue );
|
||||
static std::string str(UnitValue);
|
||||
|
||||
//! Operator ==
|
||||
inline bool operator==( const Units& rhs ) const noexcept
|
||||
{
|
||||
inline bool operator==(const Units &rhs) const noexcept {
|
||||
return d_prefix == rhs.d_prefix && d_unit == rhs.d_unit;
|
||||
}
|
||||
|
||||
//! Operator !=
|
||||
inline bool operator!=( const Units& rhs ) const noexcept
|
||||
{
|
||||
inline bool operator!=(const Units &rhs) const noexcept {
|
||||
return d_prefix != rhs.d_prefix || d_unit != rhs.d_unit;
|
||||
}
|
||||
|
||||
//! Check if unit is null
|
||||
bool isNull() const { return d_prefix == UnitPrefix::unknown || d_unit == UnitValue::unknown; }
|
||||
bool isNull() const {
|
||||
return d_prefix == UnitPrefix::unknown || d_unit == UnitValue::unknown;
|
||||
}
|
||||
|
||||
protected:
|
||||
UnitPrefix d_prefix;
|
||||
UnitValue d_unit;
|
||||
|
||||
private:
|
||||
constexpr static double d_pow10[22] = { 1e-24, 1e-21, 1e-18, 1e-15, 1e-12, 1e-9, 1e-6, 1e-3,
|
||||
1e-2, 0.1, 1, 10, 100, 1000, 1e6, 1e9, 1e12, 1e15, 1e18, 1e21, 1e24, 0 };
|
||||
constexpr static double d_pow10[22] = {
|
||||
1e-24, 1e-21, 1e-18, 1e-15, 1e-12, 1e-9, 1e-6, 1e-3, 1e-2, 0.1, 1,
|
||||
10, 100, 1000, 1e6, 1e9, 1e12, 1e15, 1e18, 1e21, 1e24, 0};
|
||||
constexpr static char d_prefixSymbol[] = "yzafpnumcd\0dhkMGTPEZYu";
|
||||
};
|
||||
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "common/Utilities.h"
|
||||
#include "StackTrace/StackTrace.h"
|
||||
#include "StackTrace/ErrorHandlers.h"
|
||||
|
@ -15,7 +31,6 @@
|
|||
#include <math.h>
|
||||
#include <mutex>
|
||||
|
||||
|
||||
// OS specific includes / definitions
|
||||
// clang-format off
|
||||
#if defined( WIN32 ) || defined( _WIN32 ) || defined( WIN64 ) || defined( _WIN64 )
|
||||
|
@ -29,162 +44,150 @@
|
|||
#endif
|
||||
// clang-format on
|
||||
|
||||
|
||||
// Mutex for Utility functions
|
||||
static std::mutex Utilities_mutex;
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Function to perform the default startup/shutdown sequences *
|
||||
****************************************************************************/
|
||||
void Utilities::startup( int argc, char **argv, bool multiple )
|
||||
{
|
||||
NULL_USE( argc );
|
||||
NULL_USE( argv );
|
||||
void Utilities::startup(int argc, char **argv, bool multiple) {
|
||||
NULL_USE(argc);
|
||||
NULL_USE(argv);
|
||||
// Disable OpenMP
|
||||
Utilities::setenv( "OMP_NUM_THREADS", "1" );
|
||||
Utilities::setenv( "MKL_NUM_THREADS", "1" );
|
||||
Utilities::setenv("OMP_NUM_THREADS", "1");
|
||||
Utilities::setenv("MKL_NUM_THREADS", "1");
|
||||
// Start MPI
|
||||
#ifdef USE_MPI
|
||||
if ( multiple ) {
|
||||
if (multiple) {
|
||||
int provided;
|
||||
MPI_Init_thread( &argc, &argv, MPI_THREAD_MULTIPLE, &provided );
|
||||
if ( provided < MPI_THREAD_MULTIPLE ) {
|
||||
MPI_Init_thread(&argc, &argv, MPI_THREAD_MULTIPLE, &provided);
|
||||
if (provided < MPI_THREAD_MULTIPLE) {
|
||||
int rank;
|
||||
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
|
||||
if ( rank == 0 )
|
||||
std::cerr << "Warning: Failed to start MPI with necessary thread support, thread support will be disabled" << std::endl;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
||||
if (rank == 0)
|
||||
std::cerr << "Warning: Failed to start MPI with necessary "
|
||||
"thread support, thread support will be disabled"
|
||||
<< std::endl;
|
||||
}
|
||||
StackTrace::globalCallStackInitialize( MPI_COMM_WORLD );
|
||||
StackTrace::globalCallStackInitialize(MPI_COMM_WORLD);
|
||||
} else {
|
||||
MPI_Init( &argc, &argv );
|
||||
MPI_Init(&argc, &argv);
|
||||
}
|
||||
#endif
|
||||
// Set the error handlers
|
||||
Utilities::setAbortBehavior( true, 3 );
|
||||
Utilities::setAbortBehavior(true, 3);
|
||||
Utilities::setErrorHandlers();
|
||||
}
|
||||
void Utilities::shutdown()
|
||||
{
|
||||
void Utilities::shutdown() {
|
||||
// Clear the error handlers
|
||||
Utilities::clearErrorHandlers();
|
||||
StackTrace::clearSignals();
|
||||
StackTrace::clearSymbols();
|
||||
int rank = 0;
|
||||
#ifdef USE_MPI
|
||||
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
||||
StackTrace::globalCallStackFinalize();
|
||||
MPI_Barrier( MPI_COMM_WORLD );
|
||||
MPI_Barrier(MPI_COMM_WORLD);
|
||||
MPI_Finalize();
|
||||
#endif
|
||||
#ifdef USE_TIMER
|
||||
PROFILE_DISABLE();
|
||||
auto memory = MemoryApp::getMemoryStats();
|
||||
if ( rank == 0 && memory.N_new > memory.N_delete )
|
||||
MemoryApp::print( std::cout );
|
||||
if (rank == 0 && memory.N_new > memory.N_delete)
|
||||
MemoryApp::print(std::cout);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Function to set an environemental variable *
|
||||
****************************************************************************/
|
||||
void Utilities::setenv( const std::string &name, const std::string &value )
|
||||
{
|
||||
void Utilities::setenv(const std::string &name, const std::string &value) {
|
||||
Utilities_mutex.lock();
|
||||
#if defined( USE_LINUX ) || defined( USE_MAC )
|
||||
#if defined(USE_LINUX) || defined(USE_MAC)
|
||||
bool pass = false;
|
||||
if ( !value.empty() )
|
||||
pass = ::setenv( name.data(), value.data(), 1 ) == 0;
|
||||
if (!value.empty())
|
||||
pass = ::setenv(name.data(), value.data(), 1) == 0;
|
||||
else
|
||||
pass = ::unsetenv( name.data() ) == 0;
|
||||
#elif defined( USE_WINDOWS )
|
||||
bool pass = SetEnvironmentVariable( name.data(), value.data() ) != 0;
|
||||
pass = ::unsetenv(name.data()) == 0;
|
||||
#elif defined(USE_WINDOWS)
|
||||
bool pass = SetEnvironmentVariable(name.data(), value.data()) != 0;
|
||||
#else
|
||||
#error Unknown OS
|
||||
#endif
|
||||
Utilities_mutex.unlock();
|
||||
if ( !pass ) {
|
||||
if (!pass) {
|
||||
char msg[1024];
|
||||
if ( !value.empty() )
|
||||
sprintf(
|
||||
msg, "Error setting enviornmental variable: %s=%s\n", name.data(), value.data() );
|
||||
if (!value.empty())
|
||||
sprintf(msg, "Error setting enviornmental variable: %s=%s\n",
|
||||
name.data(), value.data());
|
||||
else
|
||||
sprintf( msg, "Error clearing enviornmental variable: %s\n", name.data() );
|
||||
ERROR( msg );
|
||||
sprintf(msg, "Error clearing enviornmental variable: %s\n",
|
||||
name.data());
|
||||
ERROR(msg);
|
||||
}
|
||||
}
|
||||
std::string Utilities::getenv( const std::string &name )
|
||||
{
|
||||
std::string Utilities::getenv(const std::string &name) {
|
||||
std::string var;
|
||||
Utilities_mutex.lock();
|
||||
auto tmp = std::getenv( name.data() );
|
||||
if ( tmp )
|
||||
var = std::string( tmp );
|
||||
auto tmp = std::getenv(name.data());
|
||||
if (tmp)
|
||||
var = std::string(tmp);
|
||||
Utilities_mutex.unlock();
|
||||
return var;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Factor a number into it's prime factors *
|
||||
****************************************************************************/
|
||||
std::vector<int> Utilities::factor(size_t number)
|
||||
{
|
||||
if ( number<=3 )
|
||||
return std::vector<int>(1,(int)number);
|
||||
std::vector<int> Utilities::factor(size_t number) {
|
||||
if (number <= 3)
|
||||
return std::vector<int>(1, (int)number);
|
||||
size_t i, n, n_max;
|
||||
bool factor_found;
|
||||
// Compute the maximum number of factors
|
||||
int N_primes_max = 1;
|
||||
n = number;
|
||||
while (n >>= 1) ++N_primes_max;
|
||||
// Initialize n, factors
|
||||
while (n >>= 1)
|
||||
++N_primes_max;
|
||||
// Initialize n, factors
|
||||
n = number;
|
||||
std::vector<int> factors;
|
||||
factors.reserve(N_primes_max);
|
||||
while ( 1 ) {
|
||||
while (1) {
|
||||
// Check if n is a trivial prime number
|
||||
if ( n==2 || n==3 || n==5 ) {
|
||||
factors.push_back( (int) n );
|
||||
if (n == 2 || n == 3 || n == 5) {
|
||||
factors.push_back((int)n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check if n is divisible by 2
|
||||
if ( n%2 == 0 ) {
|
||||
factors.push_back( 2 );
|
||||
n/=2;
|
||||
if (n % 2 == 0) {
|
||||
factors.push_back(2);
|
||||
n /= 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Check each odd number until a factor is reached
|
||||
n_max = (size_t) floor(sqrt((double) n));
|
||||
n_max = (size_t)floor(sqrt((double)n));
|
||||
factor_found = false;
|
||||
for (i=3; i<=n_max; i+=2) {
|
||||
if ( n%i == 0 ) {
|
||||
factors.push_back( i );
|
||||
n/=i;
|
||||
for (i = 3; i <= n_max; i += 2) {
|
||||
if (n % i == 0) {
|
||||
factors.push_back(i);
|
||||
n /= i;
|
||||
factor_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( factor_found )
|
||||
if (factor_found)
|
||||
continue;
|
||||
// No factors were found, the number must be prime
|
||||
factors.push_back( (int) n );
|
||||
factors.push_back((int)n);
|
||||
break;
|
||||
}
|
||||
// Sort the factors
|
||||
std::sort( factors.begin(), factors.end() );
|
||||
std::sort(factors.begin(), factors.end());
|
||||
return factors;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Dummy function to prevent compiler from optimizing away variable *
|
||||
****************************************************************************/
|
||||
void Utilities::nullUse( void* data )
|
||||
{
|
||||
NULL_USE(data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Utilities::nullUse(void *data) { NULL_USE(data); }
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef included_Utilities
|
||||
#define included_Utilities
|
||||
|
||||
|
@ -6,10 +22,8 @@
|
|||
|
||||
#include "StackTrace/Utilities.h"
|
||||
|
||||
|
||||
namespace Utilities {
|
||||
|
||||
|
||||
// Functions inherited from StackTrace::Utilities
|
||||
using StackTrace::Utilities::abort;
|
||||
using StackTrace::Utilities::cause_segfault;
|
||||
|
@ -19,19 +33,19 @@ using StackTrace::Utilities::getMemoryUsage;
|
|||
using StackTrace::Utilities::getSystemMemory;
|
||||
using StackTrace::Utilities::setAbortBehavior;
|
||||
using StackTrace::Utilities::setErrorHandlers;
|
||||
using StackTrace::Utilities::tick;
|
||||
using StackTrace::Utilities::time;
|
||||
using StackTrace::Utilities::sleep_ms;
|
||||
using StackTrace::Utilities::sleep_s;
|
||||
|
||||
using StackTrace::Utilities::tick;
|
||||
using StackTrace::Utilities::time;
|
||||
|
||||
/*!
|
||||
* \brief Start MPI, error handlers
|
||||
* \details This routine will peform the default startup sequence
|
||||
* \param argc argc from main
|
||||
* \param argv argv from main
|
||||
* \param multiple Intialize mpi with MPI_THREAD_MULTIPLE support?
|
||||
*/
|
||||
void startup( int argc, char **argv, bool multiple=true );
|
||||
void startup(int argc, char **argv, bool multiple = true);
|
||||
|
||||
/*!
|
||||
* \brief Stop MPI, error handlers
|
||||
|
@ -39,51 +53,41 @@ void startup( int argc, char **argv, bool multiple=true );
|
|||
*/
|
||||
void shutdown();
|
||||
|
||||
|
||||
/*!
|
||||
* Get an environmental variable
|
||||
* @param name The name of the environmental variable
|
||||
* @return The value of the enviornmental variable
|
||||
*/
|
||||
std::string getenv( const std::string &name );
|
||||
|
||||
std::string getenv(const std::string &name);
|
||||
|
||||
/*!
|
||||
* Set an environmental variable
|
||||
* @param name The name of the environmental variable
|
||||
* @param value The value to set
|
||||
*/
|
||||
void setenv( const std::string &name, const std::string &value );
|
||||
|
||||
void setenv(const std::string &name, const std::string &value);
|
||||
|
||||
//! std::string version of sprintf
|
||||
inline std::string stringf( const char *format, ... );
|
||||
|
||||
inline std::string stringf(const char *format, ...);
|
||||
|
||||
//! Factor a number into it's prime factors
|
||||
std::vector<int> factor(size_t number);
|
||||
|
||||
|
||||
//! Null use function
|
||||
void nullUse( void* );
|
||||
|
||||
void nullUse(void *);
|
||||
|
||||
} // namespace Utilities
|
||||
|
||||
|
||||
#include "common/UtilityMacros.h"
|
||||
|
||||
|
||||
// stringf
|
||||
inline std::string Utilities::stringf( const char *format, ... )
|
||||
{
|
||||
inline std::string Utilities::stringf(const char *format, ...) {
|
||||
va_list ap;
|
||||
va_start( ap, format );
|
||||
va_start(ap, format);
|
||||
char tmp[4096];
|
||||
vsprintf( tmp, format, ap );
|
||||
va_end( ap );
|
||||
return std::string( tmp );
|
||||
vsprintf(tmp, format, ap);
|
||||
va_end(ap);
|
||||
return std::string(tmp);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,108 +1,104 @@
|
|||
#ifndef included_Utilities_hpp
|
||||
#define included_Utilities_hpp
|
||||
|
||||
|
||||
#include "Utilities.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace Utilities {
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* templated quicksort routines *
|
||||
************************************************************************/
|
||||
template<class T>
|
||||
void quicksort( std::vector<T> &x )
|
||||
{
|
||||
if ( x.size() <= 1u )
|
||||
template <class T> void quicksort(std::vector<T> &x) {
|
||||
if (x.size() <= 1u)
|
||||
return;
|
||||
T *arr = &x[0];
|
||||
bool test;
|
||||
long int i, ir, j, jstack, k, l, istack[100];
|
||||
T a, tmp_a;
|
||||
jstack = 0;
|
||||
l = 0;
|
||||
ir = x.size() - 1;
|
||||
while ( 1 ) {
|
||||
if ( ir - l < 7 ) { // Insertion sort when subarray small enough.
|
||||
for ( j = l + 1; j <= ir; j++ ) {
|
||||
a = arr[j];
|
||||
l = 0;
|
||||
ir = x.size() - 1;
|
||||
while (1) {
|
||||
if (ir - l < 7) { // Insertion sort when subarray small enough.
|
||||
for (j = l + 1; j <= ir; j++) {
|
||||
a = arr[j];
|
||||
test = true;
|
||||
for ( i = j - 1; i >= 0; i-- ) {
|
||||
if ( arr[i] < a ) {
|
||||
for (i = j - 1; i >= 0; i--) {
|
||||
if (arr[i] < a) {
|
||||
arr[i + 1] = a;
|
||||
test = false;
|
||||
test = false;
|
||||
break;
|
||||
}
|
||||
arr[i + 1] = arr[i];
|
||||
}
|
||||
if ( test ) {
|
||||
i = l - 1;
|
||||
if (test) {
|
||||
i = l - 1;
|
||||
arr[i + 1] = a;
|
||||
}
|
||||
}
|
||||
if ( jstack == 0 )
|
||||
if (jstack == 0)
|
||||
return;
|
||||
ir = istack[jstack]; // Pop stack and begin a new round of partitioning.
|
||||
l = istack[jstack - 1];
|
||||
ir = istack
|
||||
[jstack]; // Pop stack and begin a new round of partitioning.
|
||||
l = istack[jstack - 1];
|
||||
jstack -= 2;
|
||||
} else {
|
||||
k = ( l + ir ) / 2; // Choose median of left, center and right elements as partitioning
|
||||
// element a. Also rearrange so that a(l) < a(l+1) < a(ir).
|
||||
tmp_a = arr[k];
|
||||
arr[k] = arr[l + 1];
|
||||
k = (l + ir) /
|
||||
2; // Choose median of left, center and right elements as partitioning
|
||||
// element a. Also rearrange so that a(l) < a(l+1) < a(ir).
|
||||
tmp_a = arr[k];
|
||||
arr[k] = arr[l + 1];
|
||||
arr[l + 1] = tmp_a;
|
||||
if ( arr[l] > arr[ir] ) {
|
||||
tmp_a = arr[l];
|
||||
arr[l] = arr[ir];
|
||||
if (arr[l] > arr[ir]) {
|
||||
tmp_a = arr[l];
|
||||
arr[l] = arr[ir];
|
||||
arr[ir] = tmp_a;
|
||||
}
|
||||
if ( arr[l + 1] > arr[ir] ) {
|
||||
tmp_a = arr[l + 1];
|
||||
if (arr[l + 1] > arr[ir]) {
|
||||
tmp_a = arr[l + 1];
|
||||
arr[l + 1] = arr[ir];
|
||||
arr[ir] = tmp_a;
|
||||
arr[ir] = tmp_a;
|
||||
}
|
||||
if ( arr[l] > arr[l + 1] ) {
|
||||
tmp_a = arr[l];
|
||||
arr[l] = arr[l + 1];
|
||||
if (arr[l] > arr[l + 1]) {
|
||||
tmp_a = arr[l];
|
||||
arr[l] = arr[l + 1];
|
||||
arr[l + 1] = tmp_a;
|
||||
}
|
||||
// Scan up to find element > a
|
||||
j = ir;
|
||||
a = arr[l + 1]; // Partitioning element.
|
||||
for ( i = l + 2; i <= ir; i++ ) {
|
||||
if ( arr[i] < a )
|
||||
for (i = l + 2; i <= ir; i++) {
|
||||
if (arr[i] < a)
|
||||
continue;
|
||||
while ( arr[j] > a ) // Scan down to find element < a.
|
||||
while (arr[j] > a) // Scan down to find element < a.
|
||||
j--;
|
||||
if ( j < i )
|
||||
break; // Pointers crossed. Exit with partitioning complete.
|
||||
tmp_a = arr[i]; // Exchange elements of both arrays.
|
||||
if (j < i)
|
||||
break; // Pointers crossed. Exit with partitioning complete.
|
||||
tmp_a = arr[i]; // Exchange elements of both arrays.
|
||||
arr[i] = arr[j];
|
||||
arr[j] = tmp_a;
|
||||
}
|
||||
arr[l + 1] = arr[j]; // Insert partitioning element in both arrays.
|
||||
arr[j] = a;
|
||||
arr[j] = a;
|
||||
jstack += 2;
|
||||
// Push pointers to larger subarray on stack, process smaller subarray immediately.
|
||||
if ( ir - i + 1 >= j - l ) {
|
||||
istack[jstack] = ir;
|
||||
if (ir - i + 1 >= j - l) {
|
||||
istack[jstack] = ir;
|
||||
istack[jstack - 1] = i;
|
||||
ir = j - 1;
|
||||
ir = j - 1;
|
||||
} else {
|
||||
istack[jstack] = j - 1;
|
||||
istack[jstack] = j - 1;
|
||||
istack[jstack - 1] = l;
|
||||
l = i;
|
||||
l = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
template<class T1, class T2>
|
||||
void quicksort( std::vector<T1> &x, std::vector<T2> &y )
|
||||
{
|
||||
if ( x.size() <= 1u )
|
||||
template <class T1, class T2>
|
||||
void quicksort(std::vector<T1> &x, std::vector<T2> &y) {
|
||||
if (x.size() <= 1u)
|
||||
return;
|
||||
T1 *arr = &x[0];
|
||||
T2 *brr = &y[0];
|
||||
|
@ -111,124 +107,123 @@ void quicksort( std::vector<T1> &x, std::vector<T2> &y )
|
|||
T1 a, tmp_a;
|
||||
T2 b, tmp_b;
|
||||
jstack = 0;
|
||||
l = 0;
|
||||
ir = x.size() - 1;
|
||||
while ( 1 ) {
|
||||
if ( ir - l < 7 ) { // Insertion sort when subarray small enough.
|
||||
for ( j = l + 1; j <= ir; j++ ) {
|
||||
a = arr[j];
|
||||
b = brr[j];
|
||||
l = 0;
|
||||
ir = x.size() - 1;
|
||||
while (1) {
|
||||
if (ir - l < 7) { // Insertion sort when subarray small enough.
|
||||
for (j = l + 1; j <= ir; j++) {
|
||||
a = arr[j];
|
||||
b = brr[j];
|
||||
test = true;
|
||||
for ( i = j - 1; i >= 0; i-- ) {
|
||||
if ( arr[i] < a ) {
|
||||
for (i = j - 1; i >= 0; i--) {
|
||||
if (arr[i] < a) {
|
||||
arr[i + 1] = a;
|
||||
brr[i + 1] = b;
|
||||
test = false;
|
||||
test = false;
|
||||
break;
|
||||
}
|
||||
arr[i + 1] = arr[i];
|
||||
brr[i + 1] = brr[i];
|
||||
}
|
||||
if ( test ) {
|
||||
i = l - 1;
|
||||
if (test) {
|
||||
i = l - 1;
|
||||
arr[i + 1] = a;
|
||||
brr[i + 1] = b;
|
||||
}
|
||||
}
|
||||
if ( jstack == 0 )
|
||||
if (jstack == 0)
|
||||
return;
|
||||
ir = istack[jstack]; // Pop stack and begin a new round of partitioning.
|
||||
l = istack[jstack - 1];
|
||||
ir = istack
|
||||
[jstack]; // Pop stack and begin a new round of partitioning.
|
||||
l = istack[jstack - 1];
|
||||
jstack -= 2;
|
||||
} else {
|
||||
k = ( l + ir ) / 2; // Choose median of left, center and right elements as partitioning
|
||||
// element a. Also rearrange so that a(l) ? a(l+1) ? a(ir).
|
||||
tmp_a = arr[k];
|
||||
arr[k] = arr[l + 1];
|
||||
k = (l + ir) /
|
||||
2; // Choose median of left, center and right elements as partitioning
|
||||
// element a. Also rearrange so that a(l) ? a(l+1) ? a(ir).
|
||||
tmp_a = arr[k];
|
||||
arr[k] = arr[l + 1];
|
||||
arr[l + 1] = tmp_a;
|
||||
tmp_b = brr[k];
|
||||
brr[k] = brr[l + 1];
|
||||
tmp_b = brr[k];
|
||||
brr[k] = brr[l + 1];
|
||||
brr[l + 1] = tmp_b;
|
||||
if ( arr[l] > arr[ir] ) {
|
||||
tmp_a = arr[l];
|
||||
arr[l] = arr[ir];
|
||||
if (arr[l] > arr[ir]) {
|
||||
tmp_a = arr[l];
|
||||
arr[l] = arr[ir];
|
||||
arr[ir] = tmp_a;
|
||||
tmp_b = brr[l];
|
||||
brr[l] = brr[ir];
|
||||
tmp_b = brr[l];
|
||||
brr[l] = brr[ir];
|
||||
brr[ir] = tmp_b;
|
||||
}
|
||||
if ( arr[l + 1] > arr[ir] ) {
|
||||
tmp_a = arr[l + 1];
|
||||
if (arr[l + 1] > arr[ir]) {
|
||||
tmp_a = arr[l + 1];
|
||||
arr[l + 1] = arr[ir];
|
||||
arr[ir] = tmp_a;
|
||||
tmp_b = brr[l + 1];
|
||||
arr[ir] = tmp_a;
|
||||
tmp_b = brr[l + 1];
|
||||
brr[l + 1] = brr[ir];
|
||||
brr[ir] = tmp_b;
|
||||
brr[ir] = tmp_b;
|
||||
}
|
||||
if ( arr[l] > arr[l + 1] ) {
|
||||
tmp_a = arr[l];
|
||||
arr[l] = arr[l + 1];
|
||||
if (arr[l] > arr[l + 1]) {
|
||||
tmp_a = arr[l];
|
||||
arr[l] = arr[l + 1];
|
||||
arr[l + 1] = tmp_a;
|
||||
tmp_b = brr[l];
|
||||
brr[l] = brr[l + 1];
|
||||
tmp_b = brr[l];
|
||||
brr[l] = brr[l + 1];
|
||||
brr[l + 1] = tmp_b;
|
||||
}
|
||||
// Scan up to find element > a
|
||||
j = ir;
|
||||
a = arr[l + 1]; // Partitioning element.
|
||||
b = brr[l + 1];
|
||||
for ( i = l + 2; i <= ir; i++ ) {
|
||||
if ( arr[i] < a )
|
||||
for (i = l + 2; i <= ir; i++) {
|
||||
if (arr[i] < a)
|
||||
continue;
|
||||
while ( arr[j] > a ) // Scan down to find element < a.
|
||||
while (arr[j] > a) // Scan down to find element < a.
|
||||
j--;
|
||||
if ( j < i )
|
||||
break; // Pointers crossed. Exit with partitioning complete.
|
||||
tmp_a = arr[i]; // Exchange elements of both arrays.
|
||||
if (j < i)
|
||||
break; // Pointers crossed. Exit with partitioning complete.
|
||||
tmp_a = arr[i]; // Exchange elements of both arrays.
|
||||
arr[i] = arr[j];
|
||||
arr[j] = tmp_a;
|
||||
tmp_b = brr[i];
|
||||
tmp_b = brr[i];
|
||||
brr[i] = brr[j];
|
||||
brr[j] = tmp_b;
|
||||
}
|
||||
arr[l + 1] = arr[j]; // Insert partitioning element in both arrays.
|
||||
arr[j] = a;
|
||||
arr[j] = a;
|
||||
brr[l + 1] = brr[j];
|
||||
brr[j] = b;
|
||||
brr[j] = b;
|
||||
jstack += 2;
|
||||
// Push pointers to larger subarray on stack, process smaller subarray immediately.
|
||||
if ( ir - i + 1 >= j - l ) {
|
||||
istack[jstack] = ir;
|
||||
if (ir - i + 1 >= j - l) {
|
||||
istack[jstack] = ir;
|
||||
istack[jstack - 1] = i;
|
||||
ir = j - 1;
|
||||
ir = j - 1;
|
||||
} else {
|
||||
istack[jstack] = j - 1;
|
||||
istack[jstack] = j - 1;
|
||||
istack[jstack - 1] = l;
|
||||
l = i;
|
||||
l = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
template<class T>
|
||||
void unique( std::vector<T> &x )
|
||||
{
|
||||
if ( x.size() <= 1 )
|
||||
template <class T> void unique(std::vector<T> &x) {
|
||||
if (x.size() <= 1)
|
||||
return;
|
||||
// First perform a quicksort
|
||||
quicksort( x );
|
||||
quicksort(x);
|
||||
// Next remove duplicate entries
|
||||
size_t pos = 1;
|
||||
for ( size_t i = 1; i < x.size(); i++ ) {
|
||||
if ( x[i] != x[pos - 1] ) {
|
||||
for (size_t i = 1; i < x.size(); i++) {
|
||||
if (x[i] != x[pos - 1]) {
|
||||
x[pos] = x[i];
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
if ( pos < x.size() )
|
||||
x.resize( pos );
|
||||
if (pos < x.size())
|
||||
x.resize(pos);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} // namespace Utilities
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
||||
Copyright Equnior ASA
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// This file contains useful macros including ERROR, WARNING, INSIST, ASSERT, etc.
|
||||
#ifndef included_UtilityMacros
|
||||
#define included_UtilityMacros
|
||||
|
@ -8,7 +24,6 @@
|
|||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
/*! \defgroup Macros Set of utility macro functions
|
||||
* \details These functions are a list of C++ macros that are used
|
||||
* for common operations, including checking for errors.
|
||||
|
@ -16,7 +31,6 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/*! \def NULL_STATEMENT
|
||||
* \brief A null statement
|
||||
* \details A statement that does nothing, for insure++ make it something
|
||||
|
@ -24,33 +38,31 @@
|
|||
*/
|
||||
#ifndef NULL_STATEMENT
|
||||
#ifdef __INSURE__
|
||||
#define NULL_STATEMENT \
|
||||
do { \
|
||||
if ( 0 ) \
|
||||
int nullstatement = 0 \
|
||||
} while ( 0 )
|
||||
#define NULL_STATEMENT \
|
||||
do { \
|
||||
if (0) \
|
||||
int nullstatement = 0 \
|
||||
} while (0)
|
||||
#else
|
||||
#define NULL_STATEMENT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*! \def NULL_USE(variable)
|
||||
* \brief A null use of a variable
|
||||
* \details A null use of a variable, use to avoid GNU compiler warnings about unused variables.
|
||||
* \param variable Variable to pretend to use
|
||||
*/
|
||||
#ifndef NULL_USE
|
||||
#define NULL_USE( variable ) \
|
||||
do { \
|
||||
if ( 0 ) { \
|
||||
auto temp = (char *) &variable; \
|
||||
temp++; \
|
||||
} \
|
||||
} while ( 0 )
|
||||
#define NULL_USE(variable) \
|
||||
do { \
|
||||
if (0) { \
|
||||
auto temp = (char *)&variable; \
|
||||
temp++; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
/*! \def ERROR(MSG)
|
||||
* \brief Throw error
|
||||
* \details Throw an error exception from within any C++ source code. The
|
||||
|
@ -58,25 +70,23 @@
|
|||
* line number of the abort are also printed.
|
||||
* \param MSG Error message to print
|
||||
*/
|
||||
#define ERROR(MSG) \
|
||||
do { \
|
||||
::Utilities::abort( MSG, __FILE__, __LINE__ ); \
|
||||
} while ( 0 )
|
||||
|
||||
#define ERROR(MSG) \
|
||||
do { \
|
||||
::Utilities::abort(MSG, __FILE__, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
/*! \def WARNING(MSG)
|
||||
* \brief Print a warning
|
||||
* \details Print a warning without exit. Print file and line number of the warning.
|
||||
* \param MSG Warning message to print
|
||||
*/
|
||||
#define WARNING(MSG) \
|
||||
do { \
|
||||
std::stringstream tboxos; \
|
||||
tboxos << MSG << std::ends; \
|
||||
printf("WARNING: %s\n Warning called in %s on line %i\n", \
|
||||
tboxos.str().c_str(),__FILE__,__LINE__); \
|
||||
}while(0)
|
||||
|
||||
#define WARNING(MSG) \
|
||||
do { \
|
||||
std::stringstream tboxos; \
|
||||
tboxos << MSG << std::ends; \
|
||||
printf("WARNING: %s\n Warning called in %s on line %i\n", \
|
||||
tboxos.str().c_str(), __FILE__, __LINE__); \
|
||||
} while (0)
|
||||
|
||||
/*! \def ASSERT(EXP)
|
||||
* \brief Assert error
|
||||
|
@ -86,15 +96,14 @@
|
|||
* The file and line number of the abort are printed along with the stack trace (if availible).
|
||||
* \param EXP Expression to evaluate
|
||||
*/
|
||||
#define ASSERT(EXP) \
|
||||
do { \
|
||||
if ( !(EXP) ) { \
|
||||
std::stringstream tboxos; \
|
||||
tboxos << "Failed assertion: " << #EXP << std::ends; \
|
||||
::Utilities::abort(tboxos.str(), __FILE__, __LINE__); \
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
#define ASSERT(EXP) \
|
||||
do { \
|
||||
if (!(EXP)) { \
|
||||
std::stringstream tboxos; \
|
||||
tboxos << "Failed assertion: " << #EXP << std::ends; \
|
||||
::Utilities::abort(tboxos.str(), __FILE__, __LINE__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*! \def INSIST(EXP,MSG)
|
||||
* \brief Insist error
|
||||
|
@ -105,15 +114,15 @@
|
|||
* \param EXP Expression to evaluate
|
||||
* \param MSG Debug message to print
|
||||
*/
|
||||
#define INSIST(EXP,MSG) do { \
|
||||
if ( !(EXP) ) { \
|
||||
std::stringstream tboxos; \
|
||||
tboxos << "Failed insist: " << #EXP << std::endl; \
|
||||
tboxos << "Message: " << MSG << std::ends; \
|
||||
::Utilities::abort(tboxos.str(), __FILE__, __LINE__); \
|
||||
} \
|
||||
}while(0)
|
||||
|
||||
#define INSIST(EXP, MSG) \
|
||||
do { \
|
||||
if (!(EXP)) { \
|
||||
std::stringstream tboxos; \
|
||||
tboxos << "Failed insist: " << #EXP << std::endl; \
|
||||
tboxos << "Message: " << MSG << std::ends; \
|
||||
::Utilities::abort(tboxos.str(), __FILE__, __LINE__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Macro for use when assertions are to be included
|
||||
|
@ -127,12 +136,11 @@
|
|||
* \param EXP Expression to evaluate
|
||||
*/
|
||||
#ifdef DEBUG_CHECK_ASSERTIONS
|
||||
#define CHECK_ASSERT(EXP) ASSERT(EXP)
|
||||
#define CHECK_ASSERT(EXP) ASSERT(EXP)
|
||||
#else
|
||||
#define CHECK_ASSERT(EXP)
|
||||
#define CHECK_ASSERT(EXP)
|
||||
#endif
|
||||
|
||||
|
||||
/*! \def DISABLE_WARNINGS
|
||||
* \brief Reenable warnings
|
||||
* \details This will re-enable warnings after a call to DIASABLE_WARNINGS
|
||||
|
@ -173,9 +181,6 @@
|
|||
#endif
|
||||
// clang-format on
|
||||
|
||||
|
||||
|
||||
/*! @} */
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,338 +3,543 @@ This class implements support for halo widths larger than 1
|
|||
*/
|
||||
#include "common/WideHalo.h"
|
||||
|
||||
ScaLBLWideHalo_Communicator::ScaLBLWideHalo_Communicator(std::shared_ptr <Domain> Dm, int width)
|
||||
{
|
||||
//......................................................................................
|
||||
Lock=false; // unlock the communicator
|
||||
//......................................................................................
|
||||
// Create a separate copy of the communicator for the device
|
||||
ScaLBLWideHalo_Communicator::ScaLBLWideHalo_Communicator(
|
||||
std::shared_ptr<Domain> Dm, int width) {
|
||||
//......................................................................................
|
||||
Lock = false; // unlock the communicator
|
||||
//......................................................................................
|
||||
// Create a separate copy of the communicator for the device
|
||||
MPI_COMM_SCALBL = Dm->Comm.dup();
|
||||
//......................................................................................
|
||||
// Copy the domain size and communication information directly from Dm
|
||||
Nx = Dm->Nx;
|
||||
Ny = Dm->Ny;
|
||||
Nz = Dm->Nz;
|
||||
N = Nx*Ny*Nz;
|
||||
Nxh = Nx + 2*(width - 1);
|
||||
Nyh = Ny + 2*(width - 1);
|
||||
Nzh = Nz + 2*(width - 1);
|
||||
Nh = Nxh*Nyh*Nzh;
|
||||
|
||||
Map.resize(Nx,Ny,Nz);
|
||||
|
||||
rank=Dm->rank();
|
||||
iproc = Dm->iproc();
|
||||
jproc = Dm->jproc();
|
||||
kproc = Dm->kproc();
|
||||
nprocx = Dm->nprocx();
|
||||
nprocy = Dm->nprocy();
|
||||
nprocz = Dm->nprocz();
|
||||
rank_info = RankInfoStruct(rank,nprocx,nprocy,nprocz);
|
||||
rank = rank_info.rank[1][1][1];
|
||||
rank_X = rank_info.rank[2][1][1];
|
||||
rank_x = rank_info.rank[0][1][1];
|
||||
rank_Y = rank_info.rank[1][2][1];
|
||||
rank_y = rank_info.rank[1][0][1];
|
||||
rank_Z = rank_info.rank[1][1][2];
|
||||
rank_z = rank_info.rank[1][1][0];
|
||||
rank_XY = rank_info.rank[2][2][1];
|
||||
rank_xy = rank_info.rank[0][0][1];
|
||||
rank_Xy = rank_info.rank[2][0][1];
|
||||
rank_xY = rank_info.rank[0][2][1];
|
||||
rank_XZ = rank_info.rank[2][1][2];
|
||||
rank_xz = rank_info.rank[0][1][0];
|
||||
rank_Xz = rank_info.rank[2][1][0];
|
||||
rank_xZ = rank_info.rank[0][1][2];
|
||||
rank_YZ = rank_info.rank[1][2][2];
|
||||
rank_yz = rank_info.rank[1][0][0];
|
||||
rank_Yz = rank_info.rank[1][2][0];
|
||||
rank_yZ = rank_info.rank[1][0][2];
|
||||
rank_XYz = rank_info.rank[2][2][0];
|
||||
rank_xyz = rank_info.rank[0][0][0];
|
||||
rank_Xyz = rank_info.rank[2][0][0];
|
||||
rank_xYz = rank_info.rank[0][2][0];
|
||||
rank_XYZ = rank_info.rank[2][2][2];
|
||||
rank_xyZ = rank_info.rank[0][0][2];
|
||||
rank_XyZ = rank_info.rank[2][0][2];
|
||||
rank_xYZ = rank_info.rank[0][2][2];
|
||||
MPI_COMM_SCALBL.barrier();
|
||||
|
||||
/* Fill in communications patterns for the lists */
|
||||
/* Send lists */
|
||||
sendCount_x =getHaloBlock(width,2*width,width,Nyh-width,width,Nzh-width,dvcSendList_x);
|
||||
sendCount_X =getHaloBlock(Nxh-2*width,Nxh-width,width,Nyh-width,width,Nzh-width,dvcSendList_X);
|
||||
sendCount_y =getHaloBlock(width,Nxh-width,width,2*width,width,Nzh-width,dvcSendList_y);
|
||||
sendCount_Y =getHaloBlock(width,Nxh-width,Nyh-2*width,Nyh-width,width,Nzh-width,dvcSendList_Y);
|
||||
sendCount_z =getHaloBlock(width,Nxh-width,width,Nyh-width,width,2*width,dvcSendList_z);
|
||||
sendCount_Z =getHaloBlock(width,Nxh-width,width,Nyh-width,Nzh-2*width,Nzh-width,dvcSendList_Z);
|
||||
// xy
|
||||
sendCount_xy =getHaloBlock(width,2*width,width,2*width,width,Nzh-width,dvcSendList_xy);
|
||||
sendCount_xY =getHaloBlock(width,2*width,Nyh-2*width,Nyh-width,width,Nzh-width,dvcSendList_xY);
|
||||
sendCount_Xy =getHaloBlock(Nxh-2*width,Nxh-width,width,2*width,width,Nzh-width,dvcSendList_Xy);
|
||||
sendCount_XY =getHaloBlock(Nxh-2*width,Nxh-width,Nyh-2*width,Nyh-width,width,Nzh-width,dvcSendList_XY);
|
||||
// xz
|
||||
sendCount_xz =getHaloBlock(width,2*width,width,Nyh-width,width,2*width,dvcSendList_xz);
|
||||
sendCount_xZ =getHaloBlock(width,2*width,width,Nyh-width,Nzh-2*width,Nzh-width,dvcSendList_xZ);
|
||||
sendCount_Xz =getHaloBlock(Nxh-2*width,Nxh-width,width,Nyh-width,width,2*width,dvcSendList_Xz);
|
||||
sendCount_XZ =getHaloBlock(Nxh-2*width,Nxh-width,width,Nyh-width,Nzh-2*width,Nzh-width,dvcSendList_XZ);
|
||||
// yz
|
||||
sendCount_yz =getHaloBlock(width,Nxh-width,width,2*width,width,2*width,dvcSendList_yz);
|
||||
sendCount_yZ =getHaloBlock(width,Nxh-width,width,2*width,Nzh-2*width,Nzh-width,dvcSendList_yZ);
|
||||
sendCount_Yz =getHaloBlock(width,Nxh-width,Nyh-2*width,Nyh-width,width,2*width,dvcSendList_Yz);
|
||||
sendCount_YZ =getHaloBlock(width,Nxh-width,Nyh-2*width,Nyh-width,Nzh-2*width,Nzh-width,dvcSendList_YZ);
|
||||
// xyz
|
||||
sendCount_xyz =getHaloBlock(width,2*width,width,2*width,width,2*width,dvcSendList_xyz);
|
||||
sendCount_xyZ =getHaloBlock(width,2*width,width,2*width,Nzh-2*width,Nzh-width,dvcSendList_xyZ);
|
||||
sendCount_xYz =getHaloBlock(width,2*width,Nyh-2*width,Nyh-width,width,2*width,dvcSendList_xYz);
|
||||
sendCount_xYZ =getHaloBlock(width,2*width,Nyh-2*width,Nyh-width,Nzh-2*width,Nzh-width,dvcSendList_xYZ);
|
||||
sendCount_Xyz =getHaloBlock(Nxh-2*width,Nxh-width,width,2*width,width,2*width,dvcSendList_Xyz);
|
||||
sendCount_XyZ =getHaloBlock(Nxh-2*width,Nxh-width,width,2*width,Nzh-2*width,Nzh-width,dvcSendList_XyZ);
|
||||
sendCount_XYz =getHaloBlock(Nxh-2*width,Nxh-width,Nyh-2*width,Nyh-width,width,2*width,dvcSendList_XYz);
|
||||
sendCount_XYZ =getHaloBlock(Nxh-2*width,Nxh-width,Nyh-2*width,Nyh-width,Nzh-2*width,Nzh-width,dvcSendList_XYZ);
|
||||
|
||||
/* Recv lists */
|
||||
recvCount_x =getHaloBlock(0,width,width,Nyh-width,width,Nzh-width,dvcRecvList_x);
|
||||
recvCount_X =getHaloBlock(Nxh-width,Nxh,width,Nyh-width,width,Nzh-width,dvcRecvList_X);
|
||||
recvCount_y =getHaloBlock(width,Nxh-width,0,width,width,Nzh-width,dvcRecvList_y);
|
||||
recvCount_Y =getHaloBlock(width,Nxh-width,Nyh-width,Nyh,width,Nzh-width,dvcRecvList_Y);
|
||||
recvCount_z =getHaloBlock(width,Nxh-width,width,Nyh-width,0,width,dvcRecvList_z);
|
||||
recvCount_Z =getHaloBlock(width,Nxh-width,width,Nyh-width,Nzh-width,Nzh,dvcRecvList_Z);
|
||||
//xy
|
||||
recvCount_xy =getHaloBlock(0,width,0,width,width,Nzh-width,dvcRecvList_xy);
|
||||
recvCount_xY =getHaloBlock(0,width,Nyh-width,Nyh,width,Nzh-width,dvcRecvList_xY);
|
||||
recvCount_Xy =getHaloBlock(Nxh-width,Nxh,0,width,width,Nzh-width,dvcRecvList_Xy);
|
||||
recvCount_XY =getHaloBlock(Nxh-width,Nxh,Nyh-width,Nyh,width,Nzh-width,dvcRecvList_XY);
|
||||
//xz
|
||||
recvCount_xz =getHaloBlock(0,width,width,Nyh-width,0,width,dvcRecvList_xz);
|
||||
recvCount_xZ =getHaloBlock(0,width,width,Nyh-width,Nzh-width,Nzh,dvcRecvList_xZ);
|
||||
recvCount_Xz =getHaloBlock(Nxh-width,Nxh,width,Nyh-width,0,width,dvcRecvList_Xz);
|
||||
recvCount_XZ =getHaloBlock(Nxh-width,Nxh,width,Nyh-width,Nzh-width,Nzh,dvcRecvList_XZ);
|
||||
//yz
|
||||
recvCount_yz =getHaloBlock(width,Nxh-width,0,width,0,width,dvcRecvList_yz);
|
||||
recvCount_yZ =getHaloBlock(width,Nxh-width,0,width,Nzh-width,Nzh,dvcRecvList_yZ);
|
||||
recvCount_Yz =getHaloBlock(width,Nxh-width,Nyh-width,Nyh,0,width,dvcRecvList_Yz);
|
||||
recvCount_YZ =getHaloBlock(width,Nxh-width,Nyh-width,Nyh,Nzh-width,Nzh,dvcRecvList_YZ);
|
||||
//xyz
|
||||
recvCount_xyz =getHaloBlock(0,width,0,width,0,width,dvcRecvList_xyz);
|
||||
recvCount_xyZ =getHaloBlock(0,width,0,width,Nzh-width,Nzh,dvcRecvList_xyZ);
|
||||
recvCount_xYz =getHaloBlock(0,width,Nyh-width,Nyh,0,width,dvcRecvList_xYz);
|
||||
recvCount_xYZ =getHaloBlock(0,width,Nyh-width,Nyh,Nzh-width,Nzh,dvcRecvList_xYZ);
|
||||
recvCount_Xyz =getHaloBlock(Nxh-width,Nxh,0,width,0,width,dvcRecvList_Xyz);
|
||||
recvCount_XyZ =getHaloBlock(Nxh-width,Nxh,0,width,Nzh-width,Nzh,dvcRecvList_XyZ);
|
||||
recvCount_XYz =getHaloBlock(Nxh-width,Nxh,Nyh-width,Nyh,0,width,dvcRecvList_XYz);
|
||||
recvCount_XYZ =getHaloBlock(Nxh-width,Nxh,Nyh-width,Nyh,Nzh-width,Nzh,dvcRecvList_XYZ);
|
||||
//......................................................................................
|
||||
// Copy the domain size and communication information directly from Dm
|
||||
Nx = Dm->Nx;
|
||||
Ny = Dm->Ny;
|
||||
Nz = Dm->Nz;
|
||||
N = Nx * Ny * Nz;
|
||||
Nxh = Nx + 2 * (width - 1);
|
||||
Nyh = Ny + 2 * (width - 1);
|
||||
Nzh = Nz + 2 * (width - 1);
|
||||
Nh = Nxh * Nyh * Nzh;
|
||||
|
||||
//......................................................................................
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_x, sendCount_x*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_X, sendCount_X*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_y, sendCount_y*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_Y, sendCount_Y*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_z, sendCount_z*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_Z, sendCount_Z*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_xy, sendCount_xy*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_xY, sendCount_xY*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_Xy, sendCount_Xy*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_XY, sendCount_XY*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_xz, sendCount_xz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_xZ, sendCount_xZ*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_Xz, sendCount_Xz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_XZ, sendCount_XZ*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_yz, sendCount_yz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_yZ, sendCount_yZ*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_Yz, sendCount_Yz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_YZ, sendCount_YZ*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_xyz, sendCount_xyz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_xYz, sendCount_xYz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_Xyz, sendCount_Xyz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_XYz, sendCount_XYz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_xyZ, sendCount_xyZ*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_xYZ, sendCount_xYZ*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_XyZ, sendCount_XyZ*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &sendbuf_XYZ, sendCount_XYZ*sizeof(double)); // Allocate device memory
|
||||
//......................................................................................
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_x, recvCount_x*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_X, recvCount_X*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_y, recvCount_y*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_Y, recvCount_Y*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_z, recvCount_z*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_Z, recvCount_Z*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_xy, recvCount_xy*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_xY, recvCount_xY*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_Xy, recvCount_Xy*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_XY, recvCount_XY*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_xz, recvCount_xz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_xZ, recvCount_xZ*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_Xz, recvCount_Xz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_XZ, recvCount_XZ*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_yz, recvCount_yz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_yZ, recvCount_yZ*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_Yz, recvCount_Yz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_YZ, recvCount_YZ*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_xyz, recvCount_xyz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_xYz, recvCount_xYz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_Xyz, recvCount_Xyz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_XYz, recvCount_XYz*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_xyZ, recvCount_xyZ*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_xYZ, recvCount_xYZ*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_XyZ, recvCount_XyZ*sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **) &recvbuf_XYZ, recvCount_XYZ*sizeof(double)); // Allocate device memory
|
||||
|
||||
/* Set up a map to the halo width=1 data structure */
|
||||
for (k=width; k<Nzh-width; k++){
|
||||
for (j=width; j<Nyh-width; j++){
|
||||
for (i=width; i<Nxh-width; i++){
|
||||
int idx = k*Nxh*Nyh + j*Nxh + i;
|
||||
Map(i-width+1,j-width+1,k-width+1) = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map.resize(Nx, Ny, Nz);
|
||||
|
||||
rank = Dm->rank();
|
||||
iproc = Dm->iproc();
|
||||
jproc = Dm->jproc();
|
||||
kproc = Dm->kproc();
|
||||
nprocx = Dm->nprocx();
|
||||
nprocy = Dm->nprocy();
|
||||
nprocz = Dm->nprocz();
|
||||
rank_info = RankInfoStruct(rank, nprocx, nprocy, nprocz);
|
||||
rank = rank_info.rank[1][1][1];
|
||||
rank_X = rank_info.rank[2][1][1];
|
||||
rank_x = rank_info.rank[0][1][1];
|
||||
rank_Y = rank_info.rank[1][2][1];
|
||||
rank_y = rank_info.rank[1][0][1];
|
||||
rank_Z = rank_info.rank[1][1][2];
|
||||
rank_z = rank_info.rank[1][1][0];
|
||||
rank_XY = rank_info.rank[2][2][1];
|
||||
rank_xy = rank_info.rank[0][0][1];
|
||||
rank_Xy = rank_info.rank[2][0][1];
|
||||
rank_xY = rank_info.rank[0][2][1];
|
||||
rank_XZ = rank_info.rank[2][1][2];
|
||||
rank_xz = rank_info.rank[0][1][0];
|
||||
rank_Xz = rank_info.rank[2][1][0];
|
||||
rank_xZ = rank_info.rank[0][1][2];
|
||||
rank_YZ = rank_info.rank[1][2][2];
|
||||
rank_yz = rank_info.rank[1][0][0];
|
||||
rank_Yz = rank_info.rank[1][2][0];
|
||||
rank_yZ = rank_info.rank[1][0][2];
|
||||
rank_XYz = rank_info.rank[2][2][0];
|
||||
rank_xyz = rank_info.rank[0][0][0];
|
||||
rank_Xyz = rank_info.rank[2][0][0];
|
||||
rank_xYz = rank_info.rank[0][2][0];
|
||||
rank_XYZ = rank_info.rank[2][2][2];
|
||||
rank_xyZ = rank_info.rank[0][0][2];
|
||||
rank_XyZ = rank_info.rank[2][0][2];
|
||||
rank_xYZ = rank_info.rank[0][2][2];
|
||||
MPI_COMM_SCALBL.barrier();
|
||||
|
||||
/* Fill in communications patterns for the lists */
|
||||
/* Send lists */
|
||||
sendCount_x = getHaloBlock(width, 2 * width, width, Nyh - width, width,
|
||||
Nzh - width, dvcSendList_x);
|
||||
sendCount_X = getHaloBlock(Nxh - 2 * width, Nxh - width, width, Nyh - width,
|
||||
width, Nzh - width, dvcSendList_X);
|
||||
sendCount_y = getHaloBlock(width, Nxh - width, width, 2 * width, width,
|
||||
Nzh - width, dvcSendList_y);
|
||||
sendCount_Y = getHaloBlock(width, Nxh - width, Nyh - 2 * width, Nyh - width,
|
||||
width, Nzh - width, dvcSendList_Y);
|
||||
sendCount_z = getHaloBlock(width, Nxh - width, width, Nyh - width, width,
|
||||
2 * width, dvcSendList_z);
|
||||
sendCount_Z = getHaloBlock(width, Nxh - width, width, Nyh - width,
|
||||
Nzh - 2 * width, Nzh - width, dvcSendList_Z);
|
||||
// xy
|
||||
sendCount_xy = getHaloBlock(width, 2 * width, width, 2 * width, width,
|
||||
Nzh - width, dvcSendList_xy);
|
||||
sendCount_xY = getHaloBlock(width, 2 * width, Nyh - 2 * width, Nyh - width,
|
||||
width, Nzh - width, dvcSendList_xY);
|
||||
sendCount_Xy = getHaloBlock(Nxh - 2 * width, Nxh - width, width, 2 * width,
|
||||
width, Nzh - width, dvcSendList_Xy);
|
||||
sendCount_XY =
|
||||
getHaloBlock(Nxh - 2 * width, Nxh - width, Nyh - 2 * width, Nyh - width,
|
||||
width, Nzh - width, dvcSendList_XY);
|
||||
// xz
|
||||
sendCount_xz = getHaloBlock(width, 2 * width, width, Nyh - width, width,
|
||||
2 * width, dvcSendList_xz);
|
||||
sendCount_xZ = getHaloBlock(width, 2 * width, width, Nyh - width,
|
||||
Nzh - 2 * width, Nzh - width, dvcSendList_xZ);
|
||||
sendCount_Xz = getHaloBlock(Nxh - 2 * width, Nxh - width, width,
|
||||
Nyh - width, width, 2 * width, dvcSendList_Xz);
|
||||
sendCount_XZ =
|
||||
getHaloBlock(Nxh - 2 * width, Nxh - width, width, Nyh - width,
|
||||
Nzh - 2 * width, Nzh - width, dvcSendList_XZ);
|
||||
// yz
|
||||
sendCount_yz = getHaloBlock(width, Nxh - width, width, 2 * width, width,
|
||||
2 * width, dvcSendList_yz);
|
||||
sendCount_yZ = getHaloBlock(width, Nxh - width, width, 2 * width,
|
||||
Nzh - 2 * width, Nzh - width, dvcSendList_yZ);
|
||||
sendCount_Yz = getHaloBlock(width, Nxh - width, Nyh - 2 * width,
|
||||
Nyh - width, width, 2 * width, dvcSendList_Yz);
|
||||
sendCount_YZ =
|
||||
getHaloBlock(width, Nxh - width, Nyh - 2 * width, Nyh - width,
|
||||
Nzh - 2 * width, Nzh - width, dvcSendList_YZ);
|
||||
// xyz
|
||||
sendCount_xyz = getHaloBlock(width, 2 * width, width, 2 * width, width,
|
||||
2 * width, dvcSendList_xyz);
|
||||
sendCount_xyZ = getHaloBlock(width, 2 * width, width, 2 * width,
|
||||
Nzh - 2 * width, Nzh - width, dvcSendList_xyZ);
|
||||
sendCount_xYz = getHaloBlock(width, 2 * width, Nyh - 2 * width, Nyh - width,
|
||||
width, 2 * width, dvcSendList_xYz);
|
||||
sendCount_xYZ = getHaloBlock(width, 2 * width, Nyh - 2 * width, Nyh - width,
|
||||
Nzh - 2 * width, Nzh - width, dvcSendList_xYZ);
|
||||
sendCount_Xyz = getHaloBlock(Nxh - 2 * width, Nxh - width, width, 2 * width,
|
||||
width, 2 * width, dvcSendList_Xyz);
|
||||
sendCount_XyZ = getHaloBlock(Nxh - 2 * width, Nxh - width, width, 2 * width,
|
||||
Nzh - 2 * width, Nzh - width, dvcSendList_XyZ);
|
||||
sendCount_XYz =
|
||||
getHaloBlock(Nxh - 2 * width, Nxh - width, Nyh - 2 * width, Nyh - width,
|
||||
width, 2 * width, dvcSendList_XYz);
|
||||
sendCount_XYZ =
|
||||
getHaloBlock(Nxh - 2 * width, Nxh - width, Nyh - 2 * width, Nyh - width,
|
||||
Nzh - 2 * width, Nzh - width, dvcSendList_XYZ);
|
||||
|
||||
/* Recv lists */
|
||||
recvCount_x = getHaloBlock(0, width, width, Nyh - width, width, Nzh - width,
|
||||
dvcRecvList_x);
|
||||
recvCount_X = getHaloBlock(Nxh - width, Nxh, width, Nyh - width, width,
|
||||
Nzh - width, dvcRecvList_X);
|
||||
recvCount_y = getHaloBlock(width, Nxh - width, 0, width, width, Nzh - width,
|
||||
dvcRecvList_y);
|
||||
recvCount_Y = getHaloBlock(width, Nxh - width, Nyh - width, Nyh, width,
|
||||
Nzh - width, dvcRecvList_Y);
|
||||
recvCount_z = getHaloBlock(width, Nxh - width, width, Nyh - width, 0, width,
|
||||
dvcRecvList_z);
|
||||
recvCount_Z = getHaloBlock(width, Nxh - width, width, Nyh - width,
|
||||
Nzh - width, Nzh, dvcRecvList_Z);
|
||||
//xy
|
||||
recvCount_xy =
|
||||
getHaloBlock(0, width, 0, width, width, Nzh - width, dvcRecvList_xy);
|
||||
recvCount_xY = getHaloBlock(0, width, Nyh - width, Nyh, width, Nzh - width,
|
||||
dvcRecvList_xY);
|
||||
recvCount_Xy = getHaloBlock(Nxh - width, Nxh, 0, width, width, Nzh - width,
|
||||
dvcRecvList_Xy);
|
||||
recvCount_XY = getHaloBlock(Nxh - width, Nxh, Nyh - width, Nyh, width,
|
||||
Nzh - width, dvcRecvList_XY);
|
||||
//xz
|
||||
recvCount_xz =
|
||||
getHaloBlock(0, width, width, Nyh - width, 0, width, dvcRecvList_xz);
|
||||
recvCount_xZ = getHaloBlock(0, width, width, Nyh - width, Nzh - width, Nzh,
|
||||
dvcRecvList_xZ);
|
||||
recvCount_Xz = getHaloBlock(Nxh - width, Nxh, width, Nyh - width, 0, width,
|
||||
dvcRecvList_Xz);
|
||||
recvCount_XZ = getHaloBlock(Nxh - width, Nxh, width, Nyh - width,
|
||||
Nzh - width, Nzh, dvcRecvList_XZ);
|
||||
//yz
|
||||
recvCount_yz =
|
||||
getHaloBlock(width, Nxh - width, 0, width, 0, width, dvcRecvList_yz);
|
||||
recvCount_yZ = getHaloBlock(width, Nxh - width, 0, width, Nzh - width, Nzh,
|
||||
dvcRecvList_yZ);
|
||||
recvCount_Yz = getHaloBlock(width, Nxh - width, Nyh - width, Nyh, 0, width,
|
||||
dvcRecvList_Yz);
|
||||
recvCount_YZ = getHaloBlock(width, Nxh - width, Nyh - width, Nyh,
|
||||
Nzh - width, Nzh, dvcRecvList_YZ);
|
||||
//xyz
|
||||
recvCount_xyz = getHaloBlock(0, width, 0, width, 0, width, dvcRecvList_xyz);
|
||||
recvCount_xyZ =
|
||||
getHaloBlock(0, width, 0, width, Nzh - width, Nzh, dvcRecvList_xyZ);
|
||||
recvCount_xYz =
|
||||
getHaloBlock(0, width, Nyh - width, Nyh, 0, width, dvcRecvList_xYz);
|
||||
recvCount_xYZ = getHaloBlock(0, width, Nyh - width, Nyh, Nzh - width, Nzh,
|
||||
dvcRecvList_xYZ);
|
||||
recvCount_Xyz =
|
||||
getHaloBlock(Nxh - width, Nxh, 0, width, 0, width, dvcRecvList_Xyz);
|
||||
recvCount_XyZ = getHaloBlock(Nxh - width, Nxh, 0, width, Nzh - width, Nzh,
|
||||
dvcRecvList_XyZ);
|
||||
recvCount_XYz = getHaloBlock(Nxh - width, Nxh, Nyh - width, Nyh, 0, width,
|
||||
dvcRecvList_XYz);
|
||||
recvCount_XYZ = getHaloBlock(Nxh - width, Nxh, Nyh - width, Nyh,
|
||||
Nzh - width, Nzh, dvcRecvList_XYZ);
|
||||
|
||||
//......................................................................................
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_x,
|
||||
sendCount_x *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_X,
|
||||
sendCount_X *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_y,
|
||||
sendCount_y *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_Y,
|
||||
sendCount_Y *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_z,
|
||||
sendCount_z *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_Z,
|
||||
sendCount_Z *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_xy,
|
||||
sendCount_xy *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_xY,
|
||||
sendCount_xY *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_Xy,
|
||||
sendCount_Xy *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_XY,
|
||||
sendCount_XY *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_xz,
|
||||
sendCount_xz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_xZ,
|
||||
sendCount_xZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_Xz,
|
||||
sendCount_Xz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_XZ,
|
||||
sendCount_XZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_yz,
|
||||
sendCount_yz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_yZ,
|
||||
sendCount_yZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_Yz,
|
||||
sendCount_Yz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_YZ,
|
||||
sendCount_YZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_xyz,
|
||||
sendCount_xyz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_xYz,
|
||||
sendCount_xYz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_Xyz,
|
||||
sendCount_Xyz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_XYz,
|
||||
sendCount_XYz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_xyZ,
|
||||
sendCount_xyZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_xYZ,
|
||||
sendCount_xYZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_XyZ,
|
||||
sendCount_XyZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&sendbuf_XYZ,
|
||||
sendCount_XYZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
//......................................................................................
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_x,
|
||||
recvCount_x *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_X,
|
||||
recvCount_X *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_y,
|
||||
recvCount_y *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_Y,
|
||||
recvCount_Y *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_z,
|
||||
recvCount_z *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_Z,
|
||||
recvCount_Z *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_xy,
|
||||
recvCount_xy *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_xY,
|
||||
recvCount_xY *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_Xy,
|
||||
recvCount_Xy *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_XY,
|
||||
recvCount_XY *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_xz,
|
||||
recvCount_xz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_xZ,
|
||||
recvCount_xZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_Xz,
|
||||
recvCount_Xz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_XZ,
|
||||
recvCount_XZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_yz,
|
||||
recvCount_yz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_yZ,
|
||||
recvCount_yZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_Yz,
|
||||
recvCount_Yz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_YZ,
|
||||
recvCount_YZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_xyz,
|
||||
recvCount_xyz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_xYz,
|
||||
recvCount_xYz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_Xyz,
|
||||
recvCount_Xyz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_XYz,
|
||||
recvCount_XYz *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_xyZ,
|
||||
recvCount_xyZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_xYZ,
|
||||
recvCount_xYZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_XyZ,
|
||||
recvCount_XyZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
ScaLBL_AllocateZeroCopy((void **)&recvbuf_XYZ,
|
||||
recvCount_XYZ *
|
||||
sizeof(double)); // Allocate device memory
|
||||
|
||||
/* Set up a map to the halo width=1 data structure */
|
||||
for (k = width; k < Nzh - width; k++) {
|
||||
for (j = width; j < Nyh - width; j++) {
|
||||
for (i = width; i < Nxh - width; i++) {
|
||||
int idx = k * Nxh * Nyh + j * Nxh + i;
|
||||
Map(i - width + 1, j - width + 1, k - width + 1) = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScaLBLWideHalo_Communicator::Send(double *data){
|
||||
//...................................................................................
|
||||
if (Lock==true){
|
||||
ERROR("ScaLBL Error (SendHalo): ScaLBLWideHalo_Communicator is locked -- did you forget to match Send/Recv calls?");
|
||||
}
|
||||
else{
|
||||
Lock=true;
|
||||
}
|
||||
ScaLBL_DeviceBarrier();
|
||||
//...................................................................................
|
||||
sendtag = recvtag = 1;
|
||||
//...................................................................................
|
||||
ScaLBL_Scalar_Pack(dvcSendList_x, sendCount_x,sendbuf_x, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_y, sendCount_y,sendbuf_y, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_z, sendCount_z,sendbuf_z, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_X, sendCount_X,sendbuf_X, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_Y, sendCount_Y,sendbuf_Y, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_Z, sendCount_Z,sendbuf_Z, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xy, sendCount_xy,sendbuf_xy, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xY, sendCount_xY,sendbuf_xY, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_Xy, sendCount_Xy,sendbuf_Xy, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_XY, sendCount_XY,sendbuf_XY, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xz, sendCount_xz,sendbuf_xz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xZ, sendCount_xZ,sendbuf_xZ, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_Xz, sendCount_Xz,sendbuf_Xz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_XZ, sendCount_XZ,sendbuf_XZ, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_yz, sendCount_yz,sendbuf_yz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_yZ, sendCount_yZ,sendbuf_yZ, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_Yz, sendCount_Yz,sendbuf_Yz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_YZ, sendCount_YZ,sendbuf_YZ, data, Nh);
|
||||
/* corners */
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xyz, sendCount_xyz,sendbuf_xyz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xyZ, sendCount_xyZ,sendbuf_xyZ, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xYz, sendCount_xYz,sendbuf_xYz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xYZ, sendCount_xYZ,sendbuf_xYZ, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_Xyz, sendCount_Xyz,sendbuf_Xyz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_XyZ, sendCount_XyZ,sendbuf_XyZ, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_XYz, sendCount_XYz,sendbuf_XYz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_XYZ, sendCount_XYZ,sendbuf_XYZ, data, Nh);
|
||||
//...................................................................................
|
||||
// Send / Recv all the phase indcator field values
|
||||
//...................................................................................
|
||||
req1[0] = MPI_COMM_SCALBL.Isend(sendbuf_x,sendCount_x,rank_x,sendtag+0);
|
||||
req2[0] = MPI_COMM_SCALBL.Irecv(recvbuf_X,recvCount_X,rank_X,recvtag+0);
|
||||
req1[1] = MPI_COMM_SCALBL.Isend(sendbuf_X,sendCount_X,rank_X,sendtag+1);
|
||||
req2[1] = MPI_COMM_SCALBL.Irecv(recvbuf_x,recvCount_x,rank_x,recvtag+1);
|
||||
req1[2] = MPI_COMM_SCALBL.Isend(sendbuf_y,sendCount_y,rank_y,sendtag+2);
|
||||
req2[2] = MPI_COMM_SCALBL.Irecv(recvbuf_Y,recvCount_Y,rank_Y,recvtag+2);
|
||||
req1[3] = MPI_COMM_SCALBL.Isend(sendbuf_Y,sendCount_Y,rank_Y,sendtag+3);
|
||||
req2[3] = MPI_COMM_SCALBL.Irecv(recvbuf_y,recvCount_y,rank_y,recvtag+3);
|
||||
req1[4] = MPI_COMM_SCALBL.Isend(sendbuf_z,sendCount_z,rank_z,sendtag+4);
|
||||
req2[4] = MPI_COMM_SCALBL.Irecv(recvbuf_Z,recvCount_Z,rank_Z,recvtag+4);
|
||||
req1[5] = MPI_COMM_SCALBL.Isend(sendbuf_Z,sendCount_Z,rank_Z,sendtag+5);
|
||||
req2[5] = MPI_COMM_SCALBL.Irecv(recvbuf_z,recvCount_z,rank_z,recvtag+5);
|
||||
req1[6] = MPI_COMM_SCALBL.Isend(sendbuf_xy,sendCount_xy,rank_xy,sendtag+6);
|
||||
req2[6] = MPI_COMM_SCALBL.Irecv(recvbuf_XY,recvCount_XY,rank_XY,recvtag+6);
|
||||
req1[7] = MPI_COMM_SCALBL.Isend(sendbuf_XY,sendCount_XY,rank_XY,sendtag+7);
|
||||
req2[7] = MPI_COMM_SCALBL.Irecv(recvbuf_xy,recvCount_xy,rank_xy,recvtag+7);
|
||||
req1[8] = MPI_COMM_SCALBL.Isend(sendbuf_Xy,sendCount_Xy,rank_Xy,sendtag+8);
|
||||
req2[8] = MPI_COMM_SCALBL.Irecv(recvbuf_xY,recvCount_xY,rank_xY,recvtag+8);
|
||||
req1[9] = MPI_COMM_SCALBL.Isend(sendbuf_xY,sendCount_xY,rank_xY,sendtag+9);
|
||||
req2[9] = MPI_COMM_SCALBL.Irecv(recvbuf_Xy,recvCount_Xy,rank_Xy,recvtag+9);
|
||||
req1[10] = MPI_COMM_SCALBL.Isend(sendbuf_xz,sendCount_xz,rank_xz,sendtag+10);
|
||||
req2[10] = MPI_COMM_SCALBL.Irecv(recvbuf_XZ,recvCount_XZ,rank_XZ,recvtag+10);
|
||||
req1[11] = MPI_COMM_SCALBL.Isend(sendbuf_XZ,sendCount_XZ,rank_XZ,sendtag+11);
|
||||
req2[11] = MPI_COMM_SCALBL.Irecv(recvbuf_xz,recvCount_xz,rank_xz,recvtag+11);
|
||||
req1[12] = MPI_COMM_SCALBL.Isend(sendbuf_Xz,sendCount_Xz,rank_Xz,sendtag+12);
|
||||
req2[12] = MPI_COMM_SCALBL.Irecv(recvbuf_xZ,recvCount_xZ,rank_xZ,recvtag+12);
|
||||
req1[13] = MPI_COMM_SCALBL.Isend(sendbuf_xZ,sendCount_xZ,rank_xZ,sendtag+13);
|
||||
req2[13] = MPI_COMM_SCALBL.Irecv(recvbuf_Xz,recvCount_Xz,rank_Xz,recvtag+13);
|
||||
req1[14] = MPI_COMM_SCALBL.Isend(sendbuf_yz,sendCount_yz,rank_yz,sendtag+14);
|
||||
req2[14] = MPI_COMM_SCALBL.Irecv(recvbuf_YZ,recvCount_YZ,rank_YZ,recvtag+14);
|
||||
req1[15] = MPI_COMM_SCALBL.Isend(sendbuf_YZ,sendCount_YZ,rank_YZ,sendtag+15);
|
||||
req2[15] = MPI_COMM_SCALBL.Irecv(recvbuf_yz,recvCount_yz,rank_yz,recvtag+15);
|
||||
req1[16] = MPI_COMM_SCALBL.Isend(sendbuf_Yz,sendCount_Yz,rank_Yz,sendtag+16);
|
||||
req2[16] = MPI_COMM_SCALBL.Irecv(recvbuf_yZ,recvCount_yZ,rank_yZ,recvtag+16);
|
||||
req1[17] = MPI_COMM_SCALBL.Isend(sendbuf_yZ,sendCount_yZ,rank_yZ,sendtag+17);
|
||||
req2[17] = MPI_COMM_SCALBL.Irecv(recvbuf_Yz,recvCount_Yz,rank_Yz,recvtag+17);
|
||||
/* Corners */
|
||||
req1[18] = MPI_COMM_SCALBL.Isend(sendbuf_xyz,sendCount_xyz,rank_xyz,sendtag+18);
|
||||
req2[18] = MPI_COMM_SCALBL.Irecv(recvbuf_XYZ,recvCount_XYZ,rank_XYZ,recvtag+18);
|
||||
req1[19] = MPI_COMM_SCALBL.Isend(sendbuf_XYz,sendCount_XYz,rank_XYz,sendtag+19);
|
||||
req2[19] = MPI_COMM_SCALBL.Irecv(recvbuf_xyZ,recvCount_xyZ,rank_xyZ,recvtag+19);
|
||||
req1[20] = MPI_COMM_SCALBL.Isend(sendbuf_Xyz,sendCount_Xyz,rank_Xyz,sendtag+20);
|
||||
req2[20] = MPI_COMM_SCALBL.Irecv(recvbuf_xYZ,recvCount_xYZ,rank_xYZ,recvtag+20);
|
||||
req1[21] = MPI_COMM_SCALBL.Isend(sendbuf_xYz,sendCount_xYz,rank_xYz,sendtag+21);
|
||||
req2[21] = MPI_COMM_SCALBL.Irecv(recvbuf_XyZ,recvCount_XyZ,rank_XyZ,recvtag+21);
|
||||
req1[22] = MPI_COMM_SCALBL.Isend(sendbuf_xyZ,sendCount_xyZ,rank_xyZ,sendtag+22);
|
||||
req2[22] = MPI_COMM_SCALBL.Irecv(recvbuf_XYz,recvCount_XYz,rank_XYz,recvtag+22);
|
||||
req1[23] = MPI_COMM_SCALBL.Isend(sendbuf_XYZ,sendCount_XYZ,rank_XYZ,sendtag+23);
|
||||
req2[23] = MPI_COMM_SCALBL.Irecv(recvbuf_xyz,recvCount_xyz,rank_xyz,recvtag+23);
|
||||
req1[24] = MPI_COMM_SCALBL.Isend(sendbuf_XyZ,sendCount_XyZ,rank_XyZ,sendtag+24);
|
||||
req2[24] = MPI_COMM_SCALBL.Irecv(recvbuf_xYz,recvCount_xYz,rank_xYz,recvtag+24);
|
||||
req1[25] = MPI_COMM_SCALBL.Isend(sendbuf_xYZ,sendCount_xYZ,rank_xYZ,sendtag+25);
|
||||
req2[25] = MPI_COMM_SCALBL.Irecv(recvbuf_Xyz,recvCount_Xyz,rank_Xyz,recvtag+25);
|
||||
//...................................................................................
|
||||
|
||||
void ScaLBLWideHalo_Communicator::Send(double *data) {
|
||||
//...................................................................................
|
||||
if (Lock == true) {
|
||||
ERROR("ScaLBL Error (SendHalo): ScaLBLWideHalo_Communicator is locked "
|
||||
"-- did you forget to match Send/Recv calls?");
|
||||
} else {
|
||||
Lock = true;
|
||||
}
|
||||
ScaLBL_DeviceBarrier();
|
||||
//...................................................................................
|
||||
sendtag = recvtag = 1;
|
||||
//...................................................................................
|
||||
ScaLBL_Scalar_Pack(dvcSendList_x, sendCount_x, sendbuf_x, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_y, sendCount_y, sendbuf_y, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_z, sendCount_z, sendbuf_z, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_X, sendCount_X, sendbuf_X, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_Y, sendCount_Y, sendbuf_Y, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_Z, sendCount_Z, sendbuf_Z, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xy, sendCount_xy, sendbuf_xy, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xY, sendCount_xY, sendbuf_xY, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_Xy, sendCount_Xy, sendbuf_Xy, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_XY, sendCount_XY, sendbuf_XY, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xz, sendCount_xz, sendbuf_xz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xZ, sendCount_xZ, sendbuf_xZ, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_Xz, sendCount_Xz, sendbuf_Xz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_XZ, sendCount_XZ, sendbuf_XZ, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_yz, sendCount_yz, sendbuf_yz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_yZ, sendCount_yZ, sendbuf_yZ, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_Yz, sendCount_Yz, sendbuf_Yz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_YZ, sendCount_YZ, sendbuf_YZ, data, Nh);
|
||||
/* corners */
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xyz, sendCount_xyz, sendbuf_xyz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xyZ, sendCount_xyZ, sendbuf_xyZ, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xYz, sendCount_xYz, sendbuf_xYz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_xYZ, sendCount_xYZ, sendbuf_xYZ, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_Xyz, sendCount_Xyz, sendbuf_Xyz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_XyZ, sendCount_XyZ, sendbuf_XyZ, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_XYz, sendCount_XYz, sendbuf_XYz, data, Nh);
|
||||
ScaLBL_Scalar_Pack(dvcSendList_XYZ, sendCount_XYZ, sendbuf_XYZ, data, Nh);
|
||||
//...................................................................................
|
||||
// Send / Recv all the phase indcator field values
|
||||
//...................................................................................
|
||||
req1[0] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_x, sendCount_x, rank_x, sendtag + 0);
|
||||
req2[0] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_X, recvCount_X, rank_X, recvtag + 0);
|
||||
req1[1] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_X, sendCount_X, rank_X, sendtag + 1);
|
||||
req2[1] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_x, recvCount_x, rank_x, recvtag + 1);
|
||||
req1[2] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_y, sendCount_y, rank_y, sendtag + 2);
|
||||
req2[2] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_Y, recvCount_Y, rank_Y, recvtag + 2);
|
||||
req1[3] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_Y, sendCount_Y, rank_Y, sendtag + 3);
|
||||
req2[3] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_y, recvCount_y, rank_y, recvtag + 3);
|
||||
req1[4] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_z, sendCount_z, rank_z, sendtag + 4);
|
||||
req2[4] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_Z, recvCount_Z, rank_Z, recvtag + 4);
|
||||
req1[5] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_Z, sendCount_Z, rank_Z, sendtag + 5);
|
||||
req2[5] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_z, recvCount_z, rank_z, recvtag + 5);
|
||||
req1[6] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_xy, sendCount_xy, rank_xy, sendtag + 6);
|
||||
req2[6] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_XY, recvCount_XY, rank_XY, recvtag + 6);
|
||||
req1[7] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_XY, sendCount_XY, rank_XY, sendtag + 7);
|
||||
req2[7] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_xy, recvCount_xy, rank_xy, recvtag + 7);
|
||||
req1[8] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_Xy, sendCount_Xy, rank_Xy, sendtag + 8);
|
||||
req2[8] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_xY, recvCount_xY, rank_xY, recvtag + 8);
|
||||
req1[9] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_xY, sendCount_xY, rank_xY, sendtag + 9);
|
||||
req2[9] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_Xy, recvCount_Xy, rank_Xy, recvtag + 9);
|
||||
req1[10] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_xz, sendCount_xz, rank_xz, sendtag + 10);
|
||||
req2[10] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_XZ, recvCount_XZ, rank_XZ, recvtag + 10);
|
||||
req1[11] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_XZ, sendCount_XZ, rank_XZ, sendtag + 11);
|
||||
req2[11] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_xz, recvCount_xz, rank_xz, recvtag + 11);
|
||||
req1[12] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_Xz, sendCount_Xz, rank_Xz, sendtag + 12);
|
||||
req2[12] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_xZ, recvCount_xZ, rank_xZ, recvtag + 12);
|
||||
req1[13] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_xZ, sendCount_xZ, rank_xZ, sendtag + 13);
|
||||
req2[13] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_Xz, recvCount_Xz, rank_Xz, recvtag + 13);
|
||||
req1[14] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_yz, sendCount_yz, rank_yz, sendtag + 14);
|
||||
req2[14] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_YZ, recvCount_YZ, rank_YZ, recvtag + 14);
|
||||
req1[15] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_YZ, sendCount_YZ, rank_YZ, sendtag + 15);
|
||||
req2[15] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_yz, recvCount_yz, rank_yz, recvtag + 15);
|
||||
req1[16] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_Yz, sendCount_Yz, rank_Yz, sendtag + 16);
|
||||
req2[16] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_yZ, recvCount_yZ, rank_yZ, recvtag + 16);
|
||||
req1[17] =
|
||||
MPI_COMM_SCALBL.Isend(sendbuf_yZ, sendCount_yZ, rank_yZ, sendtag + 17);
|
||||
req2[17] =
|
||||
MPI_COMM_SCALBL.Irecv(recvbuf_Yz, recvCount_Yz, rank_Yz, recvtag + 17);
|
||||
/* Corners */
|
||||
req1[18] = MPI_COMM_SCALBL.Isend(sendbuf_xyz, sendCount_xyz, rank_xyz,
|
||||
sendtag + 18);
|
||||
req2[18] = MPI_COMM_SCALBL.Irecv(recvbuf_XYZ, recvCount_XYZ, rank_XYZ,
|
||||
recvtag + 18);
|
||||
req1[19] = MPI_COMM_SCALBL.Isend(sendbuf_XYz, sendCount_XYz, rank_XYz,
|
||||
sendtag + 19);
|
||||
req2[19] = MPI_COMM_SCALBL.Irecv(recvbuf_xyZ, recvCount_xyZ, rank_xyZ,
|
||||
recvtag + 19);
|
||||
req1[20] = MPI_COMM_SCALBL.Isend(sendbuf_Xyz, sendCount_Xyz, rank_Xyz,
|
||||
sendtag + 20);
|
||||
req2[20] = MPI_COMM_SCALBL.Irecv(recvbuf_xYZ, recvCount_xYZ, rank_xYZ,
|
||||
recvtag + 20);
|
||||
req1[21] = MPI_COMM_SCALBL.Isend(sendbuf_xYz, sendCount_xYz, rank_xYz,
|
||||
sendtag + 21);
|
||||
req2[21] = MPI_COMM_SCALBL.Irecv(recvbuf_XyZ, recvCount_XyZ, rank_XyZ,
|
||||
recvtag + 21);
|
||||
req1[22] = MPI_COMM_SCALBL.Isend(sendbuf_xyZ, sendCount_xyZ, rank_xyZ,
|
||||
sendtag + 22);
|
||||
req2[22] = MPI_COMM_SCALBL.Irecv(recvbuf_XYz, recvCount_XYz, rank_XYz,
|
||||
recvtag + 22);
|
||||
req1[23] = MPI_COMM_SCALBL.Isend(sendbuf_XYZ, sendCount_XYZ, rank_XYZ,
|
||||
sendtag + 23);
|
||||
req2[23] = MPI_COMM_SCALBL.Irecv(recvbuf_xyz, recvCount_xyz, rank_xyz,
|
||||
recvtag + 23);
|
||||
req1[24] = MPI_COMM_SCALBL.Isend(sendbuf_XyZ, sendCount_XyZ, rank_XyZ,
|
||||
sendtag + 24);
|
||||
req2[24] = MPI_COMM_SCALBL.Irecv(recvbuf_xYz, recvCount_xYz, rank_xYz,
|
||||
recvtag + 24);
|
||||
req1[25] = MPI_COMM_SCALBL.Isend(sendbuf_xYZ, sendCount_xYZ, rank_xYZ,
|
||||
sendtag + 25);
|
||||
req2[25] = MPI_COMM_SCALBL.Irecv(recvbuf_Xyz, recvCount_Xyz, rank_Xyz,
|
||||
recvtag + 25);
|
||||
//...................................................................................
|
||||
}
|
||||
|
||||
ScaLBLWideHalo_Communicator::~ScaLBLWideHalo_Communicator() {}
|
||||
void ScaLBLWideHalo_Communicator::Recv(double *data) {
|
||||
|
||||
ScaLBLWideHalo_Communicator::~ScaLBLWideHalo_Communicator()
|
||||
{
|
||||
//...................................................................................
|
||||
Utilities::MPI::waitAll(26, req1);
|
||||
Utilities::MPI::waitAll(26, req2);
|
||||
ScaLBL_DeviceBarrier();
|
||||
//...................................................................................
|
||||
//printf("Ready to unpack %i to x\n",recvCount_x);
|
||||
//printf(" print first 10 values...\n");
|
||||
//for (int idx=0; idx<10; idx++) printf(" recvBuf[%i]=%f \n",idx,recvbuf_x[idx]);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_x, recvCount_x, recvbuf_x, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_y, recvCount_y, recvbuf_y, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_X, recvCount_X, recvbuf_X, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_Y, recvCount_Y, recvbuf_Y, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xy, recvCount_xy, recvbuf_xy, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xY, recvCount_xY, recvbuf_xY, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_Xy, recvCount_Xy, recvbuf_Xy, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_XY, recvCount_XY, recvbuf_XY, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_z, recvCount_z, recvbuf_z, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xz, recvCount_xz, recvbuf_xz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_Xz, recvCount_Xz, recvbuf_Xz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_yz, recvCount_yz, recvbuf_yz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_Yz, recvCount_Yz, recvbuf_Yz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_Z, recvCount_Z, recvbuf_Z, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xZ, recvCount_xZ, recvbuf_xZ, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_XZ, recvCount_XZ, recvbuf_XZ, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_yZ, recvCount_yZ, recvbuf_yZ, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_YZ, recvCount_YZ, recvbuf_YZ, data, Nh);
|
||||
/* corners */
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xyz, recvCount_xyz, recvbuf_xyz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xYz, recvCount_xYz, recvbuf_xYz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xyZ, recvCount_xyZ, recvbuf_xyZ, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xYZ, recvCount_xYZ, recvbuf_xYZ, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_Xyz, recvCount_Xyz, recvbuf_Xyz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_XYz, recvCount_XYz, recvbuf_XYz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_XyZ, recvCount_XyZ, recvbuf_XyZ, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_XYZ, recvCount_XYZ, recvbuf_XYZ, data, Nh);
|
||||
//...................................................................................
|
||||
Lock = false; // unlock the communicator after communications complete
|
||||
//...................................................................................
|
||||
}
|
||||
void ScaLBLWideHalo_Communicator::Recv(double *data){
|
||||
|
||||
//...................................................................................
|
||||
Utilities::MPI::waitAll(26,req1);
|
||||
Utilities::MPI::waitAll(26,req2);
|
||||
ScaLBL_DeviceBarrier();
|
||||
//...................................................................................
|
||||
//printf("Ready to unpack %i to x\n",recvCount_x);
|
||||
//printf(" print first 10 values...\n");
|
||||
//for (int idx=0; idx<10; idx++) printf(" recvBuf[%i]=%f \n",idx,recvbuf_x[idx]);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_x, recvCount_x,recvbuf_x, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_y, recvCount_y,recvbuf_y, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_X, recvCount_X,recvbuf_X, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_Y, recvCount_Y,recvbuf_Y, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xy, recvCount_xy,recvbuf_xy, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xY, recvCount_xY,recvbuf_xY, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_Xy, recvCount_Xy,recvbuf_Xy, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_XY, recvCount_XY,recvbuf_XY, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_z, recvCount_z,recvbuf_z, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xz, recvCount_xz,recvbuf_xz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_Xz, recvCount_Xz,recvbuf_Xz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_yz, recvCount_yz,recvbuf_yz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_Yz, recvCount_Yz,recvbuf_Yz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_Z, recvCount_Z,recvbuf_Z, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xZ, recvCount_xZ,recvbuf_xZ, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_XZ, recvCount_XZ,recvbuf_XZ, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_yZ, recvCount_yZ,recvbuf_yZ, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_YZ, recvCount_YZ,recvbuf_YZ, data, Nh);
|
||||
/* corners */
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xyz, recvCount_xyz,recvbuf_xyz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xYz, recvCount_xYz,recvbuf_xYz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xyZ, recvCount_xyZ,recvbuf_xyZ, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_xYZ, recvCount_xYZ,recvbuf_xYZ, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_Xyz, recvCount_Xyz,recvbuf_Xyz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_XYz, recvCount_XYz,recvbuf_XYz, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_XyZ, recvCount_XyZ,recvbuf_XyZ, data, Nh);
|
||||
ScaLBL_Scalar_Unpack(dvcRecvList_XYZ, recvCount_XYZ,recvbuf_XYZ, data, Nh);
|
||||
//...................................................................................
|
||||
Lock=false; // unlock the communicator after communications complete
|
||||
//...................................................................................
|
||||
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user