3 Commits

378 changed files with 13477 additions and 90274 deletions

View File

@@ -1,108 +0,0 @@
# 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 {}
---
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
...

View File

@@ -1,13 +0,0 @@
# 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
...

View File

@@ -1,148 +0,0 @@
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
#sudo apt-get install -y libtool-ltdl
#sudo apt-get install -y libtool-ltdl-devel
#curl "https://wci.llnl.gov/sites/wci/files/2021-01/silo-4.10.2.tgz" -o "silo-4.10.2.tar.gz"
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
#-DCMAKE_C_COMPILER:PATH=$MPI_DIR/bin/mpicc \
#-DCMAKE_CXX_COMPILER:PATH=$MPI_DIR/bin/mpicxx \
#-DCMAKE_C_FLAGS="-O3 -fPIC" \
#-DCMAKE_CXX_FLAGS="-O3 -fPIC " \
#-DCMAKE_CXX_STANDARD=14 \
#-DMPIEXEC=$MPI_DIR/mpirun \
#-DUSE_EXT_MPI_FOR_SERIAL_TESTS:BOOL=TRUE \
#-DCMAKE_BUILD_TYPE:STRING=Release \
#-DHDF5_DIRECTORY=$LBPM_HDF5_DIR \
#-DHDF5_LIB=$LBPM_HDF5_DIR/lib/libhdf5.a \
#-DUSE_SILO=1 \
#-DSILO_LIB=$LBPM_SILO_DIR/lib/libsiloh5.a \
#-DSILO_DIRECTORY=$LBPM_SILO_DIR \
#-DUSE_NETCDF=0 \
#-DUSE_CUDA=0 \
#-DUSE_TIMER=0 \
#$GITHUB_WORKSPACE/LBPM
cd ..
- name: build and make
run: |
cd build
make
sudo make install
cd ..
- name: tests
run: |
cd build
ctest

View File

@@ -1,41 +0,0 @@
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

View File

@@ -1,194 +1,170 @@
# Set some CMake properties
CMAKE_MINIMUM_REQUIRED( VERSION 3.9 )
if( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.20.0")
CMAKE_POLICY( SET CMP0115 OLD )
endif()
MESSAGE("====================")
MESSAGE("Configuring LBPM-WIA")
MESSAGE("====================")
# Set the project name
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/...)
# Initialize the project
PROJECT( ${PROJ} LANGUAGES CXX)
# Prevent users from building in place
IF ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}" )
MESSAGE( FATAL_ERROR "Building code in place is a bad idea" )
ENDIF()
# Set the default C++ standard
SET( CMAKE_CXX_EXTENSIONS OFF )
IF ( NOT CMAKE_CXX_STANDARD )
IF ( CXX_STD )
MESSAGE( FATAL_ERROR "CXX_STD is obsolete, please set CMAKE_CXX_STANDARD" )
ENDIF()
SET( CMAKE_CXX_STANDARD 14 )
ENDIF()
IF ( ( "${CMAKE_CXX_STANDARD}" GREATER "90" ) OR ( "${CMAKE_CXX_STANDARD}" LESS "14" ) )
MESSAGE( FATAL_ERROR "C++14 or newer required" )
ENDIF()
# Set source/install paths
SET( ${PROJ}_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" )
SET( ${PROJ}_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}" )
IF( ${PROJ}_INSTALL_DIR )
SET( ${PROJ}_INSTALL_DIR "${${PROJ}_INSTALL_DIR}" )
ELSEIF( PREFIX )
SET( ${PROJ}_INSTALL_DIR "${PREFIX}" )
ELSEIF( NOT ${PROJ}_INSTALL_DIR )
SET( ${PROJ}_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}" )
ENDIF()
INCLUDE_DIRECTORIES( "${${PROJ}_INSTALL_DIR}/include" )
SET( CMAKE_MODULE_PATH ${${PROJ}_SOURCE_DIR} ${${PROJ}_SOURCE_DIR}/cmake )
# Include macros
INCLUDE( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macros.cmake" )
INCLUDE( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/libraries.cmake" )
INCLUDE( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/LBPM-macros.cmake" )
# Check if we are only compiling docs
CHECK_ENABLE_FLAG( ONLY_BUILD_DOCS 0 )
# Set testing paramaters
SET( DROP_METHOD "http" )
SET( DROP_SITE "" )
SET( DROP_LOCATION "/CDash/submit.php?project=LBPM-WIA" )
SET( TRIGGER_SITE "" )
SET( DROP_SITE_CDASH TRUE )
ENABLE_TESTING()
INCLUDE( CTest )
# Check the compile mode and compile flags
IF ( NOT ONLY_BUILD_DOCS )
CONFIGURE_SYSTEM()
ENDIF()
# Add some directories to include
INCLUDE_DIRECTORIES( "${${PROJ}_INSTALL_DIR}/include" )
# Create the target for documentation
ADD_CUSTOM_TARGET( doc )
ADD_CUSTOM_TARGET( latex_docs )
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 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" )
SET( DOXYFILE_OUTPUT_DIR "${${PROJ}_INSTALL_DIR}/doc" )
SET( DOXYFILE_SRC_HTML_DIR "${${PROJ}_SOURCE_DIR}/doxygen/html" )
SET( DOXYFILE_SOURCE_DIR "${${PROJ}_SOURCE_DIR}" )
SET( REL_PACKAGE_HTML "" )
SET( DOXYGEN_MACROS "" )
MESSAGE("DOXYGEN_MACROS = ${DOXYGEN_MACROS}")
INCLUDE( "${${PROJ}_SOURCE_DIR}/cmake/UseDoxygen.cmake" )
IF ( DOXYGEN_FOUND )
ADD_DEPENDENCIES( doxygen latex_docs )
ADD_DEPENDENCIES( doc latex_docs doxygen )
ELSE()
SET( USE_DOXYGEN 0 )
ENDIF()
ENDIF()
# Create custom targets for build-test, check, and distclean
ADD_CUSTOM_TARGET( build-test )
ADD_CUSTOM_TARGET( build-examples )
ADD_CUSTOM_TARGET( check COMMAND make test )
ADD_DISTCLEAN( analysis null_timer tests liblbpm-wia.* cpu gpu cuda hip example common IO threadpool StackTrace )
# Check for CUDA
CHECK_ENABLE_FLAG( USE_CUDA 0 )
CHECK_ENABLE_FLAG( USE_HIP 0 )
NULL_USE( CMAKE_CUDA_FLAGS )
IF ( USE_CUDA )
ADD_DEFINITIONS( -DUSE_CUDA )
ENABLE_LANGUAGE( CUDA )
ELSEIF ( USE_HIP )
IF ( NOT DEFINED HIP_PATH )
IF ( NOT DEFINED ENV{HIP_PATH} )
SET( HIP_PATH "/opt/rocm/hip" CACHE PATH "Path to which HIP has been installed" )
ELSE()
SET( HIP_PATH $ENV{HIP_PATH} CACHE PATH "Path to which HIP has been installed" )
ENDIF()
ENDIF()
SET( CMAKE_MODULE_PATH "${HIP_PATH}/cmake" ${CMAKE_MODULE_PATH} )
FIND_PACKAGE( HIP REQUIRED )
FIND_PACKAGE( CUDA QUIET )
MESSAGE( "HIP Found")
MESSAGE( " HIP version: ${HIP_VERSION_STRING}")
MESSAGE( " HIP platform: ${HIP_PLATFORM}")
MESSAGE( " HIP Include Path: ${HIP_INCLUDE_DIRS}")
MESSAGE( " HIP Libraries: ${HIP_LIBRARIES}")
ADD_DEFINITIONS( -DUSE_HIP )
ENDIF()
# Configure external packages
IF ( NOT ONLY_BUILD_DOCS )
CONFIGURE_MPI() # MPI must be before other libraries
CONFIGURE_MIC()
CONFIGURE_HDF5()
CONFIGURE_NETCDF()
CONFIGURE_SILO()
CONFIGURE_LBPM()
CONFIGURE_TIMER( 0 "${${PROJ}_INSTALL_DIR}/null_timer" FALSE )
CONFIGURE_LINE_COVERAGE()
# Set the external library link list
SET( EXTERNAL_LIBS ${EXTERNAL_LIBS} ${TIMER_LIBS} )
ENDIF()
# Macro to create 1,2,4 processor tests
MACRO( ADD_LBPM_TEST_1_2_4 EXENAME ${ARGN} )
ADD_LBPM_TEST( ${EXENAME} ${ARGN} )
ADD_LBPM_TEST_PARALLEL( ${EXENAME} 2 ${ARGN} )
ADD_LBPM_TEST_PARALLEL( ${EXENAME} 4 ${ARGN} )
ENDMACRO()
# Add the src directories
IF ( NOT ONLY_BUILD_DOCS )
BEGIN_PACKAGE_CONFIG( lbpm-wia-library )
ADD_PACKAGE_SUBDIRECTORY( common )
ADD_PACKAGE_SUBDIRECTORY( analysis )
ADD_PACKAGE_SUBDIRECTORY( IO )
ADD_PACKAGE_SUBDIRECTORY( threadpool )
ADD_PACKAGE_SUBDIRECTORY( StackTrace )
ADD_PACKAGE_SUBDIRECTORY( models )
IF ( USE_CUDA )
ADD_PACKAGE_SUBDIRECTORY( cuda )
ELSEIF ( USE_HIP )
ADD_SUBDIRECTORY( hip )
SET( LBPM_LIBRARIES lbpm-hip lbpm-wia )
ELSE()
ADD_PACKAGE_SUBDIRECTORY( cpu )
ENDIF()
INSTALL_LBPM_TARGET( lbpm-wia-library )
ADD_SUBDIRECTORY( tests )
ADD_SUBDIRECTORY( example )
#ADD_SUBDIRECTORY( workflows )
INSTALL_PROJ_LIB()
ENDIF()
# Set some CMake properties
CMAKE_MINIMUM_REQUIRED( VERSION 3.9 )
MESSAGE("====================")
MESSAGE("Configuring LBPM-WIA")
MESSAGE("====================")
# Set the project name
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
PROJECT( ${PROJ} LANGUAGES CXX )
# Prevent users from building in place
IF ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}" )
MESSAGE( FATAL_ERROR "Building code in place is a bad idea" )
ENDIF()
# Set the default C++ standard
SET( CMAKE_CXX_EXTENSIONS OFF )
IF ( NOT CMAKE_CXX_STANDARD )
IF ( CXX_STD )
MESSAGE( FATAL_ERROR "CXX_STD is obsolete, please set CMAKE_CXX_STANDARD" )
ENDIF()
SET( CMAKE_CXX_STANDARD 14 )
ENDIF()
IF ( ( "${CMAKE_CXX_STANDARD}" GREATER "90" ) OR ( "${CMAKE_CXX_STANDARD}" LESS "14" ) )
MESSAGE( FATAL_ERROR "C++14 or newer required" )
ENDIF()
# Set source/install paths
SET( ${PROJ}_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" )
SET( ${PROJ}_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}" )
IF( ${PROJ}_INSTALL_DIR )
SET( ${PROJ}_INSTALL_DIR "${${PROJ}_INSTALL_DIR}" )
ELSEIF( PREFIX )
SET( ${PROJ}_INSTALL_DIR "${PREFIX}" )
ELSEIF( NOT ${PROJ}_INSTALL_DIR )
SET( ${PROJ}_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}" )
ENDIF()
INCLUDE_DIRECTORIES( "${${PROJ}_INSTALL_DIR}/include" )
SET( CMAKE_MODULE_PATH ${${PROJ}_SOURCE_DIR} ${${PROJ}_SOURCE_DIR}/cmake )
# Include macros
INCLUDE( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macros.cmake" )
INCLUDE( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/libraries.cmake" )
INCLUDE( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/LBPM-macros.cmake" )
# Check if we are only compiling docs
CHECK_ENABLE_FLAG( ONLY_BUILD_DOCS 0 )
# Set testing paramaters
SET( DROP_METHOD "http" )
SET( DROP_SITE "" )
SET( DROP_LOCATION "/CDash/submit.php?project=LBPM-WIA" )
SET( TRIGGER_SITE "" )
SET( DROP_SITE_CDASH TRUE )
ENABLE_TESTING()
INCLUDE( CTest )
# Check the compile mode and compile flags
IF ( NOT ONLY_BUILD_DOCS )
CONFIGURE_SYSTEM()
ENDIF()
# Add some directories to include
INCLUDE_DIRECTORIES( "${${PROJ}_INSTALL_DIR}/include" )
# Create the target for documentation
ADD_CUSTOM_TARGET( doc )
ADD_CUSTOM_TARGET( latex_docs )
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_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" )
SET( DOXYFILE_OUTPUT_DIR "${${PROJ}_INSTALL_DIR}/doc" )
SET( DOXYFILE_SRC_HTML_DIR "${${PROJ}_SOURCE_DIR}/doxygen/html" )
SET( DOXYFILE_SOURCE_DIR "${${PROJ}_SOURCE_DIR}" )
SET( REL_PACKAGE_HTML "" )
SET( DOXYGEN_MACROS "" )
MESSAGE("DOXYGEN_MACROS = ${DOXYGEN_MACROS}")
INCLUDE( "${${PROJ}_SOURCE_DIR}/cmake/UseDoxygen.cmake" )
IF ( DOXYGEN_FOUND )
ADD_DEPENDENCIES( doxygen latex_docs )
ADD_DEPENDENCIES( doc latex_docs doxygen )
ELSE()
SET( USE_DOXYGEN 0 )
ENDIF()
ENDIF()
# Create custom targets for build-test, check, and distclean
ADD_CUSTOM_TARGET( build-test )
ADD_CUSTOM_TARGET( build-examples )
ADD_CUSTOM_TARGET( check COMMAND make test )
ADD_DISTCLEAN( analysis null_timer tests liblbpm-wia.* cpu gpu example common IO threadpool StackTrace )
# Check for CUDA
CHECK_ENABLE_FLAG( USE_CUDA 0 )
NULL_USE( CMAKE_CUDA_FLAGS )
IF ( USE_CUDA )
ADD_DEFINITIONS( -DUSE_CUDA )
ENABLE_LANGUAGE( CUDA )
ENDIF()
# Configure external packages
IF ( NOT ONLY_BUILD_DOCS )
CONFIGURE_MPI() # MPI must be before other libraries
CONFIGURE_MIC()
CONFIGURE_NETCDF()
CONFIGURE_SILO()
CONFIGURE_LBPM()
CONFIGURE_TIMER( 0 "${${PROJ}_INSTALL_DIR}/null_timer" )
CONFIGURE_LINE_COVERAGE()
# Set the external library link list
SET( EXTERNAL_LIBS ${EXTERNAL_LIBS} ${TIMER_LIBS} )
ENDIF()
# Macro to create 1,2,4 processor tests
MACRO( ADD_LBPM_TEST_1_2_4 EXENAME ${ARGN} )
ADD_LBPM_TEST( ${EXENAME} ${ARGN} )
ADD_LBPM_TEST_PARALLEL( ${EXENAME} 2 ${ARGN} )
ADD_LBPM_TEST_PARALLEL( ${EXENAME} 4 ${ARGN} )
ENDMACRO()
# Add the src directories
IF ( NOT ONLY_BUILD_DOCS )
BEGIN_PACKAGE_CONFIG( lbpm-wia-library )
ADD_PACKAGE_SUBDIRECTORY( common )
ADD_PACKAGE_SUBDIRECTORY( analysis )
ADD_PACKAGE_SUBDIRECTORY( IO )
ADD_PACKAGE_SUBDIRECTORY( threadpool )
ADD_PACKAGE_SUBDIRECTORY( StackTrace )
ADD_PACKAGE_SUBDIRECTORY( models )
IF ( USE_CUDA )
ADD_PACKAGE_SUBDIRECTORY( gpu )
ELSE()
ADD_PACKAGE_SUBDIRECTORY( cpu )
ENDIF()
INSTALL_LBPM_TARGET( lbpm-wia-library )
ADD_SUBDIRECTORY( tests )
ADD_SUBDIRECTORY( example )
#ADD_SUBDIRECTORY( workflows )
INSTALL_PROJ_LIB()
ENDIF()

View File

@@ -1,283 +0,0 @@
#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

View File

@@ -1,585 +0,0 @@
#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

View File

@@ -1,169 +0,0 @@
// 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

View File

@@ -1,348 +0,0 @@
// 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

View File

@@ -25,9 +25,9 @@ namespace IO {
// Find a character in a line
inline size_t find( const char *line, char token )
{
size_t i = 0;
size_t i=0;
while ( 1 ) {
if ( line[i] == token || line[i] < 32 || line[i] == 0 )
if ( line[i]==token || line[i]<32 || line[i]==0 )
break;
++i;
}
@@ -36,17 +36,17 @@ inline size_t find( const char *line, char token )
// Remove preceeding/trailing whitespace
inline std::string deblank( const std::string &str )
inline std::string deblank( const std::string& str )
{
size_t i1 = str.size();
size_t i2 = 0;
for ( size_t i = 0; i < str.size(); i++ ) {
if ( str[i] != ' ' && str[i] >= 32 ) {
i1 = std::min( i1, i );
i2 = std::max( i2, i );
for (size_t i=0; i<str.size(); i++) {
if ( str[i]!=' ' && str[i]>=32 ) {
i1 = std::min(i1,i);
i2 = std::max(i2,i);
}
}
return str.substr( i1, i2 - i1 + 1 );
return str.substr(i1,i2-i1+1);
}
@@ -57,14 +57,14 @@ inline std::vector<std::string> splitList( const char *line, const char token )
size_t i1 = 0;
size_t i2 = 0;
while ( 1 ) {
if ( line[i2] == token || line[i2] < 32 ) {
std::string tmp( &line[i1], i2 - i1 );
tmp = deblank( tmp );
if ( line[i2]==token || line[i2]<32 ) {
std::string tmp(&line[i1],i2-i1);
tmp = deblank(tmp);
if ( !tmp.empty() )
list.push_back( tmp );
i1 = i2 + 1;
list.push_back(tmp);
i1 = i2+1;
}
if ( line[i2] == 0 )
if ( line[i2]==0 )
break;
i2++;
}
@@ -72,6 +72,8 @@ inline std::vector<std::string> splitList( const char *line, const char token )
}
} // namespace IO
};
#endif

View File

@@ -29,7 +29,6 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Mesh.h"
#include "IO/IOHelpers.h"
#include "common/Utilities.h"
#include <limits>
@@ -50,110 +49,104 @@ inline Point nullPoint()
/****************************************************
* Mesh *
****************************************************/
Mesh::Mesh() {}
Mesh::~Mesh() {}
* Mesh *
****************************************************/
Mesh::Mesh( )
{
}
Mesh::~Mesh( )
{
}
/****************************************************
* MeshDataStruct *
****************************************************/
#define checkResult( pass, msg ) \
do { \
if ( !( pass ) ) { \
if ( abort ) \
ERROR( msg ); \
return false; \
} \
} while ( 0 )
bool MeshDataStruct::check( bool abort ) const
* MeshDataStruct *
****************************************************/
bool MeshDataStruct::check() const
{
for ( const auto &var : vars ) {
checkResult( var->type == VariableType::NodeVariable ||
var->type == VariableType::EdgeVariable ||
var->type == VariableType::SurfaceVariable ||
var->type == VariableType::VolumeVariable,
"Invalid data type" );
checkResult( !var->data.empty(), "Variable data is empty" );
enum VariableType { NodeVariable=1, EdgeVariable=2, SurfaceVariable=2, VolumeVariable=3, NullVariable=0 };
bool pass = mesh != nullptr;
for ( const auto& var : vars ) {
pass = pass && static_cast<int>(var->type)>=1 && static_cast<int>(var->type)<=3;
pass = pass && !var->data.empty();
}
const std::string &meshClass = mesh->className();
if ( !pass )
return false;
const std::string& meshClass = mesh->className();
if ( meshClass == "PointList" ) {
auto mesh2 = dynamic_cast<IO::PointList *>( mesh.get() );
ASSERT( mesh2 );
for ( const auto &var : vars ) {
const auto mesh2 = dynamic_cast<IO::PointList*>( mesh.get() );
if ( mesh2 == nullptr )
return false;
for ( const auto& var : vars ) {
if ( var->type == IO::VariableType::NodeVariable ) {
size_t N_points = mesh2->points.size();
checkResult( var->data.size( 0 ) == N_points, "sizeof NodeVariable" );
checkResult( var->data.size( 1 ) == var->dim, "sizeof NodeVariable" );
pass = pass && var->data.size(0)==mesh2->points.size() && var->data.size(1)==var->dim;
} else if ( var->type == IO::VariableType::EdgeVariable ) {
ERROR( "Invalid type for PointList" );
ERROR("Invalid type for PointList");
} else if ( var->type == IO::VariableType::SurfaceVariable ) {
ERROR( "Invalid type for PointList" );
ERROR("Invalid type for PointList");
} else if ( var->type == IO::VariableType::VolumeVariable ) {
ERROR( "Invalid type for PointList" );
ERROR("Invalid type for PointList");
} else {
ERROR( "Invalid variable type" );
ERROR("Invalid variable type");
}
}
} else if ( meshClass == "TriMesh" || meshClass == "TriList" ) {
auto mesh2 = getTriMesh( mesh );
ASSERT( mesh2 );
for ( const auto &var : vars ) {
const auto mesh2 = getTriMesh( mesh );
if ( mesh2 == nullptr )
return false;
for ( const auto& var : vars ) {
if ( var->type == IO::VariableType::NodeVariable ) {
size_t N_points = mesh2->vertices->points.size();
checkResult( var->data.size( 0 ) == N_points, "sizeof NodeVariable" );
checkResult( var->data.size( 1 ) == var->dim, "sizeof NodeVariable" );
pass = pass && var->data.size(0)==mesh2->vertices->points.size() && var->data.size(1)==var->dim;
} else if ( var->type == IO::VariableType::EdgeVariable ) {
ERROR( "Not finished" );
ERROR("Not finished");
} else if ( var->type == IO::VariableType::SurfaceVariable ) {
ERROR( "Not finished" );
ERROR("Not finished");
} else if ( var->type == IO::VariableType::VolumeVariable ) {
checkResult( var->data.size( 0 ) == mesh2->A.size(), "sizeof VolumeVariable" );
checkResult( var->data.size( 1 ) == var->dim, "sizeof VolumeVariable" );
pass = pass && var->data.size(0)==mesh2->A.size() && var->data.size(1)==var->dim;
} else {
ERROR( "Invalid variable type" );
ERROR("Invalid variable type");
}
}
} else if ( meshClass == "DomainMesh" ) {
auto mesh2 = dynamic_cast<IO::DomainMesh *>( mesh.get() );
ASSERT( mesh2 );
for ( const auto &var : vars ) {
ArraySize varSize;
const auto mesh2 = dynamic_cast<IO::DomainMesh*>( mesh.get() );
if ( mesh2 == nullptr )
return false;
for ( const auto& var : vars ) {
if ( var->type == IO::VariableType::NodeVariable ) {
varSize = ArraySize( mesh2->nx + 1, mesh2->ny + 1, mesh2->nz + 1, var->dim );
pass = pass && (int) var->data.size(0)==(mesh2->nx+1) && (int) var->data.size(1)==(mesh2->ny+1)
&& (int) var->data.size(2)==(mesh2->nz+1) && var->data.size(3)==var->dim;
} else if ( var->type == IO::VariableType::EdgeVariable ) {
ERROR( "Not finished" );
ERROR("Not finished");
} else if ( var->type == IO::VariableType::SurfaceVariable ) {
ERROR( "Not finished" );
ERROR("Not finished");
} else if ( var->type == IO::VariableType::VolumeVariable ) {
varSize = ArraySize( mesh2->nx, mesh2->ny, mesh2->nz, var->dim );
pass = pass && (int) var->data.size(0)==mesh2->nx && (int) var->data.size(1)==mesh2->ny
&& (int) var->data.size(2)==mesh2->nz && var->data.size(3)==var->dim;
} else {
ERROR( "Invalid variable type" );
ERROR("Invalid variable type");
}
if ( var->data.size( 0 ) == varSize[0] * varSize[1] * varSize[2] &&
var->data.size( 1 ) == varSize[3] )
var->data.resize( varSize );
for ( int d = 0; d < 4; d++ )
checkResult( var->data.size( d ) == varSize[d], "DomainMesh Variable" );
}
} else {
ERROR( "Unknown mesh class: " + mesh->className() );
ERROR("Unknown mesh class: "+mesh->className());
}
return true;
return pass;
}
/****************************************************
* PointList *
****************************************************/
PointList::PointList() {}
* PointList *
****************************************************/
PointList::PointList( )
{
}
PointList::PointList( size_t N )
{
Point tmp = nullPoint();
points.resize( N, tmp );
points.resize(N,tmp);
}
PointList::~PointList( )
{
}
PointList::~PointList() {}
size_t PointList::numberPointsVar( VariableType type ) const
{
size_t N = 0;
@@ -161,168 +154,174 @@ size_t PointList::numberPointsVar( VariableType type ) const
N = points.size();
return N;
}
std::pair<size_t, void *> PointList::pack( int level ) const
std::pair<size_t,void*> PointList::pack( int level ) const
{
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()];
data_out.second = data_ptr;
uint64_t *data_int = reinterpret_cast<uint64_t *>( data_ptr );
data_int[0] = level;
data_int[1] = points.size();
double *data = &data_ptr[2];
for ( size_t i = 0; i < points.size(); i++ ) {
data[3 * i + 0] = points[i].x;
data[3 * i + 1] = points[i].y;
data[3 * i + 2] = points[i].z;
std::pair<size_t,void*> data_out(0,NULL);
if ( level==0 ) {
data_out.first = (2+3*points.size())*sizeof(double);
double *data_ptr = new double[2+3*points.size()];
data_out.second = data_ptr;
uint64_t *data_int = reinterpret_cast<uint64_t*>(data_ptr);
data_int[0] = level;
data_int[1] = points.size();
double *data = &data_ptr[2];
for (size_t i=0; i<points.size(); i++) {
data[3*i+0] = points[i].x;
data[3*i+1] = points[i].y;
data[3*i+2] = points[i].z;
}
}
return data_out;
}
void PointList::unpack( const std::pair<size_t, void *> &data_in )
void PointList::unpack( const std::pair<size_t,void*>& data_in )
{
uint64_t *data_int = reinterpret_cast<uint64_t *>( data_in.second );
const double *data = reinterpret_cast<const double *>( data_in.second );
int level = data_int[0];
uint64_t N = data_int[1];
data = &data[2];
if ( level == 0 ) {
ASSERT( ( 2 + 3 * N ) * sizeof( double ) == data_in.first );
points.resize( N );
for ( size_t i = 0; i < points.size(); i++ ) {
points[i].x = data[3 * i + 0];
points[i].y = data[3 * i + 1];
points[i].z = data[3 * i + 2];
uint64_t *data_int = reinterpret_cast<uint64_t*>(data_in.second);
const double *data = reinterpret_cast<const double*>(data_in.second);
int level = data_int[0];
uint64_t N = data_int[1];
data = &data[2];
if ( level==0 ) {
ASSERT((2+3*N)*sizeof(double)==data_in.first);
points.resize(N);
for (size_t i=0; i<points.size(); i++) {
points[i].x = data[3*i+0];
points[i].y = data[3*i+1];
points[i].z = data[3*i+2];
}
}
}
/****************************************************
* TriList *
****************************************************/
TriList::TriList() {}
* TriList *
****************************************************/
TriList::TriList( )
{
}
TriList::TriList( size_t N_tri )
{
Point tmp = nullPoint();
A.resize( N_tri, tmp );
B.resize( N_tri, tmp );
C.resize( N_tri, tmp );
A.resize(N_tri,tmp);
B.resize(N_tri,tmp);
C.resize(N_tri,tmp);
}
TriList::TriList( const TriMesh &mesh )
TriList::TriList( const TriMesh& mesh )
{
Point tmp = nullPoint();
A.resize( mesh.A.size(), tmp );
B.resize( mesh.B.size(), tmp );
C.resize( mesh.C.size(), tmp );
ASSERT( mesh.vertices.get() != NULL );
const std::vector<Point> &P = mesh.vertices->points;
for ( size_t i = 0; i < A.size(); i++ )
A.resize(mesh.A.size(),tmp);
B.resize(mesh.B.size(),tmp);
C.resize(mesh.C.size(),tmp);
ASSERT(mesh.vertices.get()!=NULL);
const std::vector<Point>& P = mesh.vertices->points;
for (size_t i=0; i<A.size(); i++)
A[i] = P[mesh.A[i]];
for ( size_t i = 0; i < B.size(); i++ )
for (size_t i=0; i<B.size(); i++)
B[i] = P[mesh.B[i]];
for ( size_t i = 0; i < C.size(); i++ )
for (size_t i=0; i<C.size(); i++)
C[i] = P[mesh.C[i]];
}
TriList::~TriList() {}
TriList::~TriList( )
{
}
size_t TriList::numberPointsVar( VariableType type ) const
{
size_t N = 0;
if ( type == VariableType::NodeVariable )
N = 3 * A.size();
else if ( type == VariableType::SurfaceVariable || type == VariableType::VolumeVariable )
if ( type==VariableType::NodeVariable )
N = 3*A.size();
else if ( type==VariableType::SurfaceVariable || type==VariableType::VolumeVariable )
N = A.size();
return N;
}
std::pair<size_t, void *> TriList::pack( int level ) const
std::pair<size_t,void*> TriList::pack( int level ) const
{
std::pair<size_t, void *> data_out( 0, NULL );
if ( level == 0 ) {
data_out.first = ( 2 + 9 * A.size() ) * sizeof( double );
double *data_ptr = new double[2 + 9 * A.size()];
data_out.second = data_ptr;
uint64_t *data_int = reinterpret_cast<uint64_t *>( data_ptr );
data_int[0] = level;
data_int[1] = A.size();
double *data = &data_ptr[2];
for ( size_t i = 0; i < A.size(); i++ ) {
data[9 * i + 0] = A[i].x;
data[9 * i + 1] = A[i].y;
data[9 * i + 2] = A[i].z;
data[9 * i + 3] = B[i].x;
data[9 * i + 4] = B[i].y;
data[9 * i + 5] = B[i].z;
data[9 * i + 6] = C[i].x;
data[9 * i + 7] = C[i].y;
data[9 * i + 8] = C[i].z;
std::pair<size_t,void*> data_out(0,NULL);
if ( level==0 ) {
data_out.first = (2+9*A.size())*sizeof(double);
double *data_ptr = new double[2+9*A.size()];
data_out.second = data_ptr;
uint64_t *data_int = reinterpret_cast<uint64_t*>(data_ptr);
data_int[0] = level;
data_int[1] = A.size();
double *data = &data_ptr[2];
for (size_t i=0; i<A.size(); i++) {
data[9*i+0] = A[i].x;
data[9*i+1] = A[i].y;
data[9*i+2] = A[i].z;
data[9*i+3] = B[i].x;
data[9*i+4] = B[i].y;
data[9*i+5] = B[i].z;
data[9*i+6] = C[i].x;
data[9*i+7] = C[i].y;
data[9*i+8] = C[i].z;
}
}
return data_out;
}
void TriList::unpack( const std::pair<size_t, void *> &data_in )
void TriList::unpack( const std::pair<size_t,void*>& data_in )
{
uint64_t *data_int = reinterpret_cast<uint64_t *>( data_in.second );
const double *data = reinterpret_cast<const double *>( data_in.second );
int level = data_int[0];
uint64_t N = data_int[1];
data = &data[2];
if ( level == 0 ) {
ASSERT( ( 2 + 9 * N ) * sizeof( double ) == data_in.first );
A.resize( N );
B.resize( N );
C.resize( N );
for ( size_t i = 0; i < A.size(); i++ ) {
A[i].x = data[9 * i + 0];
A[i].y = data[9 * i + 1];
A[i].z = data[9 * i + 2];
B[i].x = data[9 * i + 3];
B[i].y = data[9 * i + 4];
B[i].z = data[9 * i + 5];
C[i].x = data[9 * i + 6];
C[i].y = data[9 * i + 7];
C[i].z = data[9 * i + 8];
uint64_t *data_int = reinterpret_cast<uint64_t*>(data_in.second);
const double *data = reinterpret_cast<const double*>(data_in.second);
int level = data_int[0];
uint64_t N = data_int[1];
data = &data[2];
if ( level==0 ) {
ASSERT((2+9*N)*sizeof(double)==data_in.first);
A.resize(N);
B.resize(N);
C.resize(N);
for (size_t i=0; i<A.size(); i++) {
A[i].x = data[9*i+0];
A[i].y = data[9*i+1];
A[i].z = data[9*i+2];
B[i].x = data[9*i+3];
B[i].y = data[9*i+4];
B[i].z = data[9*i+5];
C[i].x = data[9*i+6];
C[i].y = data[9*i+7];
C[i].z = data[9*i+8];
}
}
}
/****************************************************
* TriMesh *
****************************************************/
TriMesh::TriMesh() {}
* TriMesh *
****************************************************/
TriMesh::TriMesh( )
{
}
TriMesh::TriMesh( size_t N_tri, size_t N_point )
{
vertices.reset( new PointList( N_point ) );
A.resize( N_tri, -1 );
B.resize( N_tri, -1 );
C.resize( N_tri, -1 );
vertices.reset( new PointList(N_point) );
A.resize(N_tri,-1);
B.resize(N_tri,-1);
C.resize(N_tri,-1);
}
TriMesh::TriMesh( size_t N_tri, std::shared_ptr<PointList> points )
{
vertices = points;
A.resize( N_tri, -1 );
B.resize( N_tri, -1 );
C.resize( N_tri, -1 );
A.resize(N_tri,-1);
B.resize(N_tri,-1);
C.resize(N_tri,-1);
}
TriMesh::TriMesh( const TriList &mesh )
TriMesh::TriMesh( const TriList& mesh )
{
// For simlicity we will just create a mesh with ~3x the verticies for now
ASSERT( mesh.A.size() == mesh.B.size() && mesh.A.size() == mesh.C.size() );
A.resize( mesh.A.size() );
B.resize( mesh.B.size() );
C.resize( mesh.C.size() );
vertices.reset( new PointList( 3 * mesh.A.size() ) );
for ( size_t i = 0; i < A.size(); i++ ) {
A[i] = 3 * i + 0;
B[i] = 3 * i + 1;
C[i] = 3 * i + 2;
ASSERT(mesh.A.size()==mesh.B.size()&&mesh.A.size()==mesh.C.size());
A.resize(mesh.A.size());
B.resize(mesh.B.size());
C.resize(mesh.C.size());
vertices.reset( new PointList(3*mesh.A.size()) );
for (size_t i=0; i<A.size(); i++) {
A[i] = 3*i+0;
B[i] = 3*i+1;
C[i] = 3*i+2;
vertices->points[A[i]] = mesh.A[i];
vertices->points[B[i]] = mesh.B[i];
vertices->points[C[i]] = mesh.C[i];
}
}
TriMesh::~TriMesh()
TriMesh::~TriMesh( )
{
vertices.reset();
A.clear();
@@ -332,323 +331,181 @@ TriMesh::~TriMesh()
size_t TriMesh::numberPointsVar( VariableType type ) const
{
size_t N = 0;
if ( type == VariableType::NodeVariable )
if ( type==VariableType::NodeVariable )
N = vertices->points.size();
else if ( type == VariableType::SurfaceVariable || type == VariableType::VolumeVariable )
else if ( type==VariableType::SurfaceVariable || type==VariableType::VolumeVariable )
N = A.size();
return N;
}
std::pair<size_t, void *> TriMesh::pack( int level ) const
std::pair<size_t,void*> TriMesh::pack( int level ) const
{
std::pair<size_t, void *> data_out( 0, NULL );
if ( level == 0 ) {
const std::vector<Point> &points = vertices->points;
data_out.first =
( 3 + 3 * points.size() ) * sizeof( double ) + 3 * A.size() * sizeof( int );
double *data_ptr =
new double[4 + 3 * points.size() + ( 3 * A.size() * sizeof( int ) ) / sizeof( double )];
data_out.second = data_ptr;
uint64_t *data_int64 = reinterpret_cast<uint64_t *>( data_ptr );
data_int64[0] = level;
data_int64[1] = points.size();
data_int64[2] = A.size();
double *data = &data_ptr[3];
for ( size_t i = 0; i < points.size(); i++ ) {
data[3 * i + 0] = points[i].x;
data[3 * i + 1] = points[i].y;
data[3 * i + 2] = points[i].z;
std::pair<size_t,void*> data_out(0,NULL);
if ( level==0 ) {
const std::vector<Point>& points = vertices->points;
data_out.first = (3+3*points.size())*sizeof(double) + 3*A.size()*sizeof(int);
double *data_ptr = new double[4+3*points.size()+(3*A.size()*sizeof(int))/sizeof(double)];
data_out.second = data_ptr;
uint64_t *data_int64 = reinterpret_cast<uint64_t*>(data_ptr);
data_int64[0] = level;
data_int64[1] = points.size();
data_int64[2] = A.size();
double *data = &data_ptr[3];
for (size_t i=0; i<points.size(); i++) {
data[3*i+0] = points[i].x;
data[3*i+1] = points[i].y;
data[3*i+2] = points[i].z;
}
int *data_int = reinterpret_cast<int *>( &data[3 * points.size()] );
for ( size_t i = 0; i < A.size(); i++ ) {
data_int[3 * i + 0] = A[i];
data_int[3 * i + 1] = B[i];
data_int[3 * i + 2] = C[i];
int *data_int = reinterpret_cast<int*>(&data[3*points.size()]);
for (size_t i=0; i<A.size(); i++) {
data_int[3*i+0] = A[i];
data_int[3*i+1] = B[i];
data_int[3*i+2] = C[i];
}
}
return data_out;
}
void TriMesh::unpack( const std::pair<size_t, void *> &data_in )
void TriMesh::unpack( const std::pair<size_t,void*>& data_in )
{
uint64_t *data_int64 = reinterpret_cast<uint64_t *>( data_in.second );
const double *data = reinterpret_cast<const double *>( data_in.second );
int level = data_int64[0];
uint64_t N_P = data_int64[1];
uint64_t N_A = data_int64[2];
data = &data[3];
if ( level == 0 ) {
size_t size = ( 3 + 3 * N_P ) * sizeof( double ) + 3 * N_A * sizeof( int );
ASSERT( size == data_in.first );
vertices.reset( new PointList( N_P ) );
std::vector<Point> &points = vertices->points;
for ( size_t i = 0; i < points.size(); i++ ) {
points[i].x = data[3 * i + 0];
points[i].y = data[3 * i + 1];
points[i].z = data[3 * i + 2];
uint64_t *data_int64 = reinterpret_cast<uint64_t*>(data_in.second);
const double *data = reinterpret_cast<const double*>(data_in.second);
int level = data_int64[0];
uint64_t N_P = data_int64[1];
uint64_t N_A = data_int64[2];
data = &data[3];
if ( level==0 ) {
size_t size = (3+3*N_P)*sizeof(double)+3*N_A*sizeof(int);
ASSERT(size==data_in.first);
vertices.reset( new PointList(N_P) );
std::vector<Point>& points = vertices->points;
for (size_t i=0; i<points.size(); i++) {
points[i].x = data[3*i+0];
points[i].y = data[3*i+1];
points[i].z = data[3*i+2];
}
const int *data_int = reinterpret_cast<const int *>( &data[3 * N_P] );
A.resize( N_A );
B.resize( N_A );
C.resize( N_A );
for ( size_t i = 0; i < A.size(); i++ ) {
A[i] = data_int[3 * i + 0];
B[i] = data_int[3 * i + 1];
C[i] = data_int[3 * i + 2];
const int *data_int = reinterpret_cast<const int*>(&data[3*N_P]);
A.resize(N_A);
B.resize(N_A);
C.resize(N_A);
for (size_t i=0; i<A.size(); i++) {
A[i] = data_int[3*i+0];
B[i] = data_int[3*i+1];
C[i] = data_int[3*i+2];
}
}
}
/****************************************************
* Domain mesh *
****************************************************/
DomainMesh::DomainMesh()
: nprocx( 0 ),
nprocy( 0 ),
nprocz( 0 ),
rank( 0 ),
nx( 0 ),
ny( 0 ),
nz( 0 ),
Lx( 0 ),
Ly( 0 ),
Lz( 0 )
* Domain mesh *
****************************************************/
DomainMesh::DomainMesh():
nprocx(0), nprocy(0), nprocz(0), rank(0),
nx(0), ny(0), nz(0),
Lx(0), Ly(0), Lz(0)
{
}
DomainMesh::DomainMesh(
RankInfoStruct data, int nx2, int ny2, int nz2, double Lx2, double Ly2, double Lz2 )
: nprocx( data.nx ),
nprocy( data.ny ),
nprocz( data.nz ),
rank( data.rank[1][1][1] ),
nx( nx2 ),
ny( ny2 ),
nz( nz2 ),
Lx( Lx2 ),
Ly( Ly2 ),
Lz( Lz2 )
DomainMesh::DomainMesh( RankInfoStruct data,
int nx2, int ny2, int nz2, double Lx2, double Ly2, double Lz2 ):
nprocx(data.nx), nprocy(data.ny), nprocz(data.nz), rank(data.rank[1][1][1]),
nx(nx2), ny(ny2), nz(nz2),
Lx(Lx2), Ly(Ly2), Lz(Lz2)
{
}
DomainMesh::~DomainMesh()
{
}
DomainMesh::~DomainMesh() {}
size_t DomainMesh::numberPointsVar( VariableType type ) const
{
size_t N = 0;
if ( type == VariableType::NodeVariable )
N = ( nx + 1 ) * ( ny + 1 ) * ( nz + 1 );
else if ( type == VariableType::SurfaceVariable )
N = ( nx + 1 ) * ny * nz + nx * ( ny + 1 ) * nz + nx * ny * ( nz + 1 );
else if ( type == VariableType::VolumeVariable )
N = nx * ny * nz;
if ( type==VariableType::NodeVariable )
N = (nx+1)*(ny+1)*(nz+1);
else if ( type==VariableType::SurfaceVariable )
N = (nx+1)*ny*nz + nx*(ny+1)*nz + nx*ny*(nz+1);
else if ( type==VariableType::VolumeVariable )
N = nx*ny*nz;
return N;
}
std::pair<size_t, void *> DomainMesh::pack( int level ) const
std::pair<size_t,void*> DomainMesh::pack( int level ) const
{
std::pair<size_t, void *> data( 0, NULL );
data.first = 7 * sizeof( double );
std::pair<size_t,void*> data(0,NULL);
data.first = 7*sizeof(double);
data.second = new double[7];
memset( data.second, 0, 7 * sizeof( double ) );
int *data_int = reinterpret_cast<int *>( data.second );
double *data_double = &reinterpret_cast<double *>( data.second )[4];
data_int[0] = nprocx;
data_int[1] = nprocy;
data_int[2] = nprocz;
data_int[3] = rank;
data_int[4] = nx;
data_int[5] = ny;
data_int[6] = nz;
data_double[0] = Lx;
data_double[1] = Ly;
data_double[2] = Lz;
memset(data.second,0,7*sizeof(double));
int *data_int = reinterpret_cast<int*>(data.second);
double *data_double = &reinterpret_cast<double*>(data.second)[4];
data_int[0] = nprocx;
data_int[1] = nprocy;
data_int[2] = nprocz;
data_int[3] = rank;
data_int[4] = nx;
data_int[5] = ny;
data_int[6] = nz;
data_double[0] = Lx;
data_double[1] = Ly;
data_double[2] = Lz;
return data;
}
void DomainMesh::unpack( const std::pair<size_t, void *> &data )
void DomainMesh::unpack( const std::pair<size_t,void*>& data )
{
const int *data_int = reinterpret_cast<const int *>( data.second );
const double *data_double = &reinterpret_cast<const double *>( data.second )[4];
nprocx = data_int[0];
nprocy = data_int[1];
nprocz = data_int[2];
rank = data_int[3];
nx = data_int[4];
ny = data_int[5];
nz = data_int[6];
Lx = data_double[0];
Ly = data_double[1];
Lz = data_double[2];
const int *data_int = reinterpret_cast<const int*>(data.second);
const double *data_double = &reinterpret_cast<const double*>(data.second)[4];
nprocx = data_int[0];
nprocy = data_int[1];
nprocz = data_int[2];
rank = data_int[3];
nx = data_int[4];
ny = data_int[5];
nz = data_int[6];
Lx = data_double[0];
Ly = data_double[1];
Lz = data_double[2];
}
/****************************************************
* Converters *
****************************************************/
* Converters *
****************************************************/
std::shared_ptr<PointList> getPointList( std::shared_ptr<Mesh> mesh )
{
return std::dynamic_pointer_cast<PointList>( mesh );
return std::dynamic_pointer_cast<PointList>(mesh);
}
std::shared_ptr<TriMesh> getTriMesh( std::shared_ptr<Mesh> mesh )
{
std::shared_ptr<TriMesh> mesh2;
if ( std::dynamic_pointer_cast<TriMesh>( mesh ).get() != NULL ) {
mesh2 = std::dynamic_pointer_cast<TriMesh>( mesh );
} else if ( std::dynamic_pointer_cast<TriList>( mesh ).get() != NULL ) {
std::shared_ptr<TriList> trilist = std::dynamic_pointer_cast<TriList>( mesh );
ASSERT( trilist.get() != NULL );
mesh2.reset( new TriMesh( *trilist ) );
if ( std::dynamic_pointer_cast<TriMesh>(mesh).get() != NULL ) {
mesh2 = std::dynamic_pointer_cast<TriMesh>(mesh);
} else if ( std::dynamic_pointer_cast<TriList>(mesh).get() != NULL ) {
std::shared_ptr<TriList> trilist = std::dynamic_pointer_cast<TriList>(mesh);
ASSERT(trilist.get()!=NULL);
mesh2.reset( new TriMesh(*trilist) );
}
return mesh2;
}
std::shared_ptr<TriList> getTriList( std::shared_ptr<Mesh> mesh )
{
std::shared_ptr<TriList> mesh2;
if ( std::dynamic_pointer_cast<TriList>( mesh ).get() != NULL ) {
mesh2 = std::dynamic_pointer_cast<TriList>( mesh );
} else if ( std::dynamic_pointer_cast<TriMesh>( mesh ).get() != NULL ) {
std::shared_ptr<TriMesh> trimesh = std::dynamic_pointer_cast<TriMesh>( mesh );
ASSERT( trimesh.get() != NULL );
mesh2.reset( new TriList( *trimesh ) );
if ( std::dynamic_pointer_cast<TriList>(mesh).get() != NULL ) {
mesh2 = std::dynamic_pointer_cast<TriList>(mesh);
} else if ( std::dynamic_pointer_cast<TriMesh>(mesh).get() != NULL ) {
std::shared_ptr<TriMesh> trimesh = std::dynamic_pointer_cast<TriMesh>(mesh);
ASSERT(trimesh.get()!=NULL);
mesh2.reset( new TriList(*trimesh) );
}
return mesh2;
}
std::shared_ptr<const PointList> getPointList( std::shared_ptr<const Mesh> mesh )
{
return getPointList( std::const_pointer_cast<Mesh>( mesh ) );
return getPointList( std::const_pointer_cast<Mesh>(mesh) );
}
std::shared_ptr<const TriMesh> getTriMesh( std::shared_ptr<const Mesh> mesh )
{
return getTriMesh( std::const_pointer_cast<Mesh>( mesh ) );
return getTriMesh( std::const_pointer_cast<Mesh>(mesh) );
}
std::shared_ptr<const TriList> getTriList( std::shared_ptr<const Mesh> mesh )
{
return getTriList( std::const_pointer_cast<Mesh>( mesh ) );
return getTriList( std::const_pointer_cast<Mesh>(mesh) );
}
/****************************************************
* Convert enum values *
****************************************************/
std::string getString( VariableType type )
{
if ( type == VariableType::NodeVariable )
return "node";
else if ( type == VariableType::EdgeVariable )
return "edge";
else if ( type == VariableType::SurfaceVariable )
return "face";
else if ( type == VariableType::VolumeVariable )
return "cell";
else if ( type == VariableType::NullVariable )
return "null";
else
ERROR( "Invalid type" );
return "";
}
VariableType getVariableType( const std::string &type_in )
{
auto type = deblank( type_in );
if ( type == "node" )
return VariableType::NodeVariable;
else if ( type == "edge" || type == "1" )
return VariableType::EdgeVariable;
else if ( type == "face" )
return VariableType::SurfaceVariable;
else if ( type == "cell" || type == "3" )
return VariableType::VolumeVariable;
else if ( type == "null" )
return VariableType::NullVariable;
else
ERROR( "Invalid type: " + type );
return VariableType::NullVariable;
}
std::string getString( DataType type )
{
if ( type == DataType::Double )
return "double";
else if ( type == DataType::Float )
return "float";
else if ( type == DataType::Int )
return "int";
else if ( type == DataType::Null )
return "null";
else
ERROR( "Invalid type" );
return "";
}
DataType getDataType( const std::string &type_in )
{
auto type = deblank( type_in );
if ( type == "double" )
return DataType::Double;
else if ( type == "float" )
return DataType::Float;
else if ( type == "int" )
return DataType::Int;
else if ( type == "null" )
return DataType::Null;
else
ERROR( "Invalid type: " + type );
return DataType::Null;
}
std::string getString( MeshType type )
{
if ( type == MeshType::PointMesh )
return "PointMesh";
else if ( type == MeshType::SurfaceMesh )
return "SurfaceMesh";
else if ( type == MeshType::VolumeMesh )
return "VolumeMesh";
else if ( type == MeshType::Unknown )
return "unknown";
else
ERROR( "Invalid type" );
return "";
}
MeshType getMeshType( const std::string &type_in )
{
auto type = deblank( type_in );
if ( type == "PointMesh" || type == "1" )
return MeshType::PointMesh;
else if ( type == "SurfaceMesh" || type == "2" )
return MeshType::SurfaceMesh;
else if ( type == "VolumeMesh" || type == "3" )
return MeshType::VolumeMesh;
else if ( type == "unknown" || type == "-1" )
return MeshType::Unknown;
else
ERROR( "Invalid type: " + type );
return MeshType::Unknown;
}
std::string getString( FileFormat type )
{
if ( type == FileFormat::OLD )
return "old";
else if ( type == FileFormat::NEW )
return "new";
else if ( type == FileFormat::NEW_SINGLE )
return "new(single)";
else if ( type == FileFormat::SILO )
return "silo";
else if ( type == FileFormat::HDF5 )
return "hdf5";
else
ERROR( "Invalid type" );
return "";
}
FileFormat getFileFormat( const std::string &type_in )
{
auto type = deblank( type_in );
if ( type == "old" || type == "1" )
return FileFormat::OLD;
else if ( type == "new" || type == "2" )
return FileFormat::NEW;
else if ( type == "new(single)" || type == "3" )
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;
}
} // IO namespace
} // namespace IO

133
IO/Mesh.h
View File

@@ -21,36 +21,17 @@
#include <string.h>
#include <vector>
#include "analysis/PointList.h"
#include "common/Array.h"
#include "common/Communication.h"
#include "analysis/PointList.h"
namespace IO {
//! Enums to define types
enum class VariableType {
NodeVariable,
EdgeVariable,
SurfaceVariable,
VolumeVariable,
NullVariable
};
enum class DataType { Double, Float, Int, Null };
enum class MeshType { PointMesh, SurfaceMesh, VolumeMesh, Unknown };
enum class FileFormat { OLD, NEW, NEW_SINGLE, SILO, HDF5 };
//! Convert enums to/from strings (more future-proof than static_cast<int>)
std::string getString( VariableType );
std::string getString( DataType );
std::string getString( MeshType );
std::string getString( FileFormat );
VariableType getVariableType( const std::string & );
DataType getDataType( const std::string & );
MeshType getMeshType( const std::string & );
FileFormat getFileFormat( const std::string & );
//! Possible variable types
enum class VariableType: unsigned char { NodeVariable=1, EdgeVariable=2, SurfaceVariable=2, VolumeVariable=3, NullVariable=0 };
enum class DataType: unsigned char { Double=1, Float=2, Int=2, Null=0 };
/*! \class Mesh
@@ -66,22 +47,21 @@ public:
//! Number of points for the given variable type
virtual size_t numberPointsVar( VariableType type ) const = 0;
//! Pack the data
virtual std::pair<size_t, void *> pack( int level ) const = 0;
virtual std::pair<size_t,void*> pack( int level ) const = 0;
//! Unpack the data
virtual void unpack( const std::pair<size_t, void *> &data ) = 0;
virtual void unpack( const std::pair<size_t,void*>& data ) = 0;
protected:
//! Empty constructor
Mesh();
Mesh( const Mesh & );
Mesh &operator=( const Mesh & );
Mesh(const Mesh&);
Mesh& operator=(const Mesh&);
};
/*! \class PointList
\brief A class used to hold a list of verticies
*/
class PointList : public Mesh
class PointList: public Mesh
{
public:
//! Empty constructor
@@ -95,14 +75,13 @@ public:
//! Number of points for the given variable type
virtual size_t numberPointsVar( VariableType type ) const;
//! Pack the data
virtual std::pair<size_t, void *> pack( int level ) const;
virtual std::pair<size_t,void*> pack( int level ) const;
//! Unpack the data
virtual void unpack( const std::pair<size_t, void *> &data );
virtual void unpack( const std::pair<size_t,void*>& data );
//! Access the points
const std::vector<Point> &getPoints() const { return points; }
const std::vector<Point>& getPoints() const { return points; }
public:
std::vector<Point> points; //!< List of points vertex
std::vector<Point> points; //!< List of points vertex
};
@@ -110,7 +89,7 @@ public:
\brief A class used to hold a list of triangles specified by their vertex coordinates
*/
class TriMesh;
class TriList : public Mesh
class TriList: public Mesh
{
public:
//! Empty constructor
@@ -118,7 +97,7 @@ public:
//! Constructor for N triangles
TriList( size_t N_tri );
//! Constructor from TriMesh
TriList( const TriMesh & );
TriList( const TriMesh& );
//! Destructor
virtual ~TriList();
//! Mesh class name
@@ -126,22 +105,20 @@ public:
//! Number of points for the given variable type
virtual size_t numberPointsVar( VariableType type ) const;
//! Pack the data
virtual std::pair<size_t, void *> pack( int level ) const;
virtual std::pair<size_t,void*> pack( int level ) const;
//! Unpack the data
virtual void unpack( const std::pair<size_t, void *> &data );
virtual void unpack( const std::pair<size_t,void*>& data );
public:
std::vector<Point> A; //!< First vertex
std::vector<Point> B; //!< Second vertex
std::vector<Point> C; //!< Third vertex
std::vector<Point> A; //!< First vertex
std::vector<Point> B; //!< Second vertex
std::vector<Point> C; //!< Third vertex
};
/*! \class TriMesh
\brief A class used to hold a list of trianges specified by their vertex number and list of
coordiantes
\brief A class used to hold a list of trianges specified by their vertex number and list of coordiantes
*/
class TriMesh : public Mesh
class TriMesh: public Mesh
{
public:
//! TriMesh constructor
@@ -151,7 +128,7 @@ public:
//! Constructor for Nt triangles and the given points
TriMesh( size_t N_tri, std::shared_ptr<PointList> points );
//! Constructor from TriList
TriMesh( const TriList & );
TriMesh( const TriList& );
//! Destructor
virtual ~TriMesh();
//! Mesh class name
@@ -159,22 +136,21 @@ public:
//! Number of points for the given variable type
virtual size_t numberPointsVar( VariableType type ) const;
//! Pack the data
virtual std::pair<size_t, void *> pack( int level ) const;
virtual std::pair<size_t,void*> pack( int level ) const;
//! Unpack the data
virtual void unpack( const std::pair<size_t, void *> &data );
virtual void unpack( const std::pair<size_t,void*>& data );
public:
std::shared_ptr<PointList> vertices; //!< List of verticies
std::vector<int> A; //!< First vertex
std::vector<int> B; //!< Second vertex
std::vector<int> C; //!< Third vertex
std::shared_ptr<PointList> vertices; //!< List of verticies
std::vector<int> A; //!< First vertex
std::vector<int> B; //!< Second vertex
std::vector<int> C; //!< Third vertex
};
/*! \class Domain
\brief A class used to hold the domain
*/
class DomainMesh : public Mesh
class DomainMesh: public Mesh
{
public:
//! Empty constructor
@@ -188,10 +164,9 @@ public:
//! Number of points for the given variable type
virtual size_t numberPointsVar( VariableType type ) const;
//! Pack the data
virtual std::pair<size_t, void *> pack( int level ) const;
virtual std::pair<size_t,void*> pack( int level ) const;
//! Unpack the data
virtual void unpack( const std::pair<size_t, void *> &data );
virtual void unpack( const std::pair<size_t,void*>& data );
public:
int nprocx, nprocy, nprocz, rank;
int nx, ny, nz;
@@ -199,40 +174,37 @@ public:
};
/*! \class Variable
\brief A base class for variables
*/
struct Variable {
struct Variable
{
public:
// Internal variables
unsigned char dim; //!< Number of points per grid point (1: scalar, 3: vector, ...)
VariableType type; //!< Variable type
DataType precision; //!< Variable precision to use for IO
std::string name; //!< Variable name
Array<double> data; //!< Variable data
unsigned char dim; //!< Number of points per grid point (1: scalar, 3: vector, ...)
VariableType type; //!< Variable type
DataType precision; //!< Variable precision to use for IO
std::string name; //!< Variable name
Array<double> data; //!< Variable data
//! Empty constructor
Variable() : dim( 0 ), type( VariableType::NullVariable ), precision( DataType::Double ) {}
Variable(): dim(0), type(VariableType::NullVariable), precision(DataType::Double) {}
//! Constructor
Variable( int dim_, IO::VariableType type_, const std::string &name_ )
: dim( dim_ ), type( type_ ), precision( DataType::Double ), name( name_ )
{
}
Variable( int dim_, IO::VariableType type_, const std::string& name_ ):
dim(dim_), type(type_), precision(DataType::Double), name(name_) {}
//! Constructor
Variable(
int dim_, IO::VariableType type_, const std::string &name_, const Array<double> &data_ )
: dim( dim_ ), type( type_ ), precision( DataType::Double ), name( name_ ), data( data_ )
{
}
Variable( int dim_, IO::VariableType type_, const std::string& name_, const Array<double>& data_ ):
dim(dim_), type(type_), precision(DataType::Double), name(name_), data(data_) {}
//! Destructor
virtual ~Variable() {}
protected:
//! Empty constructor
Variable( const Variable & );
Variable &operator=( const Variable & );
Variable(const Variable&);
Variable& operator=(const Variable&);
};
/*! \class MeshDataStruct
\brief A class used to hold database info for saving a mesh
*/
@@ -240,11 +212,11 @@ struct MeshDataStruct {
DataType precision; //!< Precision to use for IO (mesh)
std::string meshName; //!< Mesh name
std::shared_ptr<Mesh> mesh; //!< Mesh data
std::vector<std::shared_ptr<Variable>> vars;
std::vector<std::shared_ptr<Variable> > vars;
//! Empty constructor
MeshDataStruct() : precision( DataType::Double ) {}
MeshDataStruct(): precision(DataType::Double) {}
//! Check the data
bool check( bool abort = true ) const;
bool check() const;
};
@@ -257,6 +229,7 @@ std::shared_ptr<const TriMesh> getTriMesh( std::shared_ptr<const Mesh> mesh );
std::shared_ptr<const TriList> getTriList( std::shared_ptr<const Mesh> mesh );
} // namespace IO
} // IO namespace
#endif

View File

@@ -29,146 +29,133 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "IO/MeshDatabase.h"
#include "IO/IOHelpers.h"
#include "IO/Mesh.h"
#include "IO/PackData.h"
#include "common/MPI.h"
#include "IO/IOHelpers.h"
#include "common/MPI_Helpers.h"
#include "common/Utilities.h"
#include <cstdio>
#include <vector>
#include <map>
#include <set>
#include <vector>
#include <cstdio>
#include <ProfilerApp.h>
// Default pack/unpack
// clang-format off
#define INSTANTIATE_PACK( TYPE ) \
template<> \
size_t packsize<TYPE>( const TYPE &rhs ) \
{ \
return sizeof( TYPE ); \
} \
template<> \
void pack<TYPE>( const TYPE &rhs, char *buffer ) \
{ \
memcpy( buffer, &rhs, sizeof( IO::MeshType ) ); \
} \
template<> \
void unpack<TYPE>( TYPE &data, const char *buffer ) \
{ \
memcpy( &data, buffer, sizeof( IO::MeshType ) ); \
}
INSTANTIATE_PACK( IO::VariableType )
INSTANTIATE_PACK( IO::DataType )
INSTANTIATE_PACK( IO::MeshType )
INSTANTIATE_PACK( IO::FileFormat )
// clang-format on
/****************************************************
****************************************************/
// MeshType
template<>
size_t packsize<IO::MeshType>( const IO::MeshType& rhs )
{
return sizeof(IO::MeshType);
}
template<>
void pack<IO::MeshType>( const IO::MeshType& rhs, char *buffer )
{
memcpy(buffer,&rhs,sizeof(IO::MeshType));
}
template<>
void unpack<IO::MeshType>( IO::MeshType& data, const char *buffer )
{
memcpy(&data,buffer,sizeof(IO::MeshType));
}
// Variable::VariableType
template<>
size_t packsize<IO::VariableType>( const IO::VariableType& rhs )
{
return sizeof(IO::VariableType);
}
template<>
void pack<IO::VariableType>( const IO::VariableType& rhs, char *buffer )
{
memcpy(buffer,&rhs,sizeof(IO::VariableType));
}
template<>
void unpack<IO::VariableType>( IO::VariableType& data, const char *buffer )
{
memcpy(&data,buffer,sizeof(IO::VariableType));
}
// DatabaseEntry
template<>
size_t packsize<IO::DatabaseEntry>( const IO::DatabaseEntry &rhs )
size_t packsize<IO::DatabaseEntry>( const IO::DatabaseEntry& rhs )
{
return packsize( rhs.name ) + packsize( rhs.file ) + packsize( rhs.offset );
return packsize(rhs.name)+packsize(rhs.file)+packsize(rhs.offset);
}
template<>
void pack<IO::DatabaseEntry>( const IO::DatabaseEntry &rhs, char *buffer )
void pack<IO::DatabaseEntry>( const IO::DatabaseEntry& rhs, char *buffer )
{
size_t i = 0;
pack( rhs.name, &buffer[i] );
i += packsize( rhs.name );
pack( rhs.file, &buffer[i] );
i += packsize( rhs.file );
pack( rhs.offset, &buffer[i] );
i += packsize( rhs.offset );
size_t i=0;
pack(rhs.name,&buffer[i]); i+=packsize(rhs.name);
pack(rhs.file,&buffer[i]); i+=packsize(rhs.file);
pack(rhs.offset,&buffer[i]); i+=packsize(rhs.offset);
}
template<>
void unpack<IO::DatabaseEntry>( IO::DatabaseEntry &data, const char *buffer )
void unpack<IO::DatabaseEntry>( IO::DatabaseEntry& data, const char *buffer )
{
size_t i = 0;
unpack( data.name, &buffer[i] );
i += packsize( data.name );
unpack( data.file, &buffer[i] );
i += packsize( data.file );
unpack( data.offset, &buffer[i] );
i += packsize( data.offset );
size_t i=0;
unpack(data.name,&buffer[i]); i+=packsize(data.name);
unpack(data.file,&buffer[i]); i+=packsize(data.file);
unpack(data.offset,&buffer[i]); i+=packsize(data.offset);
}
// VariableDatabase
template<>
size_t packsize<IO::VariableDatabase>( const IO::VariableDatabase &rhs )
size_t packsize<IO::VariableDatabase>( const IO::VariableDatabase& rhs )
{
return packsize( rhs.name ) + packsize( rhs.type ) + packsize( rhs.dim );
return packsize(rhs.name)+packsize(rhs.type)+packsize(rhs.dim);
}
template<>
void pack<IO::VariableDatabase>( const IO::VariableDatabase &rhs, char *buffer )
void pack<IO::VariableDatabase>( const IO::VariableDatabase& rhs, char *buffer )
{
size_t i = 0;
pack( rhs.name, &buffer[i] );
i += packsize( rhs.name );
pack( rhs.type, &buffer[i] );
i += packsize( rhs.type );
pack( rhs.dim, &buffer[i] );
i += packsize( rhs.dim );
size_t i=0;
pack(rhs.name,&buffer[i]); i+=packsize(rhs.name);
pack(rhs.type,&buffer[i]); i+=packsize(rhs.type);
pack(rhs.dim,&buffer[i]); i+=packsize(rhs.dim);
}
template<>
void unpack<IO::VariableDatabase>( IO::VariableDatabase &data, const char *buffer )
void unpack<IO::VariableDatabase>( IO::VariableDatabase& data, const char *buffer )
{
size_t i = 0;
unpack( data.name, &buffer[i] );
i += packsize( data.name );
unpack( data.type, &buffer[i] );
i += packsize( data.type );
unpack( data.dim, &buffer[i] );
i += packsize( data.dim );
size_t i=0;
unpack(data.name,&buffer[i]); i+=packsize(data.name);
unpack(data.type,&buffer[i]); i+=packsize(data.type);
unpack(data.dim,&buffer[i]); i+=packsize(data.dim);
}
// MeshDatabase
template<>
size_t packsize<IO::MeshDatabase>( const IO::MeshDatabase &data )
size_t packsize<IO::MeshDatabase>( const IO::MeshDatabase& data )
{
return packsize( data.name ) + packsize( data.type ) + packsize( data.meshClass ) +
packsize( data.format ) + packsize( data.domains ) + packsize( data.variables ) +
packsize( data.variable_data );
return packsize(data.name)
+ packsize(data.type)
+ packsize(data.meshClass)
+ packsize(data.format)
+ packsize(data.domains)
+ packsize(data.variables)
+ packsize(data.variable_data);
}
template<>
void pack<IO::MeshDatabase>( const IO::MeshDatabase &rhs, char *buffer )
void pack<IO::MeshDatabase>( const IO::MeshDatabase& rhs, char *buffer )
{
size_t i = 0;
pack( rhs.name, &buffer[i] );
i += packsize( rhs.name );
pack( rhs.type, &buffer[i] );
i += packsize( rhs.type );
pack( rhs.meshClass, &buffer[i] );
i += packsize( rhs.meshClass );
pack( rhs.format, &buffer[i] );
i += packsize( rhs.format );
pack( rhs.domains, &buffer[i] );
i += packsize( rhs.domains );
pack( rhs.variables, &buffer[i] );
i += packsize( rhs.variables );
pack( rhs.variable_data, &buffer[i] );
i += packsize( rhs.variable_data );
pack(rhs.name,&buffer[i]); i+=packsize(rhs.name);
pack(rhs.type,&buffer[i]); i+=packsize(rhs.type);
pack(rhs.meshClass,&buffer[i]); i+=packsize(rhs.meshClass);
pack(rhs.format,&buffer[i]); i+=packsize(rhs.format);
pack(rhs.domains,&buffer[i]); i+=packsize(rhs.domains);
pack(rhs.variables,&buffer[i]); i+=packsize(rhs.variables);
pack(rhs.variable_data,&buffer[i]); i+=packsize(rhs.variable_data);
}
template<>
void unpack<IO::MeshDatabase>( IO::MeshDatabase &data, const char *buffer )
void unpack<IO::MeshDatabase>( IO::MeshDatabase& data, const char *buffer )
{
size_t i = 0;
unpack( data.name, &buffer[i] );
i += packsize( data.name );
unpack( data.type, &buffer[i] );
i += packsize( data.type );
unpack( data.meshClass, &buffer[i] );
i += packsize( data.meshClass );
unpack( data.format, &buffer[i] );
i += packsize( data.format );
unpack( data.domains, &buffer[i] );
i += packsize( data.domains );
unpack( data.variables, &buffer[i] );
i += packsize( data.variables );
unpack( data.variable_data, &buffer[i] );
i += packsize( data.variable_data );
size_t i=0;
unpack(data.name,&buffer[i]); i+=packsize(data.name);
unpack(data.type,&buffer[i]); i+=packsize(data.type);
unpack(data.meshClass,&buffer[i]); i+=packsize(data.meshClass);
unpack(data.format,&buffer[i]); i+=packsize(data.format);
unpack(data.domains,&buffer[i]); i+=packsize(data.domains);
unpack(data.variables,&buffer[i]); i+=packsize(data.variables);
unpack(data.variable_data,&buffer[i]); i+=packsize(data.variable_data);
}
@@ -176,72 +163,79 @@ namespace IO {
/****************************************************
* VariableDatabase *
****************************************************/
bool VariableDatabase::operator==( const VariableDatabase &rhs ) const
* VariableDatabase *
****************************************************/
bool VariableDatabase::operator==(const VariableDatabase& rhs ) const
{
return type == rhs.type && dim == rhs.dim && name == rhs.name;
return type==rhs.type && dim==rhs.dim && name==rhs.name;
}
bool VariableDatabase::operator!=( const VariableDatabase &rhs ) const
bool VariableDatabase::operator!=(const VariableDatabase& rhs ) const
{
return type != rhs.type || dim != rhs.dim || name != rhs.name;
return type!=rhs.type || dim!=rhs.dim || name!=rhs.name;
}
bool VariableDatabase::operator>=( const VariableDatabase &rhs ) const
bool VariableDatabase::operator>=(const VariableDatabase& rhs ) const
{
return operator>( rhs ) || operator==( rhs );
return operator>(rhs) || operator==(rhs);
}
bool VariableDatabase::operator<=( const VariableDatabase &rhs ) const { return !operator>( rhs ); }
bool VariableDatabase::operator>( const VariableDatabase &rhs ) const
bool VariableDatabase::operator<=(const VariableDatabase& rhs ) const
{
if ( name > rhs.name )
return !operator>(rhs);
}
bool VariableDatabase::operator>(const VariableDatabase& rhs ) const
{
if ( name>rhs.name )
return true;
else if ( name < rhs.name )
else if ( name<rhs.name )
return false;
if ( type > rhs.type )
if ( type>rhs.type )
return true;
else if ( type < rhs.type )
else if ( type<rhs.type )
return false;
if ( dim > rhs.dim )
if ( dim>rhs.dim )
return true;
else if ( dim < rhs.dim )
else if ( dim<rhs.dim )
return false;
return false;
}
bool VariableDatabase::operator<( const VariableDatabase &rhs ) const
bool VariableDatabase::operator<(const VariableDatabase& rhs ) const
{
return !operator>( rhs ) && operator!=( rhs );
return !operator>(rhs) && operator!=(rhs);
}
/****************************************************
* MeshDatabase *
****************************************************/
MeshDatabase::MeshDatabase() {}
MeshDatabase::~MeshDatabase() {}
MeshDatabase::MeshDatabase( const MeshDatabase &rhs )
* MeshDatabase *
****************************************************/
MeshDatabase::MeshDatabase()
{
name = rhs.name;
type = rhs.type;
meshClass = rhs.meshClass;
format = rhs.format;
domains = rhs.domains;
variables = rhs.variables;
}
MeshDatabase::~MeshDatabase()
{
}
MeshDatabase::MeshDatabase(const MeshDatabase& rhs)
{
name = rhs.name;
type = rhs.type;
meshClass = rhs.meshClass;
format = rhs.format;
domains = rhs.domains;
variables = rhs.variables;
variable_data = rhs.variable_data;
}
MeshDatabase &MeshDatabase::operator=( const MeshDatabase &rhs )
MeshDatabase& MeshDatabase::operator=(const MeshDatabase& rhs)
{
this->name = rhs.name;
this->type = rhs.type;
this->meshClass = rhs.meshClass;
this->format = rhs.format;
this->domains = rhs.domains;
this->variables = rhs.variables;
this->name = rhs.name;
this->type = rhs.type;
this->meshClass = rhs.meshClass;
this->format = rhs.format;
this->domains = rhs.domains;
this->variables = rhs.variables;
this->variable_data = rhs.variable_data;
return *this;
}
VariableDatabase MeshDatabase::getVariableDatabase( const std::string &varname ) const
VariableDatabase MeshDatabase::getVariableDatabase( const std::string& varname ) const
{
for ( size_t i = 0; i < variables.size(); i++ ) {
for (size_t i=0; i<variables.size(); i++) {
if ( variables[i].name == varname )
return variables[i];
}
@@ -250,219 +244,221 @@ VariableDatabase MeshDatabase::getVariableDatabase( const std::string &varname )
/****************************************************
* DatabaseEntry *
****************************************************/
std::string DatabaseEntry::write() const
* DatabaseEntry *
****************************************************/
std::string DatabaseEntry::write( ) const
{
char tmp[1000];
sprintf( tmp, "%s; %s; %lu", name.c_str(), file.c_str(), offset );
return std::string( tmp );
sprintf(tmp,"%s; %s; %lu",name.c_str(),file.c_str(),offset);
return std::string(tmp);
}
DatabaseEntry::DatabaseEntry( const char *line )
DatabaseEntry::DatabaseEntry( const char* line )
{
auto list = splitList( line, ';' );
name = list[0];
file = list[1];
offset = atol( list[2].c_str() );
std::vector<std::string> list = splitList(line,';');
name = list[0];
file = list[1];
offset = atol(list[2].c_str());
}
void DatabaseEntry::read( const char *line )
void DatabaseEntry::read( const char* line )
{
auto list = splitList( line, ';' );
name = list[0];
file = list[1];
offset = atol( list[2].c_str() );
std::vector<std::string> list = splitList(line,';');
name = list[0];
file = list[1];
offset = atol(list[2].c_str());
}
void DatabaseEntry::read( const std::string &line )
void DatabaseEntry::read( const std::string& line )
{
auto list = splitList( line.c_str(), ';' );
name = list[0];
file = list[1];
offset = atol( list[2].c_str() );
std::vector<std::string> list = splitList(line.c_str(),';');
name = list[0];
file = list[1];
offset = atol(list[2].c_str());
}
// Gather the mesh databases from all processors
inline int tod( int N ) { return ( N + 7 ) / sizeof( double ); }
std::vector<MeshDatabase> gatherAll(
const std::vector<MeshDatabase> &meshes, const Utilities::MPI &comm )
inline int tod( int N ) { return (N+7)/sizeof(double); }
std::vector<MeshDatabase> gatherAll( const std::vector<MeshDatabase>& meshes, MPI_Comm comm )
{
if ( comm.getSize() == 1 )
return meshes;
PROFILE_START( "gatherAll" );
PROFILE_START( "gatherAll-pack", 2 );
int size = comm.getSize();
// First pack the mesh data to local buffers
int localsize = 0;
for ( size_t i = 0; i < meshes.size(); i++ )
localsize += tod( packsize( meshes[i] ) );
auto localbuf = new double[localsize];
int pos = 0;
for ( size_t i = 0; i < meshes.size(); i++ ) {
pack( meshes[i], (char *) &localbuf[pos] );
pos += tod( packsize( meshes[i] ) );
}
PROFILE_STOP( "gatherAll-pack", 2 );
// Get the number of bytes each processor will be sending/recieving
PROFILE_START( "gatherAll-send1", 2 );
auto recvsize = comm.allGather( localsize );
int globalsize = recvsize[0];
auto disp = new int[size];
disp[0] = 0;
for ( int i = 1; i < size; i++ ) {
disp[i] = disp[i - 1] + recvsize[i];
globalsize += recvsize[i];
}
PROFILE_STOP( "gatherAll-send1", 2 );
// Send/recv the global data
PROFILE_START( "gatherAll-send2", 2 );
auto globalbuf = new double[globalsize];
comm.allGather( localbuf, localsize, globalbuf, recvsize.data(), disp, true );
PROFILE_STOP( "gatherAll-send2", 2 );
// Unpack the data
PROFILE_START( "gatherAll-unpack", 2 );
std::map<std::string, MeshDatabase> data;
pos = 0;
while ( pos < globalsize ) {
MeshDatabase tmp;
unpack( tmp, (char *) &globalbuf[pos] );
pos += tod( packsize( tmp ) );
std::map<std::string, MeshDatabase>::iterator it = data.find( tmp.name );
if ( it == data.end() ) {
data[tmp.name] = tmp;
} else {
for ( size_t i = 0; i < tmp.domains.size(); i++ )
it->second.domains.push_back( tmp.domains[i] );
for ( size_t i = 0; i < tmp.variables.size(); i++ )
it->second.variables.push_back( tmp.variables[i] );
it->second.variable_data.insert( tmp.variable_data.begin(), tmp.variable_data.end() );
#ifdef USE_MPI
PROFILE_START("gatherAll");
PROFILE_START("gatherAll-pack",2);
int size = MPI_WORLD_SIZE();
// First pack the mesh data to local buffers
int localsize = 0;
for (size_t i=0; i<meshes.size(); i++)
localsize += tod(packsize(meshes[i]));
auto localbuf = new double[localsize];
int pos = 0;
for (size_t i=0; i<meshes.size(); i++) {
pack( meshes[i], (char*) &localbuf[pos] );
pos += tod(packsize(meshes[i]));
}
}
for ( auto it = data.begin(); it != data.end(); ++it ) {
// Get the unique variables
std::set<VariableDatabase> data2(
it->second.variables.begin(), it->second.variables.end() );
it->second.variables = std::vector<VariableDatabase>( data2.begin(), data2.end() );
}
// Free temporary memory
delete[] localbuf;
delete[] disp;
delete[] globalbuf;
// Return the results
std::vector<MeshDatabase> data2( data.size() );
size_t i = 0;
for ( auto it = data.begin(); it != data.end(); ++it, ++i )
data2[i] = it->second;
PROFILE_STOP( "gatherAll-unpack", 2 );
PROFILE_STOP( "gatherAll" );
return data2;
PROFILE_STOP("gatherAll-pack",2);
// Get the number of bytes each processor will be sending/recieving
PROFILE_START("gatherAll-send1",2);
auto recvsize = new int[size];
MPI_Allgather(&localsize,1,MPI_INT,recvsize,1,MPI_INT,comm);
int globalsize = recvsize[0];
auto disp = new int[size];
disp[0] = 0;
for (int i=1; i<size; i++) {
disp[i] = disp[i-1] + recvsize[i];
globalsize += recvsize[i];
}
PROFILE_STOP("gatherAll-send1",2);
// Send/recv the global data
PROFILE_START("gatherAll-send2",2);
auto globalbuf = new double[globalsize];
MPI_Allgatherv(localbuf,localsize,MPI_DOUBLE,globalbuf,recvsize,disp,MPI_DOUBLE,comm);
PROFILE_STOP("gatherAll-send2",2);
// Unpack the data
PROFILE_START("gatherAll-unpack",2);
std::map<std::string,MeshDatabase> data;
pos = 0;
while ( pos < globalsize ) {
MeshDatabase tmp;
unpack(tmp,(char*)&globalbuf[pos]);
pos += tod(packsize(tmp));
std::map<std::string,MeshDatabase>::iterator it = data.find(tmp.name);
if ( it==data.end() ) {
data[tmp.name] = tmp;
} else {
for (size_t i=0; i<tmp.domains.size(); i++)
it->second.domains.push_back(tmp.domains[i]);
for (size_t i=0; i<tmp.variables.size(); i++)
it->second.variables.push_back(tmp.variables[i]);
it->second.variable_data.insert(tmp.variable_data.begin(),tmp.variable_data.end());
}
}
for (std::map<std::string,MeshDatabase>::iterator it=data.begin(); it!=data.end(); ++it) {
// Get the unique variables
std::set<VariableDatabase> data2(it->second.variables.begin(),it->second.variables.end());
it->second.variables = std::vector<VariableDatabase>(data2.begin(),data2.end());
}
// Free temporary memory
delete [] localbuf;
delete [] recvsize;
delete [] disp;
delete [] globalbuf;
// Return the results
std::vector<MeshDatabase> data2(data.size());
size_t i=0;
for (std::map<std::string,MeshDatabase>::iterator it=data.begin(); it!=data.end(); ++it, ++i)
data2[i] = it->second;
PROFILE_STOP("gatherAll-unpack",2);
PROFILE_STOP("gatherAll");
return data2;
#else
return meshes;
#endif
}
//! Write the mesh databases to a file
void write( const std::vector<MeshDatabase> &meshes, const std::string &filename )
void write( const std::vector<MeshDatabase>& meshes, const std::string& filename )
{
PROFILE_START( "write" );
FILE *fid = fopen( filename.c_str(), "wb" );
for ( size_t i = 0; i < meshes.size(); i++ ) {
fprintf( fid, "%s\n", meshes[i].name.c_str() );
fprintf( fid, " type: %s\n", getString( meshes[i].type ).data() );
fprintf( fid, " meshClass: %s\n", meshes[i].meshClass.c_str() );
fprintf( fid, " format: %s\n", getString( meshes[i].format ).data() );
for ( size_t j = 0; j < meshes[i].domains.size(); j++ )
fprintf( fid, " domain: %s\n", meshes[i].domains[j].write().c_str() );
fprintf( fid, " variables: " );
for ( size_t j = 0; j < meshes[i].variables.size(); j++ ) {
const VariableDatabase &var = meshes[i].variables[j];
fprintf( fid, "%s|%s|%i; ", var.name.data(), getString( var.type ).data(), var.dim );
PROFILE_START("write");
FILE *fid = fopen(filename.c_str(),"wb");
for (size_t i=0; i<meshes.size(); i++) {
fprintf(fid,"%s\n",meshes[i].name.c_str());
fprintf(fid," type: %i\n",static_cast<int>(meshes[i].type));
fprintf(fid," meshClass: %s\n",meshes[i].meshClass.c_str());
fprintf(fid," format: %i\n",static_cast<int>(meshes[i].format));
for (size_t j=0; j<meshes[i].domains.size(); j++)
fprintf(fid," domain: %s\n",meshes[i].domains[j].write().c_str());
fprintf(fid," variables: ");
for (size_t j=0; j<meshes[i].variables.size(); j++) {
const VariableDatabase& var = meshes[i].variables[j];
fprintf(fid,"%s|%i|%i; ",var.name.c_str(),static_cast<int>(var.type),var.dim);
}
fprintf( fid, "\n" );
for ( auto it = meshes[i].variable_data.begin(); it != meshes[i].variable_data.end();
++it ) {
const char *domain = it->first.first.c_str();
const char *variable = it->first.second.c_str();
fprintf(
fid, " variable(%s,%s): %s\n", domain, variable, it->second.write().c_str() );
fprintf(fid,"\n");
std::map<std::pair<std::string,std::string>,DatabaseEntry>::const_iterator it;
for (it=meshes[i].variable_data.begin(); it!=meshes[i].variable_data.end(); ++it) {
const char* domain = it->first.first.c_str();
const char* variable = it->first.second.c_str();
fprintf(fid," variable(%s,%s): %s\n",domain,variable,it->second.write().c_str());
}
}
fclose( fid );
PROFILE_STOP( "write" );
fclose(fid);
PROFILE_STOP("write");
}
//! Read the mesh databases from a file
std::vector<MeshDatabase> read( const std::string &filename )
std::vector<MeshDatabase> read( const std::string& filename )
{
std::vector<MeshDatabase> meshes;
PROFILE_START( "read" );
FILE *fid = fopen( filename.c_str(), "rb" );
if ( fid == NULL )
ERROR( "Error opening file: " + filename );
PROFILE_START("read");
FILE *fid = fopen(filename.c_str(),"rb");
if ( fid==NULL )
ERROR("Error opening file");
char *line = new char[10000];
while ( std::fgets( line, 1000, fid ) != NULL ) {
if ( line[0] < 32 ) {
while ( std::fgets(line,1000,fid) != NULL ) {
if ( line[0]<32 ) {
// Empty line
continue;
} else if ( line[0] != ' ' ) {
meshes.resize( meshes.size() + 1 );
std::string name( line );
name.resize( name.size() - 1 );
meshes.resize(meshes.size()+1);
std::string name(line);
name.resize(name.size()-1);
meshes.back().name = name;
} else if ( strncmp( line, " format:", 10 ) == 0 ) {
meshes.back().format = getFileFormat( &line[10] );
} else if ( strncmp( line, " type:", 8 ) == 0 ) {
meshes.back().type = getMeshType( &line[8] );
} else if ( strncmp( line, " meshClass:", 13 ) == 0 ) {
meshes.back().meshClass = deblank( std::string( &line[13] ) );
} else if ( strncmp( line, " domain:", 10 ) == 0 ) {
DatabaseEntry data( &line[10] );
meshes.back().domains.push_back( data );
} else if ( strncmp( line, " variables:", 13 ) == 0 ) {
MeshDatabase &mesh = meshes.back();
std::vector<std::string> variables = splitList( &line[13], ';' );
mesh.variables.resize( variables.size() );
for ( size_t i = 0; i < variables.size(); i++ ) {
std::vector<std::string> tmp = splitList( variables[i].c_str(), '|' );
ASSERT( tmp.size() == 3 );
} else if ( strncmp(line," format:",10)==0 ) {
meshes.back().format = static_cast<unsigned char>(atoi(&line[10]));
} else if ( strncmp(line," type:",8)==0 ) {
meshes.back().type = static_cast<MeshType>(atoi(&line[8]));
} else if ( strncmp(line," meshClass:",13)==0 ) {
meshes.back().meshClass = deblank(std::string(&line[13]));
} else if ( strncmp(line," domain:",10)==0 ) {
DatabaseEntry data(&line[10]);
meshes.back().domains.push_back(data);
} else if ( strncmp(line," variables:",13)==0 ) {
MeshDatabase& mesh = meshes.back();
std::vector<std::string> variables = splitList(&line[13],';');
mesh.variables.resize(variables.size());
for (size_t i=0; i<variables.size(); i++) {
std::vector<std::string> tmp = splitList(variables[i].c_str(),'|');
ASSERT(tmp.size()==3);
mesh.variables[i].name = tmp[0];
mesh.variables[i].type = getVariableType( tmp[1] );
mesh.variables[i].dim = atoi( tmp[2].c_str() );
mesh.variables[i].type = static_cast<VariableType>(atoi(tmp[1].c_str()));
mesh.variables[i].dim = atoi(tmp[2].c_str());
}
} else if ( strncmp( line, " variable(", 12 ) == 0 ) {
size_t i1 = find( line, ',' );
size_t i2 = find( line, ':' );
std::string domain = deblank( std::string( line, 12, i1 - 12 ) );
std::string variable = deblank( std::string( line, i1 + 1, i2 - i1 - 2 ) );
std::pair<std::string, std::string> key( domain, variable );
DatabaseEntry data( &line[i2 + 1] );
meshes.back().variable_data.insert(
std::pair<std::pair<std::string, std::string>, DatabaseEntry>( key, data ) );
} else if ( strncmp(line," variable(",12)==0 ) {
size_t i1 = find(line,',');
size_t i2 = find(line,':');
std::string domain = deblank(std::string(line,12,i1-12));
std::string variable = deblank(std::string(line,i1+1,i2-i1-2));
std::pair<std::string,std::string> key(domain,variable);
DatabaseEntry data(&line[i2+1]);
meshes.back().variable_data.insert(
std::pair<std::pair<std::string,std::string>,DatabaseEntry>(key,data) );
} else {
ERROR( "Error reading line" );
ERROR("Error reading line");
}
}
fclose( fid );
delete[] line;
PROFILE_STOP( "read" );
fclose(fid);
delete [] line;
PROFILE_STOP("read");
return meshes;
}
// Return the mesh type
IO::MeshType meshType( const IO::Mesh &mesh )
IO::MeshType meshType( const IO::Mesh& mesh )
{
IO::MeshType type = IO::MeshType::Unknown;
IO::MeshType type = IO::Unknown;
const std::string meshClass = mesh.className();
if ( meshClass == "PointList" ) {
type = IO::MeshType::PointMesh;
} else if ( meshClass == "TriList" || meshClass == "TriMesh" ) {
type = IO::MeshType::SurfaceMesh;
} else if ( meshClass == "DomainMesh" ) {
type = IO::MeshType::VolumeMesh;
if ( meshClass=="PointList" ) {
type = IO::PointMesh;
} else if ( meshClass=="TriList" || meshClass=="TriMesh" ) {
type = IO::SurfaceMesh;
} else if ( meshClass=="DomainMesh" ) {
type = IO::VolumeMesh;
} else {
ERROR( "Unknown mesh" );
ERROR("Unknown mesh");
}
return type;
}
} // namespace IO
} // IO namespace

View File

@@ -16,85 +16,90 @@
#ifndef MeshDatabase_INC
#define MeshDatabase_INC
#include "IO/Mesh.h"
#include "common/MPI.h"
#include "IO/Mesh.h"
#include "common/MPI_Helpers.h"
#include <iostream>
#include <map>
#include <memory>
#include <string.h>
#include <vector>
#include <map>
namespace IO {
class Mesh;
//! Enum to identify mesh type
//enum class MeshType : char { PointMesh=1, SurfaceMesh=2, VolumeMesh=3, Unknown=-1 };
enum MeshType { PointMesh=1, SurfaceMesh=2, VolumeMesh=3, Unknown=-1 };
//! Helper struct for containing offsets for the mesh info
struct DatabaseEntry {
std::string name; //!< Name of the entry
std::string file; //!< Name of the file containing the entry
size_t offset; //!< Offset in the file to start reading
std::string write() const; //!< Convert the data to a string
void read( const char *line ); //!< Convert the string to data
void read( const std::string &line ); //!< Convert the string to data
DatabaseEntry() {} //!< Empty constructor
DatabaseEntry( const char *line ); //!< Convert the string to data
~DatabaseEntry() {} //!< Destructor
std::string name; //!< Name of the entry
std::string file; //!< Name of the file containing the entry
size_t offset; //!< Offset in the file to start reading
std::string write( ) const; //!< Convert the data to a string
void read( const char* line ); //!< Convert the string to data
void read( const std::string& line ); //!< Convert the string to data
DatabaseEntry( ) {} //!< Empty constructor
DatabaseEntry( const char* line ); //!< Convert the string to data
~DatabaseEntry() {} //!< Destructor
};
//! Structure to hold the info about the variables
struct VariableDatabase {
std::string name; //!< Name of the variable
IO::VariableType type; //!< Variable
unsigned int dim; //!< Number of points per grid point (1: scalar, 3: vector, ...)
std::string name; //!< Name of the variable
IO::VariableType type; //!< Variable
unsigned int dim; //!< Number of points per grid point (1: scalar, 3: vector, ...)
// Overload key operators
bool operator==( const VariableDatabase &rhs ) const;
bool operator!=( const VariableDatabase &rhs ) const;
bool operator>=( const VariableDatabase &rhs ) const;
bool operator<=( const VariableDatabase &rhs ) const;
bool operator>( const VariableDatabase &rhs ) const;
bool operator<( const VariableDatabase &rhs ) const;
bool operator==(const VariableDatabase& rhs ) const;
bool operator!=(const VariableDatabase& rhs ) const;
bool operator>=(const VariableDatabase& rhs ) const;
bool operator<=(const VariableDatabase& rhs ) const;
bool operator> (const VariableDatabase& rhs ) const;
bool operator< (const VariableDatabase& rhs ) const;
};
//! Structure to hold the info about the meshes
struct MeshDatabase {
typedef std::pair<std::string, std::string> variable_id;
typedef std::pair<std::string,std::string> variable_id;
std::string name; //!< Name of the mesh
MeshType type; //!< Mesh type
std::string meshClass; //!< Mesh class
FileFormat format; //!< Data format (1: old, 2: new, 3: new (single), 4: silo)
unsigned char format; //!< Data format (1: old, 2: new, 3: new (single), 4: silo)
std::vector<DatabaseEntry> domains; //!< List of the domains
std::vector<VariableDatabase> variables; //!< List of the variables
std::map<variable_id, DatabaseEntry> variable_data; //!< Data for the variables
VariableDatabase getVariableDatabase( const std::string &varname ) const;
std::vector<VariableDatabase> variables; //!< List of the variables
std::map<variable_id,DatabaseEntry> variable_data; //!< Data for the variables
VariableDatabase getVariableDatabase( const std::string& varname ) const;
public:
MeshDatabase();
~MeshDatabase();
MeshDatabase( const MeshDatabase & );
MeshDatabase &operator=( const MeshDatabase & );
MeshDatabase(const MeshDatabase&);
MeshDatabase& operator=(const MeshDatabase&);
};
//! Gather the mesh databases from all processors
std::vector<MeshDatabase> gatherAll(
const std::vector<MeshDatabase> &meshes, const Utilities::MPI &comm );
std::vector<MeshDatabase> gatherAll( const std::vector<MeshDatabase>& meshes, MPI_Comm comm );
//! Write the mesh databases to a file
void write( const std::vector<MeshDatabase> &meshes, const std::string &filename );
void write( const std::vector<MeshDatabase>& meshes, const std::string& filename );
//! Read the mesh databases from a file
std::vector<MeshDatabase> read( const std::string &filename );
std::vector<MeshDatabase> read( const std::string& filename );
//! Return the mesh type
IO::MeshType meshType( const IO::Mesh &mesh );
IO::MeshType meshType( const IO::Mesh& mesh );
} // namespace IO
} // IO namespace
#endif

View File

@@ -14,12 +14,12 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "IO/PIO.h"
#include "common/MPI.h"
#include "common/Utilities.h"
#include "common/MPI_Helpers.h"
#include <cstring>
#include <fstream>
#include <string>
#include <cstring>
namespace IO {
@@ -30,18 +30,19 @@ static ParallelStreamBuffer perr_buffer;
static ParallelStreamBuffer plog_buffer;
std::ostream pout( &pout_buffer );
std::ostream perr( &perr_buffer );
std::ostream plog( &plog_buffer );
std::ostream pout(&pout_buffer);
std::ostream perr(&perr_buffer);
std::ostream plog(&plog_buffer);
/****************************************************************************
* Functions to control logging *
****************************************************************************/
std::ofstream *global_filestream = NULL;
static void shutdownFilestream()
* Functions to control logging *
****************************************************************************/
std::ofstream *global_filestream=NULL;
static void shutdownFilestream( )
{
if ( global_filestream != NULL ) {
if ( global_filestream!=NULL ) {
global_filestream->flush();
global_filestream->close();
delete global_filestream;
@@ -51,16 +52,16 @@ static void shutdownFilestream()
void Utilities::logOnlyNodeZero( const std::string &filename )
{
int rank = 0;
#ifdef USE_MPI
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
#endif
#ifdef USE_MPI
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
#endif
if ( rank == 0 )
logAllNodes( filename, true );
logAllNodes(filename,true);
}
void Utilities::logAllNodes( const std::string &filename, bool singleStream )
{
if ( singleStream )
ERROR( "Not implimented yet" );
ERROR("Not implimented yet");
// If the filestream was open, then close it and reset streams
shutdownFilestream();
@@ -69,33 +70,33 @@ void Utilities::logAllNodes( const std::string &filename, bool singleStream )
std::string full_filename = filename;
if ( !singleStream ) {
int rank = 0;
#ifdef USE_MPI
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
#endif
#ifdef USE_MPI
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
#endif
char tmp[100];
sprintf( tmp, ".%04i", rank );
full_filename += std::string( tmp );
sprintf(tmp,".%04i",rank);
full_filename += std::string(tmp);
}
global_filestream = new std::ofstream( full_filename.c_str() );
global_filestream = new std::ofstream(full_filename.c_str());
if ( !( *global_filestream ) ) {
if ( !(*global_filestream) ) {
delete global_filestream;
global_filestream = NULL;
perr << "PIO: Could not open log file ``" << full_filename << "''\n";
} else {
pout_buffer.setOutputStream( global_filestream );
pout_buffer.setOutputStream( &std::cout );
perr_buffer.setOutputStream( global_filestream );
perr_buffer.setOutputStream( &std::cerr );
plog_buffer.setOutputStream( global_filestream );
pout_buffer.setOutputStream(global_filestream);
pout_buffer.setOutputStream(&std::cout);
perr_buffer.setOutputStream(global_filestream);
perr_buffer.setOutputStream(&std::cerr);
plog_buffer.setOutputStream(global_filestream);
}
}
/****************************************************************************
* ParallelStreamBuffer class *
****************************************************************************/
void Utilities::stopLogging()
* ParallelStreamBuffer class *
****************************************************************************/
void Utilities::stopLogging( )
{
pout_buffer.reset();
perr_buffer.reset();
@@ -107,71 +108,77 @@ void Utilities::stopLogging()
/****************************************************************************
* ParallelStreamBuffer class *
****************************************************************************/
ParallelStreamBuffer::ParallelStreamBuffer()
: d_rank( 0 ), d_size( 0 ), d_buffer_size( 0 ), d_buffer( NULL )
* ParallelStreamBuffer class *
****************************************************************************/
ParallelStreamBuffer::ParallelStreamBuffer( ):
d_rank(0), d_size(0), d_buffer_size(0), d_buffer(NULL)
{
}
ParallelStreamBuffer::~ParallelStreamBuffer() { delete[] d_buffer; }
void ParallelStreamBuffer::setOutputStream( std::ostream *stream ) { d_stream.push_back( stream ); }
ParallelStreamBuffer:: ~ParallelStreamBuffer()
{
delete [] d_buffer;
}
void ParallelStreamBuffer::setOutputStream( std::ostream *stream )
{
d_stream.push_back( stream );
}
int ParallelStreamBuffer::sync()
{
for ( size_t i = 0; i < d_stream.size(); i++ ) {
std::ostream &stream = *d_stream[i];
for (size_t i=0; i<d_stream.size(); i++) {
std::ostream& stream = *d_stream[i];
stream << d_buffer;
}
d_size = 0;
memset( d_buffer, 0, d_buffer_size );
memset(d_buffer,0,d_buffer_size);
return 0;
}
void ParallelStreamBuffer::reserve( size_t size )
{
if ( size > d_buffer_size ) {
if ( d_buffer_size == 0 ) {
if ( d_buffer_size==0 ) {
d_buffer_size = 1024;
d_buffer = new char[d_buffer_size];
memset( d_buffer, 0, d_buffer_size );
d_buffer = new char[d_buffer_size];
memset(d_buffer,0,d_buffer_size);
}
while ( size > d_buffer_size ) {
char *tmp = d_buffer;
d_buffer_size *= 2;
d_buffer = new char[d_buffer_size];
memset( d_buffer, 0, d_buffer_size );
memcpy( d_buffer, tmp, d_size );
delete[] tmp;
memset(d_buffer,0,d_buffer_size);
memcpy(d_buffer,tmp,d_size);
delete [] tmp;
}
}
}
std::streamsize ParallelStreamBuffer::xsputn( const char *text, std::streamsize n )
std::streamsize ParallelStreamBuffer::xsputn( const char* text, std::streamsize n )
{
reserve( d_size + n );
memcpy( &d_buffer[d_size], text, n );
reserve(d_size+n);
memcpy(&d_buffer[d_size],text,n);
d_size += n;
if ( text[n - 1] == 0 || text[n - 1] == 10 ) {
sync();
}
if ( text[n-1]==0 || text[n-1]==10 ) { sync(); }
return n;
}
int ParallelStreamBuffer::overflow( int ch )
int ParallelStreamBuffer::overflow(int ch)
{
reserve( d_size + 1 );
reserve(d_size+1);
d_buffer[d_size] = ch;
d_size++;
if ( ch == 0 || ch == 10 ) {
sync();
}
return std::char_traits<char>::to_int_type( ch );
if ( ch==0 || ch==10 ) { sync(); }
return std::char_traits<char>::to_int_type(ch);
}
int ParallelStreamBuffer::underflow() { return -1; }
void ParallelStreamBuffer::reset()
int ParallelStreamBuffer::underflow()
{
return -1;
}
void ParallelStreamBuffer::reset()
{
sync();
d_stream.clear();
delete[] d_buffer;
d_buffer = NULL;
delete [] d_buffer;
d_buffer = NULL;
d_buffer_size = 0;
}
} // namespace IO
} // IO namespace

View File

@@ -32,7 +32,7 @@ extern std::ostream pout;
/*!
* Parallel output stream perr writes to the standard error from all nodes.
* Output is prepended with the processor number.
* Output is prepended with the processor number.
*/
extern std::ostream perr;
@@ -60,11 +60,12 @@ inline int printp( const char *format, ... );
class ParallelStreamBuffer : public std::streambuf
{
public:
/*!
* Create a parallel buffer class. The object will require further
* initialization to set up the I/O streams and prefix string.
*/
ParallelStreamBuffer();
ParallelStreamBuffer( );
/*!
* Set the output file stream (multiple output streams are supported)
@@ -74,26 +75,26 @@ public:
/*!
* The destructor simply deallocates any internal data
* buffers. It does not modify the output streams.
* buffers. It does not modify the output streams.
*/
virtual ~ParallelStreamBuffer();
/*!
* Synchronize the parallel buffer (called from streambuf).
*/
virtual int sync();
virtual int sync();
/**
* Write the specified number of characters into the output stream (called
* from streambuf).
*/
virtual std::streamsize xsputn( const char *text, std::streamsize n );
*/
virtual std::streamsize xsputn(const char* text, std::streamsize n);
/*!
* Write an overflow character into the parallel buffer (called from
* streambuf).
*/
virtual int overflow( int ch );
virtual int overflow(int ch);
/*!
* Read an overflow character from the parallel buffer (called from
@@ -112,30 +113,30 @@ private:
size_t d_size;
size_t d_buffer_size;
char *d_buffer;
std::vector<std::ostream *> d_stream;
std::vector<std::ostream*> d_stream;
inline void reserve( size_t size );
};
namespace Utilities {
/*!
* Log messages for node zero only to the specified filename. All output
* to pout, perr, and plog on node zero will go to the log file.
*/
void logOnlyNodeZero( const std::string &filename );
/*!
* Log messages for node zero only to the specified filename. All output
* to pout, perr, and plog on node zero will go to the log file.
*/
void logOnlyNodeZero( const std::string &filename );
/*!
* Log messages from all nodes. The diagnostic data for processor XXXXX
* will be sent to a file with the name filename.XXXXX, where filename is
* the function argument.
*/
void logAllNodes( const std::string &filename, bool singleStream = false );
/*!
* Log messages from all nodes. The diagnostic data for processor XXXXX
* will be sent to a file with the name filename.XXXXX, where filename is
* the function argument.
*/
void logAllNodes( const std::string &filename, bool singleStream=false );
/*!
* Stop logging messages, flush buffers, and reset memory.
*/
void stopLogging();
/*!
* Stop logging messages, flush buffers, and reset memory.
*/
void stopLogging( );
} // namespace Utilities

View File

@@ -33,9 +33,9 @@
#include "IO/PIO.h"
#include <cstdio>
#include <iostream>
#include <stdarg.h>
#include <cstdio>
namespace IO {
@@ -43,17 +43,17 @@ namespace IO {
inline int printp( const char *format, ... )
{
va_list ap;
va_start( ap, format );
va_list ap;
va_start(ap,format);
char tmp[1024];
int n = vsprintf( tmp, format, ap );
va_end( ap );
int n = vsprintf(tmp,format,ap);
va_end(ap);
pout << tmp;
pout.flush();
return n;
}
} // namespace IO
} // IO namespace
#endif

View File

@@ -1,104 +0,0 @@
#include "IO/PackData.h"
#include <string.h>
/********************************************************
* Concrete implimentations for packing/unpacking *
********************************************************/
// unsigned char
template<>
size_t packsize<unsigned char>( const unsigned char &rhs )
{
return sizeof( unsigned char );
}
template<>
void pack<unsigned char>( const unsigned char &rhs, char *buffer )
{
memcpy( buffer, &rhs, sizeof( unsigned char ) );
}
template<>
void unpack<unsigned char>( unsigned char &data, const char *buffer )
{
memcpy( &data, buffer, sizeof( unsigned char ) );
}
// char
template<>
size_t packsize<char>( const char &rhs )
{
return sizeof( char );
}
template<>
void pack<char>( const char &rhs, char *buffer )
{
memcpy( buffer, &rhs, sizeof( char ) );
}
template<>
void unpack<char>( char &data, const char *buffer )
{
memcpy( &data, buffer, sizeof( char ) );
}
// int
template<>
size_t packsize<int>( const int &rhs )
{
return sizeof( int );
}
template<>
void pack<int>( const int &rhs, char *buffer )
{
memcpy( buffer, &rhs, sizeof( int ) );
}
template<>
void unpack<int>( int &data, const char *buffer )
{
memcpy( &data, buffer, sizeof( int ) );
}
// unsigned int
template<>
size_t packsize<unsigned int>( const unsigned int &rhs )
{
return sizeof( unsigned int );
}
template<>
void pack<unsigned int>( const unsigned int &rhs, char *buffer )
{
memcpy( buffer, &rhs, sizeof( int ) );
}
template<>
void unpack<unsigned int>( unsigned int &data, const char *buffer )
{
memcpy( &data, buffer, sizeof( int ) );
}
// size_t
template<>
size_t packsize<size_t>( const size_t &rhs )
{
return sizeof( size_t );
}
template<>
void pack<size_t>( const size_t &rhs, char *buffer )
{
memcpy( buffer, &rhs, sizeof( size_t ) );
}
template<>
void unpack<size_t>( size_t &data, const char *buffer )
{
memcpy( &data, buffer, sizeof( size_t ) );
}
// std::string
template<>
size_t packsize<std::string>( const std::string &rhs )
{
return rhs.size() + 1;
}
template<>
void pack<std::string>( const std::string &rhs, char *buffer )
{
memcpy( buffer, rhs.c_str(), rhs.size() + 1 );
}
template<>
void unpack<std::string>( std::string &data, const char *buffer )
{
data = std::string( buffer );
}

View File

@@ -1,77 +0,0 @@
// This file contains unctions to pack/unpack data structures
#ifndef included_PackData
#define included_PackData
#include <map>
#include <set>
#include <vector>
//! Template function to return the buffer size required to pack a class
template<class TYPE>
size_t packsize( const TYPE &rhs );
//! Template function to pack a class to a buffer
template<class TYPE>
void pack( const TYPE &rhs, char *buffer );
//! Template function to unpack a class from a buffer
template<class TYPE>
void unpack( TYPE &data, const char *buffer );
//! Template function to return the buffer size required to pack a std::vector
template<class TYPE>
size_t packsize( const std::vector<TYPE> &rhs );
//! Template function to pack a class to a buffer
template<class TYPE>
void pack( const std::vector<TYPE> &rhs, char *buffer );
//! Template function to pack a class to a buffer
template<class TYPE>
void unpack( std::vector<TYPE> &data, const char *buffer );
//! Template function to return the buffer size required to pack a std::pair
template<class TYPE1, class TYPE2>
size_t packsize( const std::pair<TYPE1, TYPE2> &rhs );
//! Template function to pack a class to a buffer
template<class TYPE1, class TYPE2>
void pack( const std::pair<TYPE1, TYPE2> &rhs, char *buffer );
//! Template function to pack a class to a buffer
template<class TYPE1, class TYPE2>
void unpack( std::pair<TYPE1, TYPE2> &data, const char *buffer );
//! Template function to return the buffer size required to pack a std::map
template<class TYPE1, class TYPE2>
size_t packsize( const std::map<TYPE1, TYPE2> &rhs );
//! Template function to pack a class to a buffer
template<class TYPE1, class TYPE2>
void pack( const std::map<TYPE1, TYPE2> &rhs, char *buffer );
//! Template function to pack a class to a buffer
template<class TYPE1, class TYPE2>
void unpack( std::map<TYPE1, TYPE2> &data, const char *buffer );
//! Template function to return the buffer size required to pack a std::set
template<class TYPE>
size_t packsize( const std::set<TYPE> &rhs );
//! Template function to pack a class to a buffer
template<class TYPE>
void pack( const std::set<TYPE> &rhs, char *buffer );
//! Template function to pack a class to a buffer
template<class TYPE>
void unpack( std::set<TYPE> &data, const char *buffer );
#include "IO/PackData.hpp"
#endif

View File

@@ -1,159 +0,0 @@
// This file functions to pack/unpack data structures
#ifndef included_PackData_hpp
#define included_PackData_hpp
#include "IO/PackData.h"
#include <map>
#include <set>
#include <string.h>
#include <vector>
/********************************************************
* Default instantiations for std::vector *
********************************************************/
template<class TYPE>
size_t packsize( const std::vector<TYPE> &rhs )
{
size_t bytes = sizeof( size_t );
for ( size_t i = 0; i < rhs.size(); i++ )
bytes += packsize( rhs[i] );
return bytes;
}
template<class TYPE>
void pack( const std::vector<TYPE> &rhs, char *buffer )
{
size_t size = rhs.size();
memcpy( buffer, &size, sizeof( size_t ) );
size_t pos = sizeof( size_t );
for ( size_t i = 0; i < rhs.size(); i++ ) {
pack( rhs[i], &buffer[pos] );
pos += packsize( rhs[i] );
}
}
template<class TYPE>
void unpack( std::vector<TYPE> &data, const char *buffer )
{
size_t size;
memcpy( &size, buffer, sizeof( size_t ) );
data.clear();
data.resize( size );
size_t pos = sizeof( size_t );
for ( size_t i = 0; i < data.size(); i++ ) {
unpack( data[i], &buffer[pos] );
pos += packsize( data[i] );
}
}
/********************************************************
* Default instantiations for std::pair *
********************************************************/
template<class TYPE1, class TYPE2>
size_t packsize( const std::pair<TYPE1, TYPE2> &rhs )
{
return packsize( rhs.first ) + packsize( rhs.second );
}
template<class TYPE1, class TYPE2>
void pack( const std::pair<TYPE1, TYPE2> &rhs, char *buffer )
{
pack( rhs.first, buffer );
pack( rhs.second, &buffer[packsize( rhs.first )] );
}
template<class TYPE1, class TYPE2>
void unpack( std::pair<TYPE1, TYPE2> &data, const char *buffer )
{
unpack( data.first, buffer );
unpack( data.second, &buffer[packsize( data.first )] );
}
/********************************************************
* Default instantiations for std::map *
********************************************************/
template<class TYPE1, class TYPE2>
size_t packsize( const std::map<TYPE1, TYPE2> &rhs )
{
size_t bytes = sizeof( size_t );
typename std::map<TYPE1, TYPE2>::const_iterator it;
for ( it = rhs.begin(); it != rhs.end(); ++it ) {
bytes += packsize( it->first );
bytes += packsize( it->second );
}
return bytes;
}
template<class TYPE1, class TYPE2>
void pack( const std::map<TYPE1, TYPE2> &rhs, char *buffer )
{
size_t N = rhs.size();
pack( N, buffer );
size_t pos = sizeof( size_t );
typename std::map<TYPE1, TYPE2>::const_iterator it;
for ( it = rhs.begin(); it != rhs.end(); ++it ) {
pack( it->first, &buffer[pos] );
pos += packsize( it->first );
pack( it->second, &buffer[pos] );
pos += packsize( it->second );
}
}
template<class TYPE1, class TYPE2>
void unpack( std::map<TYPE1, TYPE2> &data, const char *buffer )
{
size_t N = 0;
unpack( N, buffer );
size_t pos = sizeof( size_t );
data.clear();
for ( size_t i = 0; i < N; i++ ) {
std::pair<TYPE1, TYPE2> tmp;
unpack( tmp.first, &buffer[pos] );
pos += packsize( tmp.first );
unpack( tmp.second, &buffer[pos] );
pos += packsize( tmp.second );
data.insert( tmp );
}
}
/********************************************************
* Default instantiations for std::set *
********************************************************/
template<class TYPE>
size_t packsize( const std::set<TYPE> &rhs )
{
size_t bytes = sizeof( size_t );
typename std::set<TYPE>::const_iterator it;
for ( it = rhs.begin(); it != rhs.end(); ++it ) {
bytes += packsize( *it );
}
return bytes;
}
template<class TYPE>
void pack( const std::set<TYPE> &rhs, char *buffer )
{
size_t N = rhs.size();
pack( N, buffer );
size_t pos = sizeof( size_t );
typename std::set<TYPE>::const_iterator it;
for ( it = rhs.begin(); it != rhs.end(); ++it ) {
pack( *it );
pos += packsize( *it );
}
}
template<class TYPE>
void unpack( std::set<TYPE> &data, const char *buffer )
{
size_t N = 0;
unpack( N, buffer );
size_t pos = sizeof( size_t );
data.clear();
for ( size_t i = 0; i < N; i++ ) {
TYPE tmp;
unpack( tmp, &buffer[pos] );
pos += packsize( tmp );
data.insert( tmp );
}
}
#endif

View File

@@ -14,152 +14,71 @@
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 "IO/silo.h"
#include "IO/IOHelpers.h"
#include "common/Utilities.h"
#ifdef USE_SILO
#include "IO/silo.h"
#endif
#include <ProfilerApp.h>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <map>
#include <string.h>
#include <vector>
#include <map>
#include <cstdio>
// Inline function to read line without a return argument
static inline void fgetl( char *str, int num, FILE *stream )
static inline void fgetl( char * str, int num, FILE * stream )
{
char *ptr = fgets( str, num, stream );
if ( 0 ) {
char *temp = (char *) &ptr;
temp++;
}
}
// Check if the file exists
bool fileExists( const std::string &filename )
{
std::ifstream ifile( filename.c_str() );
return ifile.good();
char* ptr = fgets( str, num, stream );
if ( 0 ) {char *temp = (char *)&ptr; temp++;}
}
// Get the path to a file
std::string IO::getPath( const std::string &filename )
std::string IO::getPath( const std::string& filename )
{
std::string file( filename );
size_t k1 = file.rfind( 47 );
size_t k2 = file.rfind( 92 );
if ( k1 == std::string::npos ) {
k1 = 0;
}
if ( k2 == std::string::npos ) {
k2 = 0;
}
return file.substr( 0, std::max( k1, k2 ) );
std::string file(filename);
size_t k1 = file.rfind(47);
size_t k2 = file.rfind(92);
if ( k1==std::string::npos ) { k1=0; }
if ( k2==std::string::npos ) { k2=0; }
return file.substr(0,std::max(k1,k2));
}
// List the timesteps in the given directory (dumps.LBPM)
std::vector<std::string> IO::readTimesteps( const std::string &path, const std::string &format )
// List the timesteps in the given directors (dumps.LBPM)
std::vector<std::string> IO::readTimesteps( const std::string& filename )
{
// Get the name of the summary filename
std::string filename = path + "/";
if ( format == "old" || format == "new" ) {
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_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_new ) {
filename += "LBM.visit";
} else {
ERROR( "Unable to determine format (neither summary.LBM or LBM.visit exist)" );
}
} else {
ERROR( "Unknown format: " + format );
}
PROFILE_START( "readTimesteps" );
// Read the data
FILE *fid = fopen( filename.c_str(), "rb" );
if ( fid == NULL )
ERROR( "Error opening file" );
PROFILE_START("readTimesteps");
FILE *fid= fopen(filename.c_str(),"rb");
if ( fid==NULL )
ERROR("Error opening file");
std::vector<std::string> timesteps;
char buf[1000];
while ( fgets( buf, sizeof( buf ), fid ) != NULL ) {
std::string line( buf );
line.resize( line.size() - 1 );
while (fgets(buf,sizeof(buf),fid) != NULL) {
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 );
line.resize(pos);
if ( line.empty() )
continue;
timesteps.push_back( line );
timesteps.push_back(line);
}
fclose( fid );
PROFILE_STOP( "readTimesteps" );
fclose(fid);
PROFILE_STOP("readTimesteps");
return timesteps;
return timesteps;
}
// Get the maximum number of domains
int IO::maxDomains( const std::string &path, const std::string &format, const Utilities::MPI &comm )
{
int rank = comm.getRank();
int n_domains = 0;
if ( rank == 0 ) {
// Get the timesteps
auto timesteps = IO::readTimesteps( path, format );
ASSERT( !timesteps.empty() );
// Get the database for the first domain
auto db = IO::getMeshList( path, timesteps[0] );
for ( size_t i = 0; i < db.size(); i++ )
n_domains = std::max<int>( n_domains, db[i].domains.size() );
}
return comm.bcast( n_domains, 0 );
}
// Read the data for the given timestep
std::vector<IO::MeshDataStruct> IO::readData(
const std::string &path, const std::string &timestep, int rank )
{
// Get the mesh databases
auto db = IO::getMeshList( path, timestep );
// Create the data
std::vector<IO::MeshDataStruct> data( db.size() );
for ( size_t i = 0; i < data.size(); i++ ) {
data[i].precision = IO::DataType::Double;
data[i].meshName = db[i].name;
data[i].mesh = getMesh( path, timestep, db[i], rank );
data[i].vars.resize( db[i].variables.size() );
for ( size_t j = 0; j < db[i].variables.size(); j++ )
data[i].vars[j] = getVariable( path, timestep, db[i], rank, db[i].variables[j].name );
INSIST( data[i].check(), "Failed check of " + data[i].meshName );
}
return data;
}
// Read the list of variables for the given timestep
std::vector<IO::MeshDatabase> IO::getMeshList(
const std::string &path, const std::string &timestep )
std::vector<IO::MeshDatabase> IO::getMeshList( const std::string& path, const std::string& timestep )
{
std::string filename = path + "/" + timestep + "/LBM.summary";
return IO::read( filename );
@@ -167,361 +86,270 @@ std::vector<IO::MeshDatabase> IO::getMeshList(
// Read the given mesh domain
std::shared_ptr<IO::Mesh> IO::getMesh( const std::string &path, const std::string &timestep,
const IO::MeshDatabase &meshDatabase, int domain )
std::shared_ptr<IO::Mesh> IO::getMesh( const std::string& path, const std::string& timestep,
const IO::MeshDatabase& meshDatabase, int domain )
{
PROFILE_START( "getMesh" );
PROFILE_START("getMesh");
std::shared_ptr<IO::Mesh> mesh;
if ( meshDatabase.format == FileFormat::OLD ) {
if ( meshDatabase.format==1 ) {
// Old format (binary doubles)
std::string filename = path + "/" + timestep + "/" + meshDatabase.domains[domain].file;
FILE *fid = fopen( filename.c_str(), "rb" );
INSIST( fid != NULL, "Error opening file" );
FILE *fid = fopen(filename.c_str(),"rb");
INSIST(fid!=NULL,"Error opening file");
fseek( fid, 0, SEEK_END );
size_t bytes = ftell( fid );
size_t N_max = bytes / sizeof( double ) + 1000;
size_t bytes = ftell(fid);
size_t N_max = bytes/sizeof(double)+1000;
double *data = new double[N_max];
fseek( fid, 0, SEEK_SET );
size_t count = fread( data, sizeof( double ), N_max, fid );
fclose( fid );
if ( count % 3 != 0 )
ERROR( "Error reading file" );
if ( meshDatabase.type == IO::MeshType::PointMesh ) {
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];
P[i].y = data[3 * i + 1];
P[i].z = data[3 * i + 2];
fseek(fid,0,SEEK_SET);
size_t count = fread(data,sizeof(double),N_max,fid);
fclose(fid);
if ( count%3 != 0 )
ERROR("Error reading file");
if ( meshDatabase.type==IO::PointMesh ) {
size_t N = count/3;
std::shared_ptr<PointList> pointlist( new PointList(N) );
std::vector<Point>& P = pointlist->points;
for (size_t i=0; i<N; i++) {
P[i].x = data[3*i+0];
P[i].y = data[3*i+1];
P[i].z = data[3*i+2];
}
mesh = pointlist;
} else if ( meshDatabase.type == IO::MeshType::SurfaceMesh ) {
if ( count % 9 != 0 )
ERROR( "Error reading file (2)" );
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;
for ( size_t i = 0; i < N_tri; i++ ) {
A[i].x = data[9 * i + 0];
A[i].y = data[9 * i + 1];
A[i].z = data[9 * i + 2];
B[i].x = data[9 * i + 3];
B[i].y = data[9 * i + 4];
B[i].z = data[9 * i + 5];
C[i].x = data[9 * i + 6];
C[i].y = data[9 * i + 7];
C[i].z = data[9 * i + 8];
} else if ( meshDatabase.type==IO::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) );
std::vector<Point>& A = trilist->A;
std::vector<Point>& B = trilist->B;
std::vector<Point>& C = trilist->C;
for (size_t i=0; i<N_tri; i++) {
A[i].x = data[9*i+0];
A[i].y = data[9*i+1];
A[i].z = data[9*i+2];
B[i].x = data[9*i+3];
B[i].y = data[9*i+4];
B[i].z = data[9*i+5];
C[i].x = data[9*i+6];
C[i].y = data[9*i+7];
C[i].z = data[9*i+8];
}
mesh = trilist;
} else if ( meshDatabase.type == IO::MeshType::VolumeMesh ) {
} else if ( meshDatabase.type==IO::VolumeMesh ) {
// this was never supported in the old format
mesh = std::make_shared<DomainMesh>();
mesh = std::shared_ptr<DomainMesh>( new DomainMesh() );
} else {
ERROR( "Unknown mesh type" );
ERROR("Unknown mesh type");
}
delete[] data;
} else if ( meshDatabase.format == FileFormat::NEW ||
meshDatabase.format == FileFormat::NEW_SINGLE ) {
const DatabaseEntry &database = meshDatabase.domains[domain];
std::string filename = path + "/" + timestep + "/" + database.file;
FILE *fid = fopen( filename.c_str(), "rb" );
fseek( fid, database.offset, SEEK_SET );
delete [] data;
} else if ( meshDatabase.format==2 ) {
const DatabaseEntry& database = meshDatabase.domains[domain];
std::string filename = path + "/" + timestep + "/" + database.file;
FILE *fid = fopen(filename.c_str(),"rb");
fseek(fid,database.offset,SEEK_SET);
char line[1000];
fgetl( line, 1000, fid );
size_t i1 = find( line, ':' );
size_t i2 = find( &line[i1 + 1], ':' ) + i1 + 1;
size_t bytes = atol( &line[i2 + 1] );
char *data = new char[bytes];
size_t count = fread( data, 1, bytes, fid );
fclose( fid );
ASSERT( count == bytes );
if ( meshDatabase.meshClass == "PointList" ) {
mesh = std::make_shared<IO::PointList>();
} else if ( meshDatabase.meshClass == "TriMesh" ) {
mesh = std::make_shared<IO::TriMesh>();
} else if ( meshDatabase.meshClass == "TriList" ) {
mesh = std::make_shared<IO::TriList>();
} else if ( meshDatabase.meshClass == "DomainMesh" ) {
mesh = std::make_shared<IO::DomainMesh>();
fgetl(line,1000,fid);
size_t i1 = find(line,':');
size_t i2 = find(&line[i1+1],':')+i1+1;
size_t bytes = atol(&line[i2+1]);
char *data = new char[bytes];
size_t count = fread(data,1,bytes,fid);
fclose(fid);
ASSERT(count==bytes);
if ( meshDatabase.meshClass=="PointList" ) {
mesh.reset( new IO::PointList() );
} else if ( meshDatabase.meshClass=="TriMesh" ) {
mesh.reset( new IO::TriMesh() );
} else if ( meshDatabase.meshClass=="TriList" ) {
mesh.reset( new IO::TriList() );
} else if ( meshDatabase.meshClass=="DomainMesh" ) {
mesh.reset( new IO::DomainMesh() );
} else {
ERROR( "Unknown mesh class" );
ERROR("Unknown mesh class");
}
mesh->unpack( std::pair<size_t, void *>( bytes, data ) );
delete[] data;
} else if ( meshDatabase.format == FileFormat::SILO ) {
mesh->unpack( std::pair<size_t,void*>(bytes,data) );
delete [] data;
} else if ( meshDatabase.format==4 ) {
// Reading a silo file
#ifdef USE_SILO
const DatabaseEntry &database = meshDatabase.domains[domain];
std::string filename = path + "/" + timestep + "/" + database.file;
auto fid = silo::open( filename, silo::READ );
if ( meshDatabase.meshClass == "PointList" ) {
const DatabaseEntry& database = meshDatabase.domains[domain];
std::string filename = path + "/" + timestep + "/" + database.file;
auto fid = silo::open( filename, silo::READ );
if ( meshDatabase.meshClass=="PointList" ) {
Array<double> coords = silo::readPointMesh<double>( fid, database.name );
ASSERT( coords.size( 1 ) == 3 );
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 );
mesh2->points[i].z = coords( i, 2 );
ASSERT(coords.size(1)==3);
std::shared_ptr<IO::PointList> mesh2( new 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);
mesh2->points[i].z = coords(i,2);
}
mesh = mesh2;
} else if ( meshDatabase.meshClass == "TriMesh" || meshDatabase.meshClass == "TriList" ) {
} else if ( meshDatabase.meshClass=="TriMesh" || meshDatabase.meshClass=="TriList" ) {
Array<double> coords;
Array<int> tri;
silo::readTriMesh( fid, database.name, coords, tri );
ASSERT( tri.size( 1 ) == 3 && coords.size( 1 ) == 3 );
int N_tri = tri.size( 0 );
int N_point = coords.size( 0 );
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 );
mesh2->vertices->points[i].z = coords( i, 2 );
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 ) );
for (int i=0; i<N_point; i++) {
mesh2->vertices->points[i].x = coords(i,0);
mesh2->vertices->points[i].y = coords(i,1);
mesh2->vertices->points[i].z = coords(i,2);
}
for ( int i = 0; i < N_tri; i++ ) {
mesh2->A[i] = tri( i, 0 );
mesh2->B[i] = tri( i, 1 );
mesh2->C[i] = tri( i, 2 );
for (int i=0; i<N_tri; i++) {
mesh2->A[i] = tri(i,0);
mesh2->B[i] = tri(i,1);
mesh2->C[i] = tri(i,2);
}
if ( meshDatabase.meshClass == "TriMesh" ) {
if ( meshDatabase.meshClass=="TriMesh" ) {
mesh = mesh2;
} else if ( meshDatabase.meshClass == "TriList" ) {
} else if ( meshDatabase.meshClass=="TriList" ) {
auto trilist = IO::getTriList( std::dynamic_pointer_cast<IO::Mesh>( mesh2 ) );
mesh = trilist;
mesh = trilist;
}
} else if ( meshDatabase.meshClass == "DomainMesh" ) {
} else if ( meshDatabase.meshClass=="DomainMesh" ) {
std::vector<double> range;
std::vector<int> N;
silo::readUniformMesh( fid, database.name, range, N );
auto rankinfo = silo::read<int>( fid, database.name + "_rankinfo" );
auto rankinfo = silo::read<int>( fid, database.name+"_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] );
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] ) );
} else {
ERROR( "Unknown mesh class" );
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" );
ERROR("Build without silo support");
#endif
} else {
ERROR( "Unknown format" );
ERROR("Unknown format");
}
PROFILE_STOP( "getMesh" );
PROFILE_STOP("getMesh");
return mesh;
}
// Read the given variable for the given mesh domain
std::shared_ptr<IO::Variable> IO::getVariable( const std::string &path, const std::string &timestep,
const MeshDatabase &meshDatabase, int domain, const std::string &variable )
std::shared_ptr<IO::Variable> IO::getVariable( const std::string& path, const std::string& timestep,
const MeshDatabase& meshDatabase, int domain, const std::string& variable )
{
std::pair<std::string, std::string> key( meshDatabase.domains[domain].name, variable );
auto it = meshDatabase.variable_data.find( key );
if ( it == meshDatabase.variable_data.end() )
std::pair<std::string,std::string> key(meshDatabase.domains[domain].name,variable);
std::map<std::pair<std::string,std::string>,DatabaseEntry>::const_iterator it;
it = meshDatabase.variable_data.find(key);
if ( it==meshDatabase.variable_data.end() )
return std::shared_ptr<IO::Variable>();
std::shared_ptr<IO::Variable> var;
if ( meshDatabase.format == FileFormat::NEW || meshDatabase.format == FileFormat::NEW_SINGLE ) {
const DatabaseEntry &database = it->second;
std::string filename = path + "/" + timestep + "/" + database.file;
FILE *fid = fopen( filename.c_str(), "rb" );
fseek( fid, database.offset, SEEK_SET );
if ( meshDatabase.format == 2 ) {
const DatabaseEntry& database = it->second;
std::string filename = path + "/" + timestep + "/" + database.file;
FILE *fid = fopen(filename.c_str(),"rb");
fseek(fid,database.offset,SEEK_SET);
char line[1000];
fgetl( line, 1000, fid );
size_t i1 = find( line, ':' );
size_t i2 = find( &line[i1 + 1], ':' ) + i1 + 1;
std::vector<std::string> values = splitList( &line[i2 + 1], ',' );
ASSERT( values.size() == 5 );
int dim = atoi( values[0].c_str() );
auto type = values[1];
size_t N = atol( values[2].c_str() );
size_t bytes = atol( values[3].c_str() );
std::string precision = values[4];
var = std::make_shared<IO::Variable>();
var->dim = dim;
var->type = getVariableType( type );
var->name = variable;
var->data.resize( N, dim );
if ( precision == "double" ) {
size_t count = fread( var->data.data(), sizeof( double ), N * dim, fid );
ASSERT( count * sizeof( double ) == bytes );
fgetl(line,1000,fid);
size_t i1 = find(line,':');
size_t i2 = find(&line[i1+1],':')+i1+1;
std::vector<std::string> values = splitList(&line[i2+1],',');
ASSERT(values.size()==5);
int dim = atoi(values[0].c_str());
int type = atoi(values[1].c_str());
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->dim = dim;
var->type = static_cast<IO::VariableType>(type);
var->name = variable;
var->data.resize(N*dim);
if ( precision=="double" ) {
size_t count = fread(var->data.data(),sizeof(double),N*dim,fid);
ASSERT(count*sizeof(double)==bytes);
} else {
ERROR( "Format not implimented" );
ERROR("Format not implimented");
}
fclose( fid );
} else if ( meshDatabase.format == FileFormat::SILO ) {
fclose(fid);
} else if ( meshDatabase.format == 4 ) {
// Reading a silo file
#ifdef USE_SILO
const auto &database = meshDatabase.domains[domain];
const auto& database = meshDatabase.domains[domain];
auto variableDatabase = meshDatabase.getVariableDatabase( variable );
std::string filename = path + "/" + timestep + "/" + database.file;
auto fid = silo::open( filename, silo::READ );
var = std::make_shared<Variable>( variableDatabase.dim, variableDatabase.type, variable );
if ( meshDatabase.meshClass == "PointList" ) {
std::string filename = path + "/" + timestep + "/" + database.file;
auto fid = silo::open( filename, silo::READ );
var.reset( new 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" ) {
} else if ( meshDatabase.meshClass=="TriMesh" || meshDatabase.meshClass=="TriList" ) {
var->data = silo::readTriMeshVariable<double>( fid, variable );
} else if ( meshDatabase.meshClass == "DomainMesh" ) {
} else if ( meshDatabase.meshClass=="DomainMesh" ) {
var->data = silo::readUniformMeshVariable<double>( fid, variable );
} else {
ERROR( "Unknown mesh class" );
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 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" );
ERROR("Build without silo support");
#endif
} else {
ERROR( "Unknown format" );
ERROR("Unknown format");
}
return var;
}
/****************************************************
* Reformat the variable to match the mesh *
****************************************************/
void IO::reformatVariable( const IO::Mesh &mesh, IO::Variable &var )
* Reformat the variable to match the mesh *
****************************************************/
void IO::reformatVariable( const IO::Mesh& mesh, IO::Variable& var )
{
if ( mesh.className() == "DomainMesh" ) {
const IO::DomainMesh &mesh2 = dynamic_cast<const IO::DomainMesh &>( mesh );
const IO::DomainMesh& mesh2 = dynamic_cast<const IO::DomainMesh&>( mesh );
if ( var.type == VariableType::NodeVariable ) {
size_t N2 =
var.data.length() / ( ( mesh2.nx + 1 ) * ( mesh2.ny + 1 ) * ( mesh2.nz + 1 ) );
ASSERT(
( mesh2.nx + 1 ) * ( mesh2.ny + 1 ) * ( mesh2.nz + 1 ) * N2 == var.data.length() );
var.data.reshape(
{ (size_t) mesh2.nx + 1, (size_t) mesh2.ny + 1, (size_t) mesh2.nz + 1, N2 } );
size_t N2 = var.data.length() / ((mesh2.nx+1)*(mesh2.ny+1)*(mesh2.nz+1));
ASSERT( (mesh2.nx+1)*(mesh2.ny+1)*(mesh2.nz+1)*N2 == var.data.length() );
var.data.reshape( { (size_t) mesh2.nx+1, (size_t) mesh2.ny+1, (size_t) mesh2.nz+1, N2 } );
} else if ( var.type == VariableType::EdgeVariable ) {
ERROR( "Not finished" );
ERROR("Not finished");
} else if ( var.type == VariableType::SurfaceVariable ) {
ERROR( "Not finished" );
ERROR("Not finished");
} else if ( var.type == VariableType::VolumeVariable ) {
size_t N2 = var.data.length() / ( mesh2.nx * mesh2.ny * mesh2.nz );
ASSERT( mesh2.nx * mesh2.ny * mesh2.nz * N2 == var.data.length() );
size_t N2 = var.data.length() / (mesh2.nx*mesh2.ny*mesh2.nz);
ASSERT( mesh2.nx*mesh2.ny*mesh2.nz*N2 == var.data.length() );
var.data.reshape( { (size_t) mesh2.nx, (size_t) mesh2.ny, (size_t) mesh2.nz, N2 } );
} else {
ERROR( "Invalid variable type" );
ERROR("Invalid variable type");
}
} else if ( mesh.className() == "PointList" ) {
const IO::PointList &mesh2 = dynamic_cast<const IO::PointList &>( mesh );
size_t N = mesh2.points.size();
size_t N_var = var.data.length() / N;
ASSERT( N * N_var == var.data.length() );
const IO::PointList& mesh2 = dynamic_cast<const IO::PointList&>( mesh );
size_t N = mesh2.points.size();
size_t N_var = var.data.length()/N;
ASSERT( N*N_var == var.data.length() );
var.data.reshape( { N, N_var } );
} else if ( mesh.className() == "TriMesh" || mesh.className() == "TriList" ) {
std::shared_ptr<Mesh> mesh_ptr( const_cast<Mesh *>( &mesh ), []( void * ) {} );
} else if ( mesh.className()=="TriMesh" || mesh.className() == "TriList" ) {
std::shared_ptr<Mesh> mesh_ptr( const_cast<Mesh*>(&mesh), []( void* ) {} );
std::shared_ptr<TriMesh> mesh2 = getTriMesh( mesh_ptr );
if ( var.type == VariableType::NodeVariable ) {
size_t N = mesh2->vertices->points.size();
size_t N_var = var.data.length() / N;
ASSERT( N * N_var == var.data.length() );
size_t N = mesh2->vertices->points.size();
size_t N_var = var.data.length()/N;
ASSERT( N*N_var == var.data.length() );
var.data.reshape( { N, N_var } );
} else if ( var.type == VariableType::EdgeVariable ) {
ERROR( "Not finished" );
ERROR("Not finished");
} else if ( var.type == VariableType::SurfaceVariable ) {
ERROR( "Not finished" );
ERROR("Not finished");
} else if ( var.type == VariableType::VolumeVariable ) {
size_t N = mesh2->A.size();
size_t N_var = var.data.length() / N;
ASSERT( N * N_var == var.data.length() );
size_t N = mesh2->A.size();
size_t N_var = var.data.length()/N;
ASSERT( N*N_var == var.data.length() );
var.data.reshape( { N, N_var } );
} else {
ERROR( "Invalid variable type" );
ERROR("Invalid variable type");
}
} else {
ERROR( "Unknown mesh type" );
ERROR("Unknown mesh type");
}
}

View File

@@ -29,59 +29,20 @@ namespace IO {
//! Get the path to a file
std::string getPath( const std::string &filename );
std::string getPath( const std::string& filename );
/*!
* @brief Get the maximum number of domains written
* @details This function reads the summary files to determine the maximum
* number of domains in the output.
* @param[in] path The path to use for reading
* @param[in] format The data format to use:
* old - Old mesh format (provided for backward compatibility)
* new - New format, 1 file/process
* silo - Silo
* auto - Auto-determin the format
* @param[in] comm Optional comm to use to reduce IO load by
* reading on rank 0 and then communicating the result
*/
int maxDomains( const std::string &path, const std::string &format = "auto",
const Utilities::MPI &comm = MPI_COMM_SELF );
/*!
* @brief Read the timestep list
* @details This function reads the timestep list from the summary file.
* @param[in] path The path to use for reading
* @param[in] format The data format to use:
* old - Old mesh format (provided for backward compatibility)
* new - New format, 1 file/process
* silo - Silo
* auto - Auto-determin the format
* @return append Append any existing data (default is false)
*/
std::vector<std::string> readTimesteps(
const std::string &path, const std::string &format = "auto" );
/*!
* @brief Read the data for the timestep
* @details This function reads the mesh and variable data provided for the given timestep.
* @param[in] path The path to use for reading
* @param[in] timestep The timestep iteration
* @param[in] domain The desired domain to read
*/
std::vector<IO::MeshDataStruct> readData(
const std::string &path, const std::string &timestep, int domain );
//! List the timesteps in the given directors (dumps.LBPM)
std::vector<std::string> readTimesteps( const std::string& filename );
//! Read the list of mesh databases for the given timestep
std::vector<IO::MeshDatabase> getMeshList( const std::string &path, const std::string &timestep );
std::vector<IO::MeshDatabase> getMeshList( const std::string& path, const std::string& timestep );
//! Read the given mesh domain
std::shared_ptr<IO::Mesh> getMesh( const std::string &path, const std::string &timestep,
const MeshDatabase &meshDatabase, int domain );
std::shared_ptr<IO::Mesh> getMesh( const std::string& path, const std::string& timestep,
const MeshDatabase& meshDatabase, int domain );
/*!
@@ -94,19 +55,19 @@ std::shared_ptr<IO::Mesh> getMesh( const std::string &path, const std::string &t
* @param[in] variable The variable name to read
* @return Returns the variable data as a linear array
*/
std::shared_ptr<IO::Variable> getVariable( const std::string &path, const std::string &timestep,
const MeshDatabase &meshDatabase, int domain, const std::string &variable );
std::shared_ptr<IO::Variable> getVariable( const std::string& path, const std::string& timestep,
const MeshDatabase& meshDatabase, int domain, const std::string& variable );
/*!
* @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] var The variable name to read
* @param[in/out] variable The variable name to read
*/
void reformatVariable( const IO::Mesh &mesh, IO::Variable &var );
void reformatVariable( const IO::Mesh& mesh, IO::Variable& var );
} // namespace IO
} // IO namespace
#endif

View File

@@ -1,253 +0,0 @@
#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

View File

@@ -14,84 +14,30 @@
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/Xdmf.h"
#include "common/MPI.h"
#include "IO/IOHelpers.h"
#include "IO/silo.h"
#include "common/MPI_Helpers.h"
#include "common/Utilities.h"
#include "ProfilerApp.h"
#include <algorithm>
#include <memory>
#include <set>
#include <sys/stat.h>
#include <algorithm>
#include <vector>
#include <set>
#include <memory>
enum class Format { OLD, NEW, SILO, HDF5, UNKNOWN };
enum class Format { OLD, NEW, SILO, 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 & );
/****************************************************
* Recursively create the subdirectory *
****************************************************/
static void recursiveMkdir( const std::string &path, mode_t mode )
{
// Iterate through the root directories until we create the desired path
for ( size_t pos = 0; pos < path.size(); ) {
// slide backwards in string until next slash found
pos++;
for ( ; pos < path.size(); pos++ ) {
if ( path[pos] == '/' || path[pos] == 92 )
break;
}
// Create the temporary path
auto path2 = path.substr( 0, pos );
// Check if the temporary path exists
struct stat status;
int result = stat( path2.data(), &status );
if ( result == 0 ) {
// if there is a part of the path that already exists make sure it is really a directory
if ( !S_ISDIR( status.st_mode ) ) {
ERROR(
"Error in recursiveMkdir...\n"
" Cannot create directories in path = " +
path +
"\n because some intermediate item in path exists and is NOT a directory" );
}
continue;
}
// Create the directory and test the result
result = mkdir( path2.data(), mode );
if ( result != 0 ) {
// Maybe another rank created the directory, check
int result = stat( path2.data(), &status );
if ( result != 0 && !S_ISDIR( status.st_mode ) )
ERROR( "Error in Utilities::recursiveMkdir...\n"
" Cannot create directory = " +
path2 );
}
}
}
/****************************************************
* Initialize the writer *
****************************************************/
* Initialize the writer *
****************************************************/
static std::string global_IO_path;
static Format global_IO_format = Format::UNKNOWN;
void IO::initialize( const std::string &path, const std::string &format, bool append )
void IO::initialize( const std::string& path, const std::string& format, bool append )
{
if ( path.empty() )
global_IO_path = ".";
@@ -103,266 +49,475 @@ 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();
if ( !append && rank == 0 ) {
recursiveMkdir( path, S_IRWXU | S_IRGRP );
ERROR("Unknown format");
int rank = comm_rank(MPI_COMM_WORLD);
if ( !append && rank==0 ) {
mkdir(path.c_str(),S_IRWXU|S_IRGRP);
std::string filename;
if ( global_IO_format == Format::OLD || global_IO_format == Format::NEW )
if ( global_IO_format==Format::OLD || global_IO_format==Format::NEW )
filename = global_IO_path + "/summary.LBM";
else if ( global_IO_format == Format::SILO || global_IO_format == Format::HDF5 )
else if ( global_IO_format==Format::SILO )
filename = global_IO_path + "/LBM.visit";
else
ERROR( "Unknown format" );
auto fid = fopen( filename.c_str(), "wb" );
fclose( fid );
ERROR("Unknown format");
auto fid = fopen(filename.c_str(),"wb");
fclose(fid);
}
}
// Write the mesh data in the original format
static std::vector<IO::MeshDatabase> writeMeshesOrigFormat(
const std::vector<IO::MeshDataStruct> &meshData, const std::string &path, int rank )
static std::vector<IO::MeshDatabase> writeMeshesOrigFormat( const std::vector<IO::MeshDataStruct>& meshData, const std::string& path )
{
int rank = MPI_WORLD_RANK();
std::vector<IO::MeshDatabase> meshes_written;
for ( size_t i = 0; i < meshData.size(); i++ ) {
for (size_t i=0; i<meshData.size(); i++) {
char domainname[100], filename[100], fullpath[200];
sprintf( domainname, "%05i", rank );
sprintf( filename, "%s.%05i", meshData[i].meshName.c_str(), rank );
sprintf( fullpath, "%s/%s", path.c_str(), filename );
FILE *fid = fopen( fullpath, "wb" );
INSIST( fid != NULL, std::string( "Error opening file: " ) + fullpath );
sprintf(domainname,"%05i",rank);
sprintf(filename,"%s.%05i",meshData[i].meshName.c_str(),rank);
sprintf(fullpath,"%s/%s",path.c_str(),filename);
FILE *fid = fopen(fullpath,"wb");
INSIST(fid!=NULL,std::string("Error opening file: ")+fullpath);
std::shared_ptr<IO::Mesh> mesh = meshData[i].mesh;
IO::MeshDatabase mesh_entry;
mesh_entry.name = meshData[i].meshName;
mesh_entry.type = meshType( *mesh );
mesh_entry.name = meshData[i].meshName;
mesh_entry.type = meshType(*mesh);
mesh_entry.meshClass = meshData[i].mesh->className();
mesh_entry.format = IO::FileFormat::OLD;
mesh_entry.format = 1;
IO::DatabaseEntry domain;
domain.name = domainname;
domain.file = filename;
domain.name = domainname;
domain.file = filename;
domain.offset = 0;
mesh_entry.domains.push_back( domain );
static bool printVariableSupportMsg = true;
if ( !meshData[i].vars.empty() && printVariableSupportMsg ) {
printVariableSupportMsg = false;
printf( "Warning: variables are not supported with this format (original)\n" );
mesh_entry.domains.push_back(domain);
if ( !meshData[i].vars.empty() ) {
printf("Warning: variables are not supported with this format\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" ) {
if ( meshClass=="PointList" ) {
// List of points
std::shared_ptr<IO::PointList> pointlist =
std::dynamic_pointer_cast<IO::PointList>( mesh );
const std::vector<Point> &P = pointlist->points;
for ( size_t i = 0; i < P.size(); i++ ) {
std::shared_ptr<IO::PointList> pointlist = std::dynamic_pointer_cast<IO::PointList>(mesh);
const std::vector<Point>& P = pointlist->points;
for (size_t i=0; i<P.size(); i++) {
double x[3];
x[0] = P[i].x;
x[1] = P[i].y;
x[2] = P[i].z;
fwrite( x, sizeof( double ), 3, fid );
x[0] = P[i].x; x[1] = P[i].y; x[2] = P[i].z;
fwrite(x,sizeof(double),3,fid);
}
} else if ( meshClass == "TriList" || meshClass == "TriMesh" ) {
} else if ( meshClass=="TriList" || meshClass=="TriMesh" ) {
// Triangle mesh
std::shared_ptr<IO::TriList> trilist = IO::getTriList( mesh );
const std::vector<Point> &A = trilist->A;
const std::vector<Point> &B = trilist->B;
const std::vector<Point> &C = trilist->C;
for ( size_t i = 0; i < A.size(); i++ ) {
std::shared_ptr<IO::TriList> trilist = IO::getTriList(mesh);
const std::vector<Point>& A = trilist->A;
const std::vector<Point>& B = trilist->B;
const std::vector<Point>& C = trilist->C;
for (size_t i=0; i<A.size(); i++) {
double tri[9];
tri[0] = A[i].x;
tri[1] = A[i].y;
tri[2] = A[i].z;
tri[3] = B[i].x;
tri[4] = B[i].y;
tri[5] = B[i].z;
tri[6] = C[i].x;
tri[7] = C[i].y;
tri[8] = C[i].z;
fwrite( tri, sizeof( double ), 9, fid );
tri[0] = A[i].x; tri[1] = A[i].y; tri[2] = A[i].z;
tri[3] = B[i].x; tri[4] = B[i].y; tri[5] = B[i].z;
tri[6] = C[i].x; tri[7] = C[i].y; tri[8] = C[i].z;
fwrite(tri,sizeof(double),9,fid);
}
} else if ( meshClass == "DomainMesh" ) {
} else if ( meshClass=="DomainMesh" ) {
// This format was never supported with the old format
} else {
ERROR( "Unknown mesh" );
ERROR("Unknown mesh");
}
fclose( fid );
fclose(fid);
std::sort( mesh_entry.variables.begin(), mesh_entry.variables.end() );
mesh_entry.variables.erase(
std::unique( mesh_entry.variables.begin(), mesh_entry.variables.end() ),
mesh_entry.variables.end() );
meshes_written.push_back( mesh_entry );
mesh_entry.variables.erase( std::unique( mesh_entry.variables.begin(), mesh_entry.variables.end() ), mesh_entry.variables.end() );
meshes_written.push_back(mesh_entry);
}
return meshes_written;
}
// Create the database entry for the mesh data
IO::MeshDatabase IO::getDatabase(
const std::string &filename, const IO::MeshDataStruct &mesh, IO::FileFormat format, int rank )
static IO::MeshDatabase getDatabase( const std::string& filename, const IO::MeshDataStruct& mesh, int format )
{
int rank = MPI_WORLD_RANK();
char domainname[100];
sprintf( domainname, "%s_%05i", mesh.meshName.c_str(), rank );
sprintf(domainname,"%s_%05i",mesh.meshName.c_str(),rank);
// Create the MeshDatabase
IO::MeshDatabase database;
database.name = mesh.meshName;
database.type = meshType( *( mesh.mesh ) );
database.name = mesh.meshName;
database.type = meshType(*(mesh.mesh));
database.meshClass = mesh.mesh->className();
database.format = format;
database.format = format;
// Write the mesh
IO::DatabaseEntry domain;
domain.name = domainname;
domain.file = filename;
domain.name = domainname;
domain.file = filename;
domain.offset = -1;
database.domains.push_back( domain );
database.domains.push_back(domain);
// Write the variables
for ( size_t i = 0; i < mesh.vars.size(); i++ ) {
for (size_t i=0; i<mesh.vars.size(); i++) {
// Add basic variable info
IO::VariableDatabase info;
info.name = mesh.vars[i]->name;
info.type = mesh.vars[i]->type;
info.dim = mesh.vars[i]->dim;
database.variables.push_back( info );
info.dim = mesh.vars[i]->dim;
database.variables.push_back(info);
// Add domain variable info
IO::DatabaseEntry variable;
variable.name = mesh.vars[i]->name;
variable.file = filename;
variable.name = mesh.vars[i]->name;
variable.file = filename;
variable.offset = -1;
std::pair<std::string, std::string> key( domain.name, mesh.vars[i]->name );
database.variable_data.insert(
std::pair<std::pair<std::string, std::string>, IO::DatabaseEntry>( key, variable ) );
std::pair<std::string,std::string> key(domain.name,mesh.vars[i]->name);
database.variable_data.insert(
std::pair<std::pair<std::string,std::string>,IO::DatabaseEntry>(key,variable) );
}
return database;
}
// Write a mesh (and variables) to a file
static IO::MeshDatabase write_domain( FILE *fid, const std::string &filename,
const IO::MeshDataStruct &mesh, IO::FileFormat format, int rank )
static IO::MeshDatabase write_domain( FILE *fid, const std::string& filename,
const IO::MeshDataStruct& mesh, int format )
{
ASSERT( !mesh.meshName.empty() );
const int level = 0;
int rank = MPI_WORLD_RANK();
// Create the MeshDatabase
IO::MeshDatabase database = getDatabase( filename, mesh, format, rank );
IO::MeshDatabase database = getDatabase( filename, mesh, format );
// Write the mesh
IO::DatabaseEntry &domain = database.domains[0];
domain.offset = ftell( fid );
std::pair<size_t, void *> data = mesh.mesh->pack( level );
fprintf( fid, "Mesh: %s-%05i: %lu\n", mesh.meshName.c_str(), rank, data.first );
fwrite( data.second, 1, data.first, fid );
fprintf( fid, "\n" );
delete[]( char * ) data.second;
IO::DatabaseEntry& domain = database.domains[0];
domain.offset = ftell(fid);
std::pair<size_t,void*> data = mesh.mesh->pack(level);
fprintf(fid,"Mesh: %s-%05i: %lu\n",mesh.meshName.c_str(),rank,data.first);
fwrite(data.second,1,data.first,fid);
fprintf(fid,"\n");
delete [] (char*) data.second;
// Write the variables
for ( size_t i = 0; i < mesh.vars.size(); i++ ) {
ASSERT( mesh.vars[i]->type != IO::VariableType::NullVariable );
std::pair<std::string, std::string> key( domain.name, mesh.vars[i]->name );
auto &variable = database.variable_data[key];
variable.offset = ftell( fid );
int dim = mesh.vars[i]->dim;
auto type = getString( mesh.vars[i]->type );
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 );
fprintf( fid, "\n" );
for (size_t i=0; i<mesh.vars.size(); i++) {
std::pair<std::string,std::string> key(domain.name,mesh.vars[i]->name);
IO::DatabaseEntry& variable = database.variable_data[key];
variable.offset = ftell(fid);
int dim = mesh.vars[i]->dim;
int type = static_cast<int>(mesh.vars[i]->type);
size_t N = mesh.vars[i]->data.length();
if ( type == static_cast<int>(IO::VariableType::NullVariable) ) {
ERROR("Variable type not set");
}
size_t N_mesh = mesh.mesh->numberPointsVar(mesh.vars[i]->type);
ASSERT(N==dim*N_mesh);
fprintf(fid,"Var: %s-%05i-%s: %i, %i, %lu, %lu, double\n",
database.name.c_str(), rank, variable.name.c_str(),
dim, type, N_mesh, N*sizeof(double) );
fwrite(mesh.vars[i]->data.data(),sizeof(double),N,fid);
fprintf(fid,"\n");
}
return database;
}
// 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,
int rank )
#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() };
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() };
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 ) {
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 );
silo::writePointMeshVariable( fid, meshname, var.name, data2 );
} else if ( var.precision == IO::DataType::Int ) {
Array<int> data2( var.data.size() );
data2.copy( var.data );
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() };
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];
auto type = static_cast<silo::VariableType>( var.type );
if ( var.precision == IO::DataType::Double ) {
silo::writeTriMeshVariable( fid, 3, meshname, var.name, var.data, type );
} else if ( var.precision == IO::DataType::Float ) {
Array<float> data2( var.data.size() );
data2.copy( var.data );
silo::writeTriMeshVariable( fid, 3, meshname, var.name, data2, type );
} else if ( var.precision == IO::DataType::Int ) {
Array<int> data2( var.data.size() );
data2.copy( var.data );
silo::writeTriMeshVariable( fid, 3, meshname, var.name, data2, 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;
silo::writeUniformMesh<3>( fid, meshname, range, N );
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];
auto type = static_cast<silo::VariableType>( var.type );
if ( var.precision == IO::DataType::Double ) {
silo::writeUniformMeshVariable<3>( fid, meshname, N, var.name, var.data, type );
} else if ( var.precision == IO::DataType::Float ) {
Array<float> data2( var.data.size() );
data2.copy( var.data );
silo::writeUniformMeshVariable<3>( fid, meshname, N, var.name, data2, type );
} else if ( var.precision == IO::DataType::Int ) {
Array<int> data2( var.data.size() );
data2.copy( var.data );
silo::writeUniformMeshVariable<3>( fid, meshname, N, var.name, data2, 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, int format )
{
// Create the MeshDatabase
auto database = getDatabase( filename, mesh, format );
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 = silo::open( filename, 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 );
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 );
silo::writeMultiVar( fid, variable.name, varnames, varTypes );
}
}
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, int format )
{
int rank = MPI_WORLD_RANK();
std::vector<IO::MeshDatabase> meshes_written;
char filename[100], fullpath[200];
sprintf( filename, "%05i", rank );
sprintf( fullpath, "%s/%s", path.c_str(), filename );
FILE *fid = fopen( fullpath, "wb" );
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 );
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;
meshes_written.push_back( write_domain(fid,filename,meshData[i],format) );
}
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, int format )
{
#ifdef USE_SILO
int rank = MPI_WORLD_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 = silo::open( fullpath, 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) );
}
silo::close( fid );
return meshes_written;
#else
ERROR("Application built without silo support");
return std::vector<IO::MeshDatabase>();
#endif
}
/****************************************************
* Write the mesh data *
****************************************************/
void IO::writeData( const std::string &subdir, const std::vector<IO::MeshDataStruct> &meshData,
const Utilities::MPI &comm )
* Write the mesh data *
****************************************************/
void IO::writeData( const std::string& subdir, const std::vector<IO::MeshDataStruct>& meshData, MPI_Comm comm )
{
if ( global_IO_path.empty() )
IO::initialize();
PROFILE_START( "writeData" );
int rank = Utilities::MPI( MPI_COMM_WORLD ).getRank();
IO::initialize( );
PROFILE_START("writeData");
int rank = comm_rank(comm);
// Check the meshData before writing
for ( const auto &data : meshData )
ASSERT( data.check() );
for ( const auto& data : meshData ) {
if ( !data.check() )
ERROR("Error in meshData");
}
// Create the output directory
std::string path = global_IO_path + "/" + subdir;
recursiveMkdir( path, S_IRWXU | S_IRGRP );
if ( rank == 0 ) {
mkdir(path.c_str(),S_IRWXU|S_IRGRP);
}
MPI_Barrier(comm);
// Write the mesh files
Xdmf xmf;
std::vector<IO::MeshDatabase> meshes_written;
if ( global_IO_format == Format::OLD ) {
// Write the original triangle format
meshes_written = writeMeshesOrigFormat( meshData, path, rank );
meshes_written = writeMeshesOrigFormat( meshData, path );
} else if ( global_IO_format == Format::NEW ) {
// Write the new format (double precision)
meshes_written = writeMeshesNewFormat( meshData, path, IO::FileFormat::NEW, rank );
meshes_written = writeMeshesNewFormat( meshData, path, 2 );
} 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 );
meshes_written = writeMeshesSilo( meshData, path, 4 );
} else {
ERROR( "Unknown format" );
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 );
}
meshes_written = gatherAll(meshes_written,comm);
// Write the summary files
if ( rank == 0 ) {
// Write the summary file for the current timestep
write( meshes_written, path + "/LBM.summary" );
// Write summary file if needed
char filename[200];
sprintf(filename,"%s/LBM.summary",path.c_str());
write(meshes_written,filename);
// Write summary silo file if needed
#ifdef USE_SILO
if ( global_IO_format == Format::SILO ) {
writeSiloSummary( meshes_written, path + "/summary.silo" );
} else if ( global_IO_format == Format::HDF5 ) {
xmf.write( path + "/summary.xmf" );
sprintf(filename,"%s/summary.silo",path.c_str());
writeSiloSummary(meshes_written,filename);
}
#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";
FILE *fid = fopen( filename.c_str(), "ab" );
fprintf( fid, "%s/\n", subdir.c_str() );
fclose( fid );
auto filename = global_IO_path+"/summary.LBM";
FILE *fid = fopen(filename.c_str(),"ab");
fprintf(fid,"%s/\n",subdir.c_str());
fclose(fid);
} else if ( global_IO_format == Format::SILO ) {
auto filename = global_IO_path + "/LBM.visit";
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 );
auto filename = global_IO_path+"/LBM.visit";
FILE *fid = fopen(filename.c_str(),"ab");
fprintf(fid,"%s/summary.silo\n",subdir.c_str());
fclose(fid);
} else {
ERROR( "Unknown format" );
ERROR("Unknown format");
}
}
PROFILE_STOP( "writeData" );
PROFILE_STOP("writeData");
}

View File

@@ -29,20 +29,17 @@ namespace IO {
/*!
* @brief Initialize the writer
* @details This function initializes the writer to the given path.
* All subsequent writes will occur in this directory.
* If this is not called, then it will default to the current path.
* @details This function initializes the writer to the given path. All subsequent
* writes will occur in this directory. If this is not called, then it will default
* to the current path.
* @param[in] path The path to use for writes
* @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
* hdf5 - HDF5 + XMDF
* old - Old mesh format (provided for backward compatibility, cannot write variables)
* new - New format, 1 file/process
* silo - Silo
* @param[in] append Append any existing data (default is false)
*/
void initialize(
const std::string &path = "", const std::string &format = "hdf5", bool append = false );
void initialize( const std::string& path="", const std::string& format="silo", bool append=false );
/*!
@@ -52,8 +49,7 @@ void initialize(
* @param[in] meshData The data to write
* @param[in] comm The comm to use for writing (usually MPI_COMM_WORLD or a dup thereof)
*/
void writeData( const std::string &subdir, const std::vector<IO::MeshDataStruct> &meshData,
const Utilities::MPI &comm );
void writeData( const std::string& subdir, const std::vector<IO::MeshDataStruct>& meshData, MPI_Comm comm );
/*!
@@ -63,20 +59,14 @@ void writeData( const std::string &subdir, const std::vector<IO::MeshDataStruct>
* @param[in] meshData The data to write
* @param[in] comm The comm to use for writing (usually MPI_COMM_WORLD or a dup thereof)
*/
inline void writeData(
int timestep, const std::vector<IO::MeshDataStruct> &meshData, const Utilities::MPI &comm )
inline void writeData( int timestep, const std::vector<IO::MeshDataStruct>& meshData, MPI_Comm comm )
{
char subdir[100];
sprintf( subdir, "vis%03i", timestep );
sprintf(subdir,"vis%03i",timestep);
writeData( subdir, meshData, comm );
}
// 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
} // IO namespace
#endif

View File

@@ -1,620 +0,0 @@
#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 &center, 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
View File

@@ -1,131 +0,0 @@
#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;
};

View File

@@ -14,8 +14,8 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "IO/netcdf.h"
#include "common/MPI.h"
#include "common/Utilities.h"
#include "common/MPI_Helpers.h"
#include "ProfilerApp.h"
@@ -27,14 +27,14 @@
#include <netcdf_par.h>
#define CHECK_NC_ERR( ERR ) \
do { \
if ( ERR != NC_NOERR ) { \
#define CHECK_NC_ERR( ERR ) \
do { \
if ( ERR != NC_NOERR ) { \
std::string msg = "Error calling netcdf routine: "; \
msg += nc_strerror( ERR ); \
ERROR( msg ); \
} \
} while ( 0 )
msg += nc_strerror( ERR ); \
ERROR( msg ); \
} \
} while (0)
namespace netcdf {
@@ -65,64 +65,43 @@ static inline VariableType convertType( nc_type type )
else if ( type == NC_DOUBLE )
type2 = DOUBLE;
else
ERROR( "Unknown type" );
ERROR("Unknown type");
return type2;
}
// Get nc_type from the template
template<class T>
inline nc_type getType();
template<>
inline nc_type getType<char>()
{
return NC_CHAR;
}
template<>
inline nc_type getType<short>()
{
return NC_SHORT;
}
template<>
inline nc_type getType<int>()
{
return NC_INT;
}
template<>
inline nc_type getType<float>()
{
return NC_FLOAT;
}
template<>
inline nc_type getType<double>()
{
return NC_DOUBLE;
}
template<class T> inline nc_type getType();
template<> inline nc_type getType<char>() { return NC_CHAR; }
template<> inline nc_type getType<short>() { return NC_SHORT; }
template<> inline nc_type getType<int>() { return NC_INT; }
template<> inline nc_type getType<float>() { return NC_FLOAT; }
template<> inline nc_type getType<double>() { return NC_DOUBLE; }
// Function to reverse an array
template<class TYPE>
inline std::vector<TYPE> reverse( const std::vector<TYPE> &x )
inline std::vector<TYPE> reverse( const std::vector<TYPE>& x )
{
std::vector<TYPE> y( x.size() );
for ( size_t i = 0; i < x.size(); i++ )
y[i] = x[x.size() - i - 1];
std::vector<TYPE> y(x.size());
for (size_t i=0; i<x.size(); i++)
y[i] = x[x.size()-i-1];
return y;
}
// Function to reverse an array
template<class TYPE1, class TYPE2>
inline std::vector<TYPE2> convert( const std::vector<TYPE1> &x )
inline std::vector<TYPE2> convert( const std::vector<TYPE1>& x )
{
std::vector<TYPE2> y( x.size() );
for ( size_t i = 0; i < x.size(); i++ )
y[i] = static_cast<TYPE2>( x[i] );
std::vector<TYPE2> y(x.size());
for (size_t i=0; i<x.size(); i++)
y[i] = static_cast<TYPE2>(x[i]);
return y;
}
/****************************************************
* Convert the VariableType to a string *
****************************************************/
* Convert the VariableType to a string *
****************************************************/
std::string VariableTypeName( VariableType type )
{
if ( type == BYTE )
@@ -150,12 +129,12 @@ std::string VariableTypeName( VariableType type )
/****************************************************
* Open/close a file *
****************************************************/
int open( const std::string &filename, FileMode mode, const Utilities::MPI &comm )
* Open/close a file *
****************************************************/
int open( const std::string& filename, FileMode mode, MPI_Comm comm )
{
int fid = 0;
if ( comm.isNull() ) {
if ( comm == MPI_COMM_NULL ) {
if ( mode == READ ) {
int err = nc_open( filename.c_str(), NC_NOWRITE, &fid );
CHECK_NC_ERR( err );
@@ -163,26 +142,23 @@ int open( const std::string &filename, FileMode mode, const Utilities::MPI &comm
int err = nc_open( filename.c_str(), NC_WRITE, &fid );
CHECK_NC_ERR( err );
} else if ( mode == CREATE ) {
int err = nc_create( filename.c_str(), NC_SHARE | NC_64BIT_OFFSET, &fid );
int err = nc_create( filename.c_str(), NC_SHARE|NC_64BIT_OFFSET, &fid );
CHECK_NC_ERR( err );
} else {
ERROR( "Unknown file mode" );
ERROR("Unknown file mode");
}
} else {
if ( mode == READ ) {
int err = nc_open_par(
filename.c_str(), NC_MPIPOSIX, comm.getCommunicator(), MPI_INFO_NULL, &fid );
int err = nc_open_par( filename.c_str(), NC_MPIPOSIX, comm, MPI_INFO_NULL, &fid );
CHECK_NC_ERR( err );
} else if ( mode == WRITE ) {
int err = nc_open_par( filename.c_str(), NC_WRITE | NC_MPIPOSIX, comm.getCommunicator(),
MPI_INFO_NULL, &fid );
int err = nc_open_par( filename.c_str(), NC_WRITE|NC_MPIPOSIX, comm, MPI_INFO_NULL, &fid );
CHECK_NC_ERR( err );
} else if ( mode == CREATE ) {
int err = nc_create_par( filename.c_str(), NC_NETCDF4 | NC_MPIIO,
comm.getCommunicator(), MPI_INFO_NULL, &fid );
int err = nc_create_par( filename.c_str(), NC_NETCDF4|NC_MPIIO, comm, MPI_INFO_NULL, &fid );
CHECK_NC_ERR( err );
} else {
ERROR( "Unknown file mode" );
ERROR("Unknown file mode");
}
}
return fid;
@@ -191,44 +167,43 @@ void close( int fid )
{
int err = nc_close( fid );
if ( err != NC_NOERR )
ERROR( "Error closing file" );
ERROR("Error closing file");
}
/****************************************************
* Query basic properties *
****************************************************/
* Query basic properties *
****************************************************/
static std::vector<size_t> getDimVar( int fid, int varid )
{
int ndim = 0;
int err = nc_inq_varndims( fid, varid, &ndim );
int err = nc_inq_varndims( fid, varid, &ndim );
CHECK_NC_ERR( err );
std::vector<size_t> dims( ndim, 0 );
int dimid[64] = { -1 };
err = nc_inq_vardimid( fid, varid, dimid );
std::vector<size_t> dims(ndim,0);
int dimid[64] = {-1};
err = nc_inq_vardimid( fid, varid, dimid );
CHECK_NC_ERR( err );
for ( int i = 0; i < ndim; i++ ) {
for (int i=0; i<ndim; i++) {
err = nc_inq_dimlen( fid, dimid[i], &dims[i] );
CHECK_NC_ERR( err );
}
return dims;
}
static int getVarID( int fid, const std::string &var )
static int getVarID( int fid, const std::string& var )
{
int id = -1;
int id = -1;
int err = nc_inq_varid( fid, var.c_str(), &id );
CHECK_NC_ERR( err );
return id;
}
std::vector<size_t> getVarDim( int fid, const std::string &var )
std::vector<size_t> getVarDim( int fid, const std::string& var )
{
return getDimVar( fid, getVarID( fid, var ) );
}
std::vector<size_t> getAttDim( int fid, const std::string &att )
std::vector<size_t> getAttDim( int fid, const std::string& att )
{
std::vector<size_t> dim( 1, 0 );
std::vector<size_t> dim(1,0);
int err = nc_inq_attlen( fid, NC_GLOBAL, att.c_str(), dim.data() );
CHECK_NC_ERR( err );
return dim;
}
std::vector<std::string> getVarNames( int fid )
@@ -236,9 +211,9 @@ std::vector<std::string> getVarNames( int fid )
int nvar;
int err = nc_inq( fid, NULL, &nvar, NULL, NULL );
CHECK_NC_ERR( err );
std::vector<std::string> vars( nvar );
for ( int i = 0; i < nvar; i++ ) {
char name[NC_MAX_NAME + 1];
std::vector<std::string> vars(nvar);
for (int i=0; i<nvar; i++) {
char name[NC_MAX_NAME+1];
err = nc_inq_varname( fid, i, name );
CHECK_NC_ERR( err );
vars[i] = name;
@@ -250,269 +225,262 @@ std::vector<std::string> getAttNames( int fid )
int natt;
int err = nc_inq( fid, NULL, NULL, &natt, NULL );
CHECK_NC_ERR( err );
std::vector<std::string> att( natt );
for ( int i = 0; i < natt; i++ ) {
char name[NC_MAX_NAME + 1];
err = nc_inq_attname( fid, NC_GLOBAL, i, name );
std::vector<std::string> att(natt);
for (int i=0; i<natt; i++) {
char name[NC_MAX_NAME+1];
err = nc_inq_attname( fid, NC_GLOBAL, i, name );
CHECK_NC_ERR( err );
att[i] = name;
}
return att;
}
VariableType getVarType( int fid, const std::string &var )
VariableType getVarType( int fid, const std::string& var )
{
int varid = -1;
int err = nc_inq_varid( fid, var.c_str(), &varid );
int err = nc_inq_varid( fid, var.c_str(), &varid );
CHECK_NC_ERR( err );
nc_type type = 0;
err = nc_inq_vartype( fid, varid, &type );
nc_type type=0;
err = nc_inq_vartype( fid, varid, &type );
CHECK_NC_ERR( err );
return convertType( type );
return convertType(type);
}
VariableType getAttType( int fid, const std::string &att )
VariableType getAttType( int fid, const std::string& att )
{
nc_type type = 0;
int err = nc_inq_atttype( fid, NC_GLOBAL, att.c_str(), &type );
nc_type type=0;
int err = nc_inq_atttype( fid, NC_GLOBAL, att.c_str(), &type );
CHECK_NC_ERR( err );
return convertType( type );
return convertType(type);
}
/****************************************************
* Read a variable *
****************************************************/
* Read a variable *
****************************************************/
template<>
Array<unsigned short> getVar<unsigned short>( int fid, const std::string &var )
Array<unsigned short> getVar<unsigned short>( int fid, const std::string& var )
{
PROFILE_START( "getVar<unsigned short>" );
Array<unsigned short> x( reverse( getVarDim( fid, var ) ) );
int err = nc_get_var_ushort( fid, getVarID( fid, var ), x.data() );
PROFILE_START("getVar<unsigned short>");
Array<unsigned short> x( reverse(getVarDim(fid,var)) );
int err = nc_get_var_ushort( fid, getVarID(fid,var), x.data() );
CHECK_NC_ERR( err );
PROFILE_STOP( "getVar<unsigned short>" );
PROFILE_STOP("getVar<unsigned short>");
return x.reverseDim();
}
template<>
Array<short> getVar<short>( int fid, const std::string &var )
Array<short> getVar<short>( int fid, const std::string& var )
{
PROFILE_START( "getVar<short>" );
Array<short> x( reverse( getVarDim( fid, var ) ) );
int err = nc_get_var_short( fid, getVarID( fid, var ), x.data() );
PROFILE_START("getVar<short>");
Array<short> x( reverse(getVarDim(fid,var)) );
int err = nc_get_var_short( fid, getVarID(fid,var), x.data() );
CHECK_NC_ERR( err );
PROFILE_STOP( "getVar<short>" );
PROFILE_STOP("getVar<short>");
return x.reverseDim();
}
template<>
Array<unsigned int> getVar<unsigned int>( int fid, const std::string &var )
Array<unsigned int> getVar<unsigned int>( int fid, const std::string& var )
{
PROFILE_START( "getVar<unsigned int>" );
Array<unsigned int> x( reverse( getVarDim( fid, var ) ) );
int err = nc_get_var_uint( fid, getVarID( fid, var ), x.data() );
PROFILE_START("getVar<unsigned int>");
Array<unsigned int> x( reverse(getVarDim(fid,var)) );
int err = nc_get_var_uint( fid, getVarID(fid,var), x.data() );
CHECK_NC_ERR( err );
PROFILE_STOP( "getVar<unsigned int>" );
PROFILE_STOP("getVar<unsigned int>");
return x.reverseDim();
}
template<>
Array<int> getVar<int>( int fid, const std::string &var )
Array<int> getVar<int>( int fid, const std::string& var )
{
PROFILE_START( "getVar<int>" );
Array<int> x( reverse( getVarDim( fid, var ) ) );
int err = nc_get_var_int( fid, getVarID( fid, var ), x.data() );
PROFILE_START("getVar<int>");
Array<int> x( reverse(getVarDim(fid,var)) );
int err = nc_get_var_int( fid, getVarID(fid,var), x.data() );
CHECK_NC_ERR( err );
PROFILE_STOP( "getVar<int>" );
PROFILE_STOP("getVar<int>");
return x.reverseDim();
}
template<>
Array<float> getVar<float>( int fid, const std::string &var )
Array<float> getVar<float>( int fid, const std::string& var )
{
PROFILE_START( "getVar<float>" );
Array<float> x( reverse( getVarDim( fid, var ) ) );
int err = nc_get_var_float( fid, getVarID( fid, var ), x.data() );
PROFILE_START("getVar<float>");
Array<float> x( reverse(getVarDim(fid,var)) );
int err = nc_get_var_float( fid, getVarID(fid,var), x.data() );
CHECK_NC_ERR( err );
PROFILE_STOP( "getVar<float>" );
PROFILE_STOP("getVar<float>");
return x.reverseDim();
}
template<>
Array<double> getVar<double>( int fid, const std::string &var )
Array<double> getVar<double>( int fid, const std::string& var )
{
PROFILE_START( "getVar<double>" );
Array<double> x( reverse( getVarDim( fid, var ) ) );
int err = nc_get_var_double( fid, getVarID( fid, var ), x.data() );
PROFILE_START("getVar<double>");
Array<double> x( reverse(getVarDim(fid,var)) );
int err = nc_get_var_double( fid, getVarID(fid,var), x.data() );
CHECK_NC_ERR( err );
PROFILE_STOP( "getVar<double>" );
PROFILE_STOP("getVar<double>");
return x.reverseDim();
}
template<>
Array<char> getVar<char>( int fid, const std::string &var )
{
PROFILE_START( "getVar<char>" );
Array<char> x( reverse( getVarDim( fid, var ) ) );
int err = nc_get_var_text( fid, getVarID( fid, var ), x.data() );
Array<char> getVar<char>( int fid, const std::string& var )
{
PROFILE_START("getVar<char>");
Array<char> x( reverse(getVarDim(fid,var)) );
int err = nc_get_var_text( fid, getVarID(fid,var), x.data() );
CHECK_NC_ERR( err );
PROFILE_STOP( "getVar<char>" );
PROFILE_STOP("getVar<char>");
return x.reverseDim();
}
template<>
Array<std::string> getVar<std::string>( int fid, const std::string &var )
Array<std::string> getVar<std::string>( int fid, const std::string& var )
{
PROFILE_START( "getVar<std::string>" );
Array<char> tmp = getVar<char>( fid, var );
std::vector<size_t> dim = { tmp.size( 0 ), tmp.size( 1 ), tmp.size( 2 ) };
PROFILE_START("getVar<std::string>");
Array<char> tmp = getVar<char>( fid, var );
std::vector<size_t> dim = {tmp.size(0), tmp.size(1), tmp.size(2) };
if ( dim.size() == 1 )
dim[0] = 1;
else
dim.erase( dim.begin() );
Array<std::string> text( dim );
for ( size_t i = 0; i < text.length(); i++ )
text( i ) = &( tmp( 0, i ) );
PROFILE_STOP( "getVar<std::string>" );
Array<std::string> text(dim);
for (size_t i=0; i<text.length(); i++)
text(i) = &(tmp(0,i));
PROFILE_STOP("getVar<std::string>");
return text;
}
static inline void get_stride_args( const std::vector<int> &start, const std::vector<int> &count,
const std::vector<int> &stride, size_t *startp, size_t *countp, ptrdiff_t *stridep )
static inline void get_stride_args( const std::vector<int>& start,
const std::vector<int>& count, const std::vector<int>& stride,
size_t *startp, size_t *countp, ptrdiff_t *stridep )
{
for ( size_t i = 0; i < start.size(); i++ )
for (size_t i=0; i<start.size(); i++)
startp[i] = start[i];
for ( size_t i = 0; i < count.size(); i++ )
for (size_t i=0; i<count.size(); i++)
countp[i] = count[i];
for ( size_t i = 0; i < stride.size(); i++ )
for (size_t i=0; i<stride.size(); i++)
stridep[i] = stride[i];
}
template<class TYPE>
int nc_get_vars_TYPE( int fid, int varid, const size_t start[], const size_t count[],
const ptrdiff_t stride[], TYPE *ptr );
int nc_get_vars_TYPE( int fid, int varid, const size_t start[],
const size_t count[], const ptrdiff_t stride[], TYPE *ptr );
template<>
int nc_get_vars_TYPE<short>( int fid, int varid, const size_t start[], const size_t count[],
const ptrdiff_t stride[], short *ptr )
int nc_get_vars_TYPE<short>( int fid, int varid, const size_t start[],
const size_t count[], const ptrdiff_t stride[], short *ptr )
{
return nc_get_vars_short( fid, varid, start, count, stride, ptr );
}
template<>
int nc_get_vars_TYPE<int>( int fid, int varid, const size_t start[], const size_t count[],
const ptrdiff_t stride[], int *ptr )
int nc_get_vars_TYPE<int>( int fid, int varid, const size_t start[],
const size_t count[], const ptrdiff_t stride[], int *ptr )
{
return nc_get_vars_int( fid, varid, start, count, stride, ptr );
}
template<>
int nc_get_vars_TYPE<float>( int fid, int varid, const size_t start[], const size_t count[],
const ptrdiff_t stride[], float *ptr )
int nc_get_vars_TYPE<float>( int fid, int varid, const size_t start[],
const size_t count[], const ptrdiff_t stride[], float *ptr )
{
return nc_get_vars_float( fid, varid, start, count, stride, ptr );
}
template<>
int nc_get_vars_TYPE<double>( int fid, int varid, const size_t start[], const size_t count[],
const ptrdiff_t stride[], double *ptr )
int nc_get_vars_TYPE<double>( int fid, int varid, const size_t start[],
const size_t count[], const ptrdiff_t stride[], double *ptr )
{
return nc_get_vars_double( fid, varid, start, count, stride, ptr );
}
template<class TYPE>
Array<TYPE> getVar( int fid, const std::string &var, const std::vector<int> &start,
const std::vector<int> &count, const std::vector<int> &stride )
Array<TYPE> getVar( int fid, const std::string& var, const std::vector<int>& start,
const std::vector<int>& count, const std::vector<int>& stride )
{
PROFILE_START( "getVar<> (strided)" );
PROFILE_START("getVar<> (strided)");
std::vector<size_t> var_size = getVarDim( fid, var );
for ( int d = 0; d < (int) var_size.size(); d++ ) {
if ( start[d] < 0 || start[d] + stride[d] * ( count[d] - 1 ) > (int) var_size[d] ) {
int rank = Utilities::MPI( MPI_COMM_WORLD ).getRank();
for (int d=0; d<(int)var_size.size(); d++) {
if ( start[d]<0 || start[d]+stride[d]*(count[d]-1)>(int)var_size[d] ) {
int rank = comm_rank(MPI_COMM_WORLD);
char tmp[1000];
sprintf( tmp,
"%i: Range exceeded array dimension:\n"
sprintf(tmp,"%i: Range exceeded array dimension:\n"
" start[%i]=%i, count[%i]=%i, stride[%i]=%i, var_size[%i]=%i",
rank, d, start[d], d, count[d], d, stride[d], d, (int) var_size[d] );
ERROR( tmp );
rank,d,start[d],d,count[d],d,stride[d],d,(int)var_size[d]);
ERROR(tmp);
}
}
Array<TYPE> x( reverse( convert<int, size_t>( count ) ) );
Array<TYPE> x( reverse(convert<int,size_t>(count)) );
size_t startp[10], countp[10];
ptrdiff_t stridep[10];
get_stride_args( start, count, stride, startp, countp, stridep );
int err =
nc_get_vars_TYPE<TYPE>( fid, getVarID( fid, var ), startp, countp, stridep, x.data() );
int err = nc_get_vars_TYPE<TYPE>( fid, getVarID(fid,var), startp, countp, stridep, x.data() );
CHECK_NC_ERR( err );
PROFILE_STOP( "getVar<> (strided)" );
PROFILE_STOP("getVar<> (strided)");
return x.reverseDim();
}
template Array<short> getVar<short>( int, const std::string &, const std::vector<int> &,
const std::vector<int> &, const std::vector<int> & );
template Array<int> getVar<int>( int, const std::string &, const std::vector<int> &,
const std::vector<int> &, const std::vector<int> & );
template Array<float> getVar<float>( int, const std::string &, const std::vector<int> &,
const std::vector<int> &, const std::vector<int> & );
template Array<double> getVar<double>( int, const std::string &, const std::vector<int> &,
const std::vector<int> &, const std::vector<int> & );
template Array<short> getVar<short>( int, const std::string&, const std::vector<int>&, const std::vector<int>&, const std::vector<int>& );
template Array<int> getVar<int>( int, const std::string&, const std::vector<int>&, const std::vector<int>&, const std::vector<int>& );
template Array<float> getVar<float>( int, const std::string&, const std::vector<int>&, const std::vector<int>&, const std::vector<int>& );
template Array<double> getVar<double>( int, const std::string&, const std::vector<int>&, const std::vector<int>&, const std::vector<int>& );
/****************************************************
* Read an attribute *
****************************************************/
* Read an attribute *
****************************************************/
template<>
Array<double> getAtt<double>( int fid, const std::string &att )
Array<double> getAtt<double>( int fid, const std::string& att )
{
PROFILE_START( "getAtt<double>" );
Array<double> x( getAttDim( fid, att ) );
PROFILE_START("getAtt<double>");
Array<double> x( getAttDim(fid,att) );
int err = nc_get_att_double( fid, NC_GLOBAL, att.c_str(), x.data() );
CHECK_NC_ERR( err );
PROFILE_STOP( "getAtt<double>" );
PROFILE_STOP("getAtt<double>");
return x;
}
template<>
Array<std::string> getAtt<std::string>( int fid, const std::string &att )
Array<std::string> getAtt<std::string>( int fid, const std::string& att )
{
PROFILE_START( "getAtt<std::string>" );
char *tmp = new char[getAttDim( fid, att )[0]];
Array<std::string> x( 1 );
x( 0 ) = tmp;
delete[] tmp;
PROFILE_STOP( "getAtt<std::string>" );
PROFILE_START("getAtt<std::string>");
char *tmp = new char[getAttDim(fid,att)[0]];
Array<std::string> x(1);
x(0) = tmp;
delete [] tmp;
PROFILE_STOP("getAtt<std::string>");
return x;
}
/****************************************************
* Write an array to a file *
****************************************************/
std::vector<int> defDim(
int fid, const std::vector<std::string> &names, const std::vector<int> &dims )
* Write an array to a file *
****************************************************/
std::vector<int> defDim( int fid, const std::vector<std::string>& names, const std::vector<int>& dims )
{
std::vector<int> dimid( names.size(), 0 );
for ( size_t i = 0; i < names.size(); i++ ) {
int err = nc_def_dim( fid, names[i].c_str(), dims[i], &dimid[i] );
std::vector<int> dimid(names.size(),0);
for (size_t i=0; i<names.size(); i++) {
int err = nc_def_dim( fid, names[i].c_str(), dims[i], &dimid[i]);
CHECK_NC_ERR( err );
}
return dimid;
}
template<class TYPE>
void write( int fid, const std::string &var, const std::vector<int> &dimids,
const Array<TYPE> &data, const RankInfoStruct &info )
void write( int fid, const std::string& var, const std::vector<int>& dimids,
const Array<TYPE>& data, const RankInfoStruct& info )
{
// Define the variable
int varid = 0;
int err = nc_def_var( fid, var.c_str(), getType<TYPE>(), data.ndim(), dimids.data(), &varid );
int err = nc_def_var( fid, var.c_str(), getType<TYPE>(), data.ndim(), dimids.data(), &varid );
CHECK_NC_ERR( err );
// exit define mode
// exit define mode
err = nc_enddef( fid );
CHECK_NC_ERR( err );
// set the access method to use MPI/PnetCDF collective I/O
// set the access method to use MPI/PnetCDF collective I/O
err = nc_var_par_access( fid, varid, NC_INDEPENDENT );
CHECK_NC_ERR( err );
// parallel write: each process writes its subarray to the file
auto x = data.reverseDim();
std::vector<size_t> count = { data.size( 0 ), data.size( 1 ), data.size( 2 ) };
std::vector<size_t> start = { info.ix * data.size( 0 ), info.jy * data.size( 1 ),
info.kz * data.size( 2 ) };
auto x = data.reverseDim();
std::vector<size_t> count = { data.size(0), data.size(1), data.size(2) };
std::vector<size_t> start = { info.ix*data.size(0), info.jy*data.size(1), info.kz*data.size(2) };
nc_put_vara( fid, varid, start.data(), count.data(), x.data() );
}
template void write<short>( int fid, const std::string &var, const std::vector<int> &dimids,
const Array<short> &data, const RankInfoStruct &info );
template void write<int>( int fid, const std::string &var, const std::vector<int> &dimids,
const Array<int> &data, const RankInfoStruct &info );
template void write<float>( int fid, const std::string &var, const std::vector<int> &dimids,
const Array<float> &data, const RankInfoStruct &info );
template void write<double>( int fid, const std::string &var, const std::vector<int> &dimids,
const Array<double> &data, const RankInfoStruct &info );
template void write<short>( int fid, const std::string& var, const std::vector<int>& dimids, const Array<short>& data, const RankInfoStruct& info );
template void write<int>( int fid, const std::string& var, const std::vector<int>& dimids, const Array<int>& data, const RankInfoStruct& info );
template void write<float>( int fid, const std::string& var, const std::vector<int>& dimids, const Array<float>& data, const RankInfoStruct& info );
template void write<double>( int fid, const std::string& var, const std::vector<int>& dimids, const Array<double>& data, const RankInfoStruct& info );
} // namespace netcdf
}; // netcdf namespace
#else
#endif

View File

@@ -20,8 +20,9 @@
#include <vector>
#include "common/Array.h"
#include "common/MPI_Helpers.h"
#include "common/Communication.h"
#include "common/MPI.h"
namespace netcdf {
@@ -40,126 +41,116 @@ std::string VariableTypeName( VariableType type );
/*!
* @brief Open netcdf file
* @details This function opens a netcdf file
* @detailed This function opens a netcdf file
* @return This function returns a handle to the file
* @param filename File to open
* @param mode Open the file for reading or writing
* @param comm MPI communicator to use (MPI_COMM_WORLD: don't use parallel netcdf)
*/
int open( const std::string &filename, FileMode mode, const Utilities::MPI &comm = MPI_COMM_NULL );
*/
int open( const std::string& filename, FileMode mode, MPI_Comm comm=MPI_COMM_NULL );
/*!
* @brief Close netcdf file
* @details This function closes a netcdf file
* @detailed This function closes a netcdf file
* @param fid Handle to the open file
*/
*/
void close( int fid );
/*!
* @brief Read the variable names
* @details This function reads a list of the variable names in the file
* @detailed This function reads a list of the variable names in the file
* @param fid Handle to the open file
*/
*/
std::vector<std::string> getVarNames( int fid );
/*!
* @brief Read the attribute names
* @details This function reads a list of the attribute names in the file
* @detailed This function reads a list of the attribute names in the file
* @param fid Handle to the open file
*/
*/
std::vector<std::string> getAttNames( int fid );
/*!
* @brief Return the variable type
* @details This function returns the type for a variable
* @detailed This function returns the type for a variable
* @param fid Handle to the open file
* @param var Variable to read
*/
VariableType getVarType( int fid, const std::string &var );
*/
VariableType getVarType( int fid, const std::string& var );
/*!
* @brief Return the attribute type
* @details This function returns the type for an attribute
* @detailed This function returns the type for an attribute
* @param fid Handle to the open file
* @param att Attribute to read
*/
VariableType getAttType( int fid, const std::string &att );
*/
VariableType getAttType( int fid, const std::string& att );
/*!
* @brief Return the variable dimensions
* @details This function returns the die for a variable
* @detailed This function returns the die for a variable
* @param fid Handle to the open file
* @param var Variable to read
*/
std::vector<size_t> getVarDim( int fid, const std::string &var );
*/
std::vector<size_t> getVarDim( int fid, const std::string& var );
/*!
* @brief Read a variable
* @details This function reads a variable with the given name from the file
* @detailed This function reads a variable with the given name from the file
* @param fid Handle to the open file
* @param var Variable to read
*/
*/
template<class TYPE>
Array<TYPE> getVar( int fid, const std::string &var );
Array<TYPE> getVar( int fid, const std::string& var );
/*!
* @brief Read a strided variable
* @details This function reads a strided variable with the given name from the file
* @detailed This function reads a strided variable with the given name from the file
* @param fid Handle to the open file
* @param var Variable to read
* @param start Starting corner for the read
* @param count Number of elements to read
* @param stride Stride size for the read
*/
*/
template<class TYPE>
Array<TYPE> getVar( int fid, const std::string &var, const std::vector<int> &start,
const std::vector<int> &count, const std::vector<int> &stride );
Array<TYPE> getVar( int fid, const std::string& var, const std::vector<int>& start,
const std::vector<int>& count, const std::vector<int>& stride );
/*!
* @brief Read an attribute
* @details This function reads an attribute with the given name from the file
* @detailed This function reads an attribute with the given name from the file
* @param fid Handle to the open file
* @param att Attribute to read
*/
*/
template<class TYPE>
Array<TYPE> getAtt( int fid, const std::string &att );
Array<TYPE> getAtt( int fid, const std::string& att );
/*!
* @brief Write the dimensions
* @details This function writes the grid dimensions to netcdf.
* @detailed 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 );
*/
std::vector<int> defDim( int fid, const std::vector<std::string>& names, const std::vector<int>& dims );
/*!
* @brief Write a variable
* @details This function writes a variable to netcdf.
* @detailed 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
void write( int fid, const std::string& var, const std::vector<int>& dimids, const Array<TYPE>& data, const RankInfoStruct& rank_info );
}; // netcdf namespace
#endif

View File

@@ -14,8 +14,8 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include "IO/silo.h"
#include "common/MPI.h"
#include "common/Utilities.h"
#include "common/MPI_Helpers.h"
#include "ProfilerApp.h"
@@ -25,14 +25,14 @@
#include <silo.h>
namespace IO {
namespace silo {
/****************************************************
* Open/close a file *
****************************************************/
DBfile *open( const std::string &filename, FileMode mode )
* Open/close a file *
****************************************************/
DBfile* open( const std::string& filename, FileMode mode )
{
DBfile *fid = nullptr;
if ( mode == CREATE ) {
@@ -44,79 +44,82 @@ DBfile *open( const std::string &filename, FileMode mode )
}
return fid;
}
void close( DBfile *fid ) { DBClose( fid ); }
void close( DBfile* fid )
{
DBClose( fid );
}
/****************************************************
* Helper functions *
****************************************************/
DataType varDataType( DBfile *fid, const std::string &name )
* Helper functions *
****************************************************/
VariableDataType varDataType( DBfile *fid, const std::string& name )
{
auto type = DBGetVarType( fid, name.c_str() );
DataType type2 = DataType::Null;
auto type = DBGetVarType( fid, name.c_str() );
VariableDataType type2 = VariableDataType::UNKNOWN;
if ( type == DB_DOUBLE )
type2 = DataType::Double;
type2 = VariableDataType::DOUBLE;
else if ( type == DB_FLOAT )
type2 = DataType::Float;
type2 = VariableDataType::FLOAT;
else if ( type == DB_INT )
type2 = DataType::Int;
type2 = VariableDataType::INT;
return type2;
}
/****************************************************
* Write/read a uniform mesh to silo *
****************************************************/
void readUniformMesh(
DBfile *fid, const std::string &meshname, std::vector<double> &range, std::vector<int> &N )
* Write/read a uniform mesh to silo *
****************************************************/
void readUniformMesh( DBfile* fid, const std::string& meshname,
std::vector<double>& range, std::vector<int>& N )
{
DBquadmesh *mesh = DBGetQuadmesh( fid, meshname.c_str() );
int ndim = mesh->ndims;
range.resize( 2 * ndim );
N.resize( ndim );
for ( int d = 0; d < ndim; d++ ) {
N[d] = mesh->dims[d] - 1;
range[2 * d + 0] = mesh->min_extents[d];
range[2 * d + 1] = mesh->max_extents[d];
DBquadmesh* mesh = DBGetQuadmesh( fid, meshname.c_str() );
int ndim = mesh->ndims;
range.resize(2*ndim);
N.resize(ndim);
for (int d=0; d<ndim; d++) {
N[d] = mesh->dims[d]-1;
range[2*d+0] = mesh->min_extents[d];
range[2*d+1] = mesh->max_extents[d];
}
DBFreeQuadmesh( mesh );
}
/****************************************************
* Write a multimesh *
****************************************************/
void writeMultiMesh( DBfile *fid, const std::string &meshname,
const std::vector<std::string> &meshNames, const std::vector<int> &meshTypes )
* Write a multimesh *
****************************************************/
void writeMultiMesh( DBfile* fid, const std::string& meshname,
const std::vector<std::string>& meshNames,
const std::vector<int>& meshTypes )
{
std::vector<char *> meshnames( meshNames.size() );
std::vector<char*> meshnames(meshNames.size());
for ( size_t i = 0; i < meshNames.size(); ++i )
meshnames[i] = (char *) meshNames[i].c_str();
std::string tree_name = meshname + "_tree";
DBoptlist *optList = DBMakeOptlist( 1 );
DBAddOption( optList, DBOPT_MRGTREE_NAME, (char *) tree_name.c_str() );
DBPutMultimesh( fid, meshname.c_str(), meshNames.size(), meshnames.data(),
(int *) meshTypes.data(), nullptr );
DBPutMultimesh( fid, meshname.c_str(), meshNames.size(), meshnames.data(), (int*) meshTypes.data(), nullptr );
DBFreeOptlist( optList );
}
/****************************************************
* Write a multivariable *
****************************************************/
void writeMultiVar( DBfile *fid, const std::string &varname,
const std::vector<std::string> &varNames, const std::vector<int> &varTypes )
* Write a multivariable *
****************************************************/
void writeMultiVar( DBfile* fid, const std::string& varname,
const std::vector<std::string>& varNames,
const std::vector<int>& varTypes )
{
std::vector<char *> varnames( varNames.size(), nullptr );
for ( size_t j = 0; j < varNames.size(); j++ )
varnames[j] = const_cast<char *>( varNames[j].c_str() );
DBPutMultivar(
fid, varname.c_str(), varNames.size(), varnames.data(), (int *) varTypes.data(), nullptr );
std::vector<char*> varnames(varNames.size(),nullptr);
for (size_t j=0; j<varNames.size(); j++)
varnames[j] = const_cast<char*>(varNames[j].c_str());
DBPutMultivar( fid, varname.c_str(), varNames.size(), varnames.data(), (int*) varTypes.data(), nullptr );
}
} // namespace silo
} // namespace IO
}; // silo namespace
#else

162
IO/silo.h
View File

@@ -16,183 +16,185 @@
#ifndef SILO_INTERFACE
#define SILO_INTERFACE
#include <array>
#include <string>
#include <vector>
#include <array>
#include "IO/Mesh.h"
#include "common/Array.h"
#include "common/MPI_Helpers.h"
#include "common/Communication.h"
#include "common/MPI.h"
#ifdef USE_SILO
#include <silo.h>
#include <silo.h>
#else
typedef int DBfile;
typedef int DBfile;
#endif
namespace IO {
namespace silo {
enum FileMode { READ, WRITE, CREATE };
enum class VariableType : int { NodeVariable=1, EdgeVariable=2, SurfaceVariable=2, VolumeVariable=3, NullVariable=0 };
enum class VariableDataType { DOUBLE, FLOAT, INT, UNKNOWN };
/*!
* @brief Open silo file
* @details This function opens a silo file
* @detailed This function opens a silo file
* @param[in] filename File to open
* @param[in] mode Open the file for reading or writing
* @return This function returns a handle to the file
*/
DBfile *open( const std::string &filename, FileMode mode );
*/
DBfile* open( const std::string& filename, FileMode mode );
/*!
* @brief Close silo file
* @details This function closes a silo file
* @detailed This function closes a silo file
* @param[in] fid Handle to the open file
*/
void close( DBfile *fid );
*/
void close( DBfile* fid );
/*!
* @brief Get the variable type
* @details This function returns the type of variable data
* @detailed This function returns the type of variable data
* @param[in] fid Handle to the open file
* @param[in] name Name of variable
*/
DataType varDataType( DBfile *fid, const std::string &name );
*/
VariableDataType varDataType( DBfile *dbfile, const std::string& name );
/*!
* @brief Write data to silo
* @details This function writes an arbitrary array to silo
* @detailed This function writes an arbitrary array to silo
* @param[in] fid Handle to the open file
* @param[in] varname Variable name
* @param[in] data Data to write
*/
*/
template<class TYPE>
void write( DBfile *fid, const std::string &varname, const std::vector<TYPE> &data );
void write( DBfile* fid, const std::string& varname, const std::vector<TYPE>& data );
/*!
* @brief Write data to silo
* @details This function writes an arbitrary array to silo
* @detailed This function writes an arbitrary array to silo
* @param[in] fid Handle to the open file
* @param[in] varname Variable name
* @return Data read
*/
*/
template<class TYPE>
std::vector<TYPE> read( DBfile *fid, const std::string &varname );
std::vector<TYPE> read( DBfile* fid, const std::string& varname );
/*!
* @brief Write a uniform grid
* @details This function writes a uniform grid to silo as a Quadmesh
* @detailed This function writes a uniform grid to silo as a Quadmesh
* @param[in] fid Handle to the open file
* @param[in] meshname Mesh name
* @param[in] range Range of mesh { xmin, xmax, ymin, ymax, zmin, zmax }
* @param[in] N Number of cells in each direction
*/
*/
template<int NDIM>
void writeUniformMesh( DBfile *fid, const std::string &meshname,
const std::array<double, 2 * NDIM> &range, const std::array<int, NDIM> &N );
void writeUniformMesh( DBfile* fid, const std::string& meshname,
const std::array<double,2*NDIM>& range, const std::array<int,NDIM>& N );
/*!
* @brief Read a uniform grid
* @details This function reads a uniform grid from silo
* @detailed This function reads a uniform grid from silo
* @param[in] fid Handle to the open file
* @param[in] meshname Mesh name
* @param[out] range Range of mesh { xmin, xmax, ymin, ymax, zmin, zmax }
* @param[out] N Number of cells in each direction
*/
void readUniformMesh(
DBfile *fid, const std::string &meshname, std::vector<double> &range, std::vector<int> &N );
*/
void readUniformMesh( DBfile* fid, const std::string& meshname,
std::vector<double>& range, std::vector<int>& N );
/*!
* @brief Write a uniform grid variable
* @details This function writes a uniform grid variable to silo as a Quadmesh
* @detailed This function writes a uniform grid variable to silo as a Quadmesh
* @param[in] fid Handle to the open file
* @param[in] meshname Mesh name
* @param[in] N Number of cells in each direction
* @param[in] varname Variable name
* @param[in] data Variable data
* @param[in] type Variable type
*/
template<int NDIM, class TYPE>
void writeUniformMeshVariable( DBfile *fid, const std::string &meshname,
const std::array<int, NDIM> &N, const std::string &varname, const Array<TYPE> &data,
VariableType type );
*/
template< int NDIM, class TYPE >
void writeUniformMeshVariable( DBfile* fid, const std::string& meshname, const std::array<int,NDIM>& N,
const std::string& varname, const Array<TYPE>& data, VariableType type );
/*!
* @brief Read a uniform mesh grid variable
* @details This function read a uniform mesh variable to silo
* @detailed This function read a uniform mesh variable to silo
* @param[in] fid Handle to the open file
* @param[in] varname Variable name
* @return Variable data
*/
*/
template<class TYPE>
Array<TYPE> readUniformMeshVariable( DBfile *fid, const std::string &varname );
Array<TYPE> readUniformMeshVariable( DBfile* fid, const std::string& varname );
/*!
* @brief Write a pointmesh
* @details This function writes a pointmesh to silo
* @detailed This function writes a pointmesh to silo
* @param[in] fid Handle to the open file
* @param[in] meshname Mesh name
* @param[in] ndim Number of dimensions
* @param[in] N Number of points
* @param[in] coords Coordinates of the points
*/
*/
template<class TYPE>
void writePointMesh(
DBfile *fid, const std::string &meshname, int ndim, int N, const TYPE *coords[] );
void writePointMesh( DBfile* fid, const std::string& meshname,
int ndim, int N, const TYPE *coords[] );
/*!
* @brief Read a pointmesh
* @details This function reads a pointmesh from silo
* @detailed This function reads a pointmesh from silo
* @param[in] fid Handle to the open file
* @param[in] meshname Mesh name
* @return Returns the coordinates as a N x ndim array
*/
* @return Returns the coordinates as a N x ndim array
*/
template<class TYPE>
Array<TYPE> readPointMesh( DBfile *fid, const std::string &meshname );
Array<TYPE> readPointMesh( DBfile* fid, const std::string& meshname );
/*!
* @brief Write a pointmesh grid variable
* @details This function writes a pointmesh variable to silo
* @detailed This function writes a pointmesh variable to silo
* @param[in] fid Handle to the open file
* @param[in] meshname Mesh name
* @param[in] varname Variable name
* @param[in] data Variable data
*/
*/
template<class TYPE>
void writePointMeshVariable(
DBfile *fid, const std::string &meshname, const std::string &varname, const Array<TYPE> &data );
void writePointMeshVariable( DBfile* fid, const std::string& meshname,
const std::string& varname, const Array<TYPE>& data );
/*!
* @brief Read a pointmesh grid variable
* @details This function reads a pointmesh variable from silo
* @detailed This function reads a pointmesh variable from silo
* @param[in] fid Handle to the open file
* @param[in] varname Variable name
* @return Variable data
*/
*/
template<class TYPE>
Array<TYPE> readPointMeshVariable( DBfile *fid, const std::string &varname );
Array<TYPE> readPointMeshVariable( DBfile* fid, const std::string& varname );
/*!
* @brief Write a triangle mesh
* @details This function writes a triangle (or simplex) based mesh to silo
* @detailed This function writes a triangle (or simplex) based mesh to silo
* @param[in] fid Handle to the open file
* @param[in] meshname Mesh name
* @param[in] ndim Number of dimensions for the coordinates
@@ -201,78 +203,80 @@ Array<TYPE> readPointMeshVariable( DBfile *fid, const std::string &varname );
* @param[in] coords Coordinates of the points
* @param[in] N_tri Number of triangles
* @param[in] tri Coordinates of the points
*/
*/
template<class TYPE>
void writeTriMesh( DBfile *fid, const std::string &meshname, int ndim, int ndim_tri, int N,
const TYPE *coords[], int N_tri, const int *tri[] );
void writeTriMesh( DBfile* fid, const std::string& meshname,
int ndim, int ndim_tri, int N, const TYPE *coords[], int N_tri, const int *tri[] );
/*!
* @brief Read a triangle mesh
* @details This function reads a triangle (or simplex) based mesh to silo
* @detailed This function reads a triangle (or simplex) based mesh to silo
* @param[in] fid Handle to the open file
* @param[in] meshname Mesh name
* @param[in] coords Coordinates of the points
* @param[in] tri Coordinates of the points
*/
*/
template<class TYPE>
void readTriMesh( DBfile *fid, const std::string &meshname, Array<TYPE> &coords, Array<int> &tri );
void readTriMesh( DBfile* fid, const std::string& meshname, Array<TYPE>& coords, Array<int>& tri );
/*!
* @brief Write a triangle mesh grid variable
* @details This function writes a triangle mesh variable to silo
* @detailed This function writes a triangle mesh variable to silo
* @param[in] fid Handle to the open file
* @param[in] ndim Number of dimensions
* @param[in] meshname Mesh name
* @param[in] varname Variable name
* @param[in] data Variable data
* @param[in] type Variable type
*/
*/
template<class TYPE>
void writeTriMeshVariable( DBfile *fid, int ndim, const std::string &meshname,
const std::string &varname, const Array<TYPE> &data, VariableType type );
void writeTriMeshVariable( DBfile* fid, int ndim, const std::string& meshname,
const std::string& varname, const Array<TYPE>& data, VariableType type );
/*!
* @brief Read a triangle mesh grid variable
* @details This function read a triangle mesh variable to silo
* @detailed This function read a triangle mesh variable to silo
* @param[in] fid Handle to the open file
* @param[in] varname Variable name
* @return Variable data
*/
*/
template<class TYPE>
Array<TYPE> readTriMeshVariable( DBfile *fid, const std::string &varname );
Array<TYPE> readTriMeshVariable( DBfile* fid, const std::string& varname );
/*!
* @brief Write a multimesh
* @details This function writes a multimesh to silo
* @detailed This function writes a multimesh to silo
* @param[in] fid Handle to the open file
* @param[in] meshname Mesh name
* @param[in] subMeshNames Names of the sub meshes in the form "filename:meshname"
* @param[in] subMeshTypes Type of each submesh
*/
void writeMultiMesh( DBfile *fid, const std::string &meshname,
const std::vector<std::string> &subMeshNames, const std::vector<int> &subMeshTypes );
*/
void writeMultiMesh( DBfile* fid, const std::string& meshname,
const std::vector<std::string>& subMeshNames,
const std::vector<int>& subMeshTypes );
/*!
* @brief Write a multivariable
* @details This function writes a multivariable to silo
* @detailed This function writes a multivariable to silo
* @return This function returns a handle to the file
* @param[in] fid Handle to the open file
* @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
*/
void writeMultiVar( DBfile *fid, const std::string &varname,
const std::vector<std::string> &subVarNames, const std::vector<int> &subVarTypes );
* @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 );
} // namespace silo
} // namespace IO
}; // silo namespace
#endif
#include "IO/silo.hpp"

View File

@@ -32,8 +32,8 @@
#define SILO_INTERFACE_HPP
#include "IO/silo.h"
#include "common/MPI.h"
#include "common/Utilities.h"
#include "common/MPI_Helpers.h"
#include "ProfilerApp.h"
@@ -43,78 +43,52 @@
#include <silo.h>
namespace IO {
namespace silo {
/****************************************************
* Helper functions *
****************************************************/
* Helper functions *
****************************************************/
template<class TYPE> static constexpr int getType();
template<> constexpr int getType<double>() { return DB_DOUBLE; }
template<> constexpr int getType<float>() { return DB_FLOAT; }
template<> constexpr int getType<int>() { return DB_INT; }
template<class TYPE>
static constexpr int getType();
template<>
constexpr int getType<double>()
{
return DB_DOUBLE;
}
template<>
constexpr int getType<float>()
{
return DB_FLOAT;
}
template<>
constexpr int getType<int>()
{
return DB_INT;
}
template<class TYPE>
inline void copyData( Array<TYPE> &data, int type, const void *src )
inline void copyData( Array<TYPE>& data, int type, const void *src )
{
if ( type == getType<TYPE>() )
memcpy( data.data(), src, data.length() * sizeof( TYPE ) );
memcpy( data.data(), src, data.length()*sizeof(TYPE) );
else if ( type == DB_DOUBLE )
data.copy( static_cast<const double *>( src ) );
data.copy( static_cast<const double*>(src) );
else if ( type == DB_FLOAT )
data.copy( static_cast<const float *>( src ) );
data.copy( static_cast<const float*>(src) );
else if ( type == DB_INT )
data.copy( static_cast<const int *>( src ) );
data.copy( static_cast<const int*>(src) );
else
ERROR( "Unknown type" );
ERROR("Unknown type");
}
/****************************************************
* Write/read an arbitrary vector *
****************************************************/
* Write/read an arbitrary vector *
****************************************************/
template<class TYPE> constexpr int getSiloType();
template<> constexpr int getSiloType<int>() { return DB_INT; }
template<> constexpr int getSiloType<float>() { return DB_FLOAT; }
template<> constexpr int getSiloType<double>() { return DB_DOUBLE; }
template<class TYPE>
constexpr int getSiloType();
template<>
constexpr int getSiloType<int>()
{
return DB_INT;
}
template<>
constexpr int getSiloType<float>()
{
return DB_FLOAT;
}
template<>
constexpr int getSiloType<double>()
{
return DB_DOUBLE;
}
template<class TYPE>
void write( DBfile *fid, const std::string &varname, const std::vector<TYPE> &data )
void write( DBfile* fid, const std::string& varname, const std::vector<TYPE>& data )
{
int dims = data.size();
int err = DBWrite( fid, varname.c_str(), (void *) data.data(), &dims, 1, getSiloType<TYPE>() );
int err = DBWrite( fid, varname.c_str(), (void*) data.data(), &dims, 1, getSiloType<TYPE>() );
ASSERT( err == 0 );
}
template<class TYPE>
std::vector<TYPE> read( DBfile *fid, const std::string &varname )
std::vector<TYPE> read( DBfile* fid, const std::string& varname )
{
int N = DBGetVarLength( fid, varname.c_str() );
std::vector<TYPE> data( N );
std::vector<TYPE> data(N);
int err = DBReadVar( fid, varname.c_str(), data.data() );
ASSERT( err == 0 );
return data;
@@ -122,31 +96,31 @@ std::vector<TYPE> read( DBfile *fid, const std::string &varname )
/****************************************************
* Helper function to get variable suffixes *
****************************************************/
* Helper function to get variable suffixes *
****************************************************/
inline std::vector<std::string> getVarSuffix( int ndim, int nvars )
{
std::vector<std::string> suffix( nvars );
std::vector<std::string> suffix(nvars);
if ( nvars == 1 ) {
suffix[0] = "";
} else if ( nvars == ndim ) {
if ( ndim == 2 ) {
if ( ndim==2 ) {
suffix[0] = "_x";
suffix[1] = "_y";
} else if ( ndim == 3 ) {
} else if ( ndim==3 ) {
suffix[0] = "_x";
suffix[1] = "_y";
suffix[2] = "_z";
} else {
ERROR( "Not finished" );
ERROR("Not finished");
}
} else if ( nvars == ndim * ndim ) {
if ( ndim == 2 ) {
} else if ( nvars == ndim*ndim ) {
if ( ndim==2 ) {
suffix[0] = "_xx";
suffix[1] = "_xy";
suffix[2] = "_yx";
suffix[3] = "_yy";
} else if ( ndim == 3 ) {
} else if ( ndim==3 ) {
suffix[0] = "_xx";
suffix[1] = "_xy";
suffix[2] = "_xz";
@@ -157,183 +131,177 @@ inline std::vector<std::string> getVarSuffix( int ndim, int nvars )
suffix[7] = "_zy";
suffix[8] = "_zz";
} else {
ERROR( "Not finished" );
ERROR("Not finished");
}
} else {
for ( int i = 0; i < nvars; i++ )
suffix[i] = "_" + std::to_string( i + 1 );
for (int i=0; i<nvars; i++)
suffix[i] = "_" + std::to_string(i+1);
}
return suffix;
}
/****************************************************
* Write/read a uniform mesh to silo *
****************************************************/
* Write/read a uniform mesh to silo *
****************************************************/
template<int NDIM>
void writeUniformMesh( DBfile *fid, const std::string &meshname,
const std::array<double, 2 * NDIM> &range, const std::array<int, NDIM> &N )
void writeUniformMesh( DBfile* fid, const std::string& meshname,
const std::array<double,2*NDIM>& range, const std::array<int,NDIM>& N )
{
PROFILE_START( "writeUniformMesh", 2 );
PROFILE_START("writeUniformMesh",2);
int dims[NDIM];
for ( size_t d = 0; d < N.size(); d++ )
dims[d] = N[d] + 1;
for (size_t d=0; d<N.size(); d++)
dims[d] = N[d]+1;
float *x = nullptr;
if ( NDIM >= 1 ) {
x = new float[dims[0]];
for ( int i = 0; i < N[0]; i++ )
x[i] = range[0] + i * ( range[1] - range[0] ) / N[0];
for (int i=0; i<N[0]; i++)
x[i] = range[0] + i*(range[1]-range[0])/N[0];
x[N[0]] = range[1];
}
float *y = nullptr;
if ( NDIM >= 2 ) {
y = new float[dims[1]];
for ( int i = 0; i < N[1]; i++ )
y[i] = range[2] + i * ( range[3] - range[2] ) / N[1];
for (int i=0; i<N[1]; i++)
y[i] = range[2] + i*(range[3]-range[2])/N[1];
y[N[1]] = range[3];
}
float *z = nullptr;
if ( NDIM >= 3 ) {
z = new float[dims[2]];
for ( int i = 0; i < N[2]; i++ )
z[i] = range[4] + i * ( range[5] - range[4] ) / N[2];
for (int i=0; i<N[2]; i++)
z[i] = range[4] + i*(range[5]-range[4])/N[2];
z[N[2]] = range[5];
}
float *coords[] = { x, y, z };
int err = DBPutQuadmesh(
fid, meshname.c_str(), nullptr, coords, dims, NDIM, DB_FLOAT, DB_COLLINEAR, nullptr );
delete[] x;
delete[] y;
delete[] z;
int err = DBPutQuadmesh( fid, meshname.c_str(), nullptr, coords, dims, NDIM, DB_FLOAT, DB_COLLINEAR, nullptr );
ASSERT( err == 0 );
PROFILE_STOP( "writeUniformMesh", 2 );
PROFILE_STOP("writeUniformMesh",2);
}
/****************************************************
* Write a vector/tensor quad variable *
****************************************************/
template<int NDIM, class TYPE>
void writeUniformMeshVariable( DBfile *fid, const std::string &meshname,
const std::array<int, NDIM> &N, const std::string &varname, const Array<TYPE> &data,
VariableType type )
* Write a vector/tensor quad variable *
****************************************************/
template<int NDIM,class TYPE>
void writeUniformMeshVariable( DBfile* fid, const std::string& meshname, const std::array<int,NDIM>& N,
const std::string& varname, const Array<TYPE>& data, VariableType type )
{
PROFILE_START( "writeUniformMeshVariable", 2 );
int nvars = 1, dims[NDIM] = { 1 };
PROFILE_START("writeUniformMeshVariable",2);
int nvars=1, dims[NDIM]={1};
const TYPE *vars[NDIM] = { nullptr };
int vartype = 0;
int vartype = 0;
if ( type == VariableType::NodeVariable ) {
ASSERT( data.ndim() == NDIM || data.ndim() == NDIM + 1 );
for ( int d = 0; d < NDIM; d++ )
ASSERT( N[d] + 1 == (int) data.size( d ) );
vartype = DB_NODECENT;
nvars = data.size( NDIM );
size_t N = data.length() / nvars;
for ( int d = 0; d < NDIM; d++ )
dims[d] = data.size( d );
for ( int i = 0; i < nvars; i++ )
vars[i] = &data( i * N );
ASSERT( data.ndim()==NDIM || data.ndim()==NDIM+1 );
for (int d=0; d<NDIM; d++)
ASSERT(N[d]+1==(int)data.size(d));
vartype = DB_NODECENT;
nvars = data.size(NDIM);
size_t N = data.length()/nvars;
for (int d=0; d<NDIM; d++)
dims[d] = data.size(d);
for (int i=0; i<nvars; i++)
vars[i] = &data(i*N);
} else if ( type == VariableType::EdgeVariable ) {
ERROR( "Not finished" );
ERROR("Not finished");
} else if ( type == VariableType::SurfaceVariable ) {
ERROR( "Not finished" );
ERROR("Not finished");
} else if ( type == VariableType::VolumeVariable ) {
ASSERT( data.ndim() == NDIM || data.ndim() == NDIM + 1 );
for ( int d = 0; d < NDIM; d++ )
ASSERT( N[d] == (int) data.size( d ) );
vartype = DB_ZONECENT;
nvars = data.size( NDIM );
size_t N = data.length() / nvars;
for ( int d = 0; d < NDIM; d++ )
dims[d] = data.size( d );
for ( int i = 0; i < nvars; i++ )
vars[i] = &data( i * N );
ASSERT( data.ndim()==NDIM || data.ndim()==NDIM+1 );
for (int d=0; d<NDIM; d++)
ASSERT(N[d]==(int)data.size(d));
vartype = DB_ZONECENT;
nvars = data.size(NDIM);
size_t N = data.length()/nvars;
for (int d=0; d<NDIM; d++)
dims[d] = data.size(d);
for (int i=0; i<nvars; i++)
vars[i] = &data(i*N);
} else {
ERROR( "Invalid variable type" );
ERROR("Invalid variable type");
}
auto suffix = getVarSuffix( NDIM, nvars );
std::vector<std::string> var_names( nvars );
for ( int i = 0; i < nvars; i++ )
std::vector<std::string> var_names(nvars);
for (int i=0; i<nvars; i++)
var_names[i] = varname + suffix[i];
std::vector<char *> varnames( nvars, nullptr );
for ( int i = 0; i < nvars; i++ )
varnames[i] = const_cast<char *>( var_names[i].c_str() );
int err = DBPutQuadvar( fid, varname.c_str(), meshname.c_str(), nvars, varnames.data(), vars,
dims, NDIM, nullptr, 0, getType<TYPE>(), vartype, nullptr );
std::vector<char*> varnames(nvars,nullptr);
for (int i=0; i<nvars; i++)
varnames[i] = const_cast<char*>(var_names[i].c_str());
int err = DBPutQuadvar( fid, varname.c_str(), meshname.c_str(), nvars,
varnames.data(), vars, dims, NDIM, nullptr, 0, getType<TYPE>(), vartype, nullptr );
ASSERT( err == 0 );
PROFILE_STOP( "writeUniformMeshVariable", 2 );
PROFILE_STOP("writeUniformMeshVariable",2);
}
template<class TYPE>
Array<TYPE> readUniformMeshVariable( DBfile *fid, const std::string &varname )
template<class TYPE>
Array<TYPE> readUniformMeshVariable( DBfile* fid, const std::string& varname )
{
auto var = DBGetQuadvar( fid, varname.c_str() );
ASSERT( var != nullptr );
Array<TYPE> data( var->nels, var->nvals );
int type = var->datatype;
for ( int i = 0; i < var->nvals; i++ ) {
for (int i=0; i<var->nvals; i++) {
Array<TYPE> data2( var->nels );
copyData<TYPE>( data2, type, var->vals[i] );
memcpy( &data( 0, i ), data2.data(), var->nels * sizeof( TYPE ) );
memcpy( &data(0,i), data2.data(), var->nels*sizeof(TYPE) );
}
std::vector<size_t> dims( var->ndims + 1, var->nvals );
for ( int d = 0; d < var->ndims; d++ )
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;
}
/****************************************************
* Read/write a point mesh/variable to silo *
****************************************************/
* Read/write a point mesh/variable to silo *
****************************************************/
template<class TYPE>
void writePointMesh(
DBfile *fid, const std::string &meshname, int ndim, int N, const TYPE *coords[] )
void writePointMesh( DBfile* fid, const std::string& meshname,
int ndim, int N, const TYPE *coords[] )
{
int err = DBPutPointmesh( fid, meshname.c_str(), ndim, coords, N, getType<TYPE>(), nullptr );
ASSERT( err == 0 );
}
template<class TYPE>
Array<TYPE> readPointMesh( DBfile *fid, const std::string &meshname )
template<class TYPE>
Array<TYPE> readPointMesh( DBfile* fid, const std::string& meshname )
{
auto mesh = DBGetPointmesh( fid, meshname.c_str() );
int N = mesh->nels;
int ndim = mesh->ndims;
Array<TYPE> coords( N, ndim );
int N = mesh->nels;
int ndim = mesh->ndims;
Array<TYPE> coords(N,ndim);
int type = mesh->datatype;
for ( int d = 0; d < ndim; d++ ) {
for (int d=0; d<ndim; d++) {
Array<TYPE> data2( N );
copyData<TYPE>( data2, type, mesh->coords[d] );
memcpy( &coords( 0, d ), data2.data(), N * sizeof( TYPE ) );
memcpy( &coords(0,d), data2.data(), N*sizeof(TYPE) );
}
DBFreePointmesh( mesh );
return coords;
}
template<class TYPE>
void writePointMeshVariable(
DBfile *fid, const std::string &meshname, const std::string &varname, const Array<TYPE> &data )
void writePointMeshVariable( DBfile* fid, const std::string& meshname,
const std::string& varname, const Array<TYPE>& data )
{
int N = data.size( 0 );
int nvars = data.size( 1 );
std::vector<const TYPE *> vars( nvars );
for ( int i = 0; i < nvars; i++ )
vars[i] = &data( 0, i );
int err = DBPutPointvar(
fid, varname.c_str(), meshname.c_str(), nvars, vars.data(), N, getType<TYPE>(), nullptr );
int N = data.size(0);
int nvars = data.size(1);
std::vector<const TYPE*> vars(nvars);
for (int i=0; i<nvars; i++)
vars[i] = &data(0,i);
int err = DBPutPointvar( fid, varname.c_str(), meshname.c_str(), nvars, vars.data(), N, getType<TYPE>(), nullptr );
ASSERT( err == 0 );
}
template<class TYPE>
Array<TYPE> readPointMeshVariable( DBfile *fid, const std::string &varname )
template<class TYPE>
Array<TYPE> readPointMeshVariable( DBfile* fid, const std::string& varname )
{
auto var = DBGetPointvar( fid, varname.c_str() );
ASSERT( var != nullptr );
Array<TYPE> data( var->nels, var->nvals );
int type = var->datatype;
for ( int i = 0; i < var->nvals; i++ ) {
for (int i=0; i<var->nvals; i++) {
Array<TYPE> data2( var->nels );
copyData<TYPE>( data2, type, var->vals[i] );
memcpy( &data( 0, i ), data2.data(), var->nels * sizeof( TYPE ) );
memcpy( &data(0,i), data2.data(), var->nels*sizeof(TYPE) );
}
DBFreeMeshvar( var );
return data;
@@ -341,111 +309,110 @@ Array<TYPE> readPointMeshVariable( DBfile *fid, const std::string &varname )
/****************************************************
* Read/write a triangle mesh *
****************************************************/
* Read/write a triangle mesh *
****************************************************/
template<class TYPE>
void writeTriMesh( DBfile *fid, const std::string &meshName, int ndim, int ndim_tri, int N,
const TYPE *coords[], int N_tri, const int *tri[] )
void writeTriMesh( DBfile* fid, const std::string& meshName,
int ndim, int ndim_tri, int N, const TYPE *coords[], int N_tri, const int *tri[] )
{
auto zoneName = meshName + "_zones";
std::vector<int> nodelist( ( ndim_tri + 1 ) * N_tri );
for ( int i = 0, j = 0; i < N_tri; i++ ) {
for ( int d = 0; d < ndim_tri + 1; d++, j++ )
std::vector<int> nodelist( (ndim_tri+1)*N_tri );
for (int i=0, j=0; i<N_tri; i++) {
for (int d=0; d<ndim_tri+1; d++, j++)
nodelist[j] = tri[d][i];
}
int shapetype = 0;
if ( ndim_tri == 1 )
if ( ndim_tri==1 )
shapetype = DB_ZONETYPE_BEAM;
else if ( ndim_tri == 2 )
else if ( ndim_tri==2 )
shapetype = DB_ZONETYPE_TRIANGLE;
else if ( ndim_tri == 3 )
else if ( ndim_tri==3 )
shapetype = DB_ZONETYPE_PYRAMID;
else
ERROR( "Unknown shapetype" );
int shapesize = ndim_tri + 1;
int shapecnt = N_tri;
DBPutZonelist2( fid, zoneName.c_str(), N_tri, ndim_tri, nodelist.data(), nodelist.size(), 0, 0,
0, &shapetype, &shapesize, &shapecnt, 1, nullptr );
DBPutUcdmesh( fid, meshName.c_str(), ndim, nullptr, coords, N, nodelist.size(),
zoneName.c_str(), nullptr, getType<TYPE>(), nullptr );
ERROR("Unknown shapetype");
int shapesize = ndim_tri+1;
int shapecnt = N_tri;
DBPutZonelist2( fid, zoneName.c_str(), N_tri, ndim_tri, nodelist.data(),
nodelist.size(), 0, 0, 0, &shapetype, &shapesize, &shapecnt, 1, nullptr );
DBPutUcdmesh( fid, meshName.c_str(), ndim, nullptr, coords, N,
nodelist.size(), zoneName.c_str(), nullptr, getType<TYPE>(), nullptr );
}
template<class TYPE>
void readTriMesh( DBfile *fid, const std::string &meshname, Array<TYPE> &coords, Array<int> &tri )
void readTriMesh( DBfile* fid, const std::string& meshname, Array<TYPE>& coords, Array<int>& tri )
{
auto mesh = DBGetUcdmesh( fid, meshname.c_str() );
int ndim = mesh->ndims;
auto mesh = DBGetUcdmesh( fid, meshname.c_str() );
int ndim = mesh->ndims;
int N_nodes = mesh->nnodes;
coords.resize( N_nodes, ndim );
coords.resize(N_nodes,ndim);
int mesh_type = mesh->datatype;
for ( int d = 0; d < ndim; d++ ) {
for (int d=0; d<ndim; d++) {
Array<TYPE> data2( N_nodes );
copyData<TYPE>( data2, mesh_type, mesh->coords[d] );
memcpy( &coords( 0, d ), data2.data(), N_nodes * sizeof( TYPE ) );
memcpy( &coords(0,d), data2.data(), N_nodes*sizeof(TYPE) );
}
auto zones = mesh->zones;
auto zones = mesh->zones;
int N_zones = zones->nzones;
ASSERT( zones->nshapes == 1 );
ASSERT( zones->nshapes==1 );
int shapesize = zones->shapesize[0];
tri.resize( N_zones, shapesize );
for ( int i = 0; i < N_zones; i++ ) {
for ( int j = 0; j < shapesize; j++ )
tri( i, j ) = zones->nodelist[i * shapesize + j];
tri.resize(N_zones,shapesize);
for (int i=0; i<N_zones; i++) {
for (int j=0; j<shapesize; j++)
tri(i,j) = zones->nodelist[i*shapesize+j];
}
DBFreeUcdmesh( mesh );
}
template<class TYPE>
void writeTriMeshVariable( DBfile *fid, int ndim, const std::string &meshname,
const std::string &varname, const Array<TYPE> &data, VariableType type )
void writeTriMeshVariable( DBfile* fid, int ndim, const std::string& meshname,
const std::string& varname, const Array<TYPE>& data, VariableType type )
{
int nvars = 0;
int vartype = 0;
int nvars = 0;
int vartype = 0;
const TYPE *vars[10] = { nullptr };
if ( type == VariableType::NodeVariable ) {
vartype = DB_NODECENT;
nvars = data.size( 1 );
for ( int i = 0; i < nvars; i++ )
vars[i] = &data( 0, i );
nvars = data.size(1);
for (int i=0; i<nvars; i++)
vars[i] = &data(0,i);
} else if ( type == VariableType::EdgeVariable ) {
ERROR( "Not finished" );
ERROR("Not finished");
} else if ( type == VariableType::SurfaceVariable ) {
ERROR( "Not finished" );
ERROR("Not finished");
} else if ( type == VariableType::VolumeVariable ) {
vartype = DB_ZONECENT;
nvars = data.size( 1 );
for ( int i = 0; i < nvars; i++ )
vars[i] = &data( 0, i );
nvars = data.size(1);
for (int i=0; i<nvars; i++)
vars[i] = &data(0,i);
} else {
ERROR( "Invalid variable type" );
ERROR("Invalid variable type");
}
auto suffix = getVarSuffix( ndim, nvars );
std::vector<std::string> var_names( nvars );
for ( int i = 0; i < nvars; i++ )
std::vector<std::string> var_names(nvars);
for (int i=0; i<nvars; i++)
var_names[i] = varname + suffix[i];
std::vector<char *> varnames( nvars, nullptr );
for ( int i = 0; i < nvars; i++ )
varnames[i] = const_cast<char *>( var_names[i].c_str() );
DBPutUcdvar( fid, varname.c_str(), meshname.c_str(), nvars, varnames.data(), vars,
data.size( 0 ), nullptr, 0, getType<TYPE>(), vartype, nullptr );
std::vector<char*> varnames(nvars,nullptr);
for (int i=0; i<nvars; i++)
varnames[i] = const_cast<char*>(var_names[i].c_str());
DBPutUcdvar( fid, varname.c_str(), meshname.c_str(), nvars,
varnames.data(), vars, data.size(0), nullptr, 0, getType<TYPE>(), vartype, nullptr );
}
template<class TYPE>
Array<TYPE> readTriMeshVariable( DBfile *fid, const std::string &varname )
Array<TYPE> readTriMeshVariable( DBfile* fid, const std::string& varname )
{
auto var = DBGetUcdvar( fid, varname.c_str() );
ASSERT( var != nullptr );
Array<TYPE> data( var->nels, var->nvals );
int type = var->datatype;
for ( int i = 0; i < var->nvals; i++ ) {
for (int i=0; i<var->nvals; i++) {
Array<TYPE> data2( var->nels );
copyData<TYPE>( data2, type, var->vals[i] );
memcpy( &data( 0, i ), data2.data(), var->nels * sizeof( TYPE ) );
memcpy( &data(0,i), data2.data(), var->nels*sizeof(TYPE) );
}
DBFreeUcdvar( var );
return data;
}
} // namespace silo
} // namespace IO
}; // silo namespace
#endif

View File

@@ -23,7 +23,7 @@ Configure, build & install procedure
* edit configure script from sample_scripts directory and configure (e.g.)
`/path/to/LBPM/sample_scripts/configure_desktop`
`/path/to/LBPM-WIA/sample_scripts/configure_desktop`
* compile and install

View File

@@ -26,6 +26,7 @@ cmake \
-D CMAKE_CXX_COMPILER:PATH=CC \
-D CFLAGS="-DCBUB" \
-D CXXFLAGS="-DCBUB" \
-D MPI_COMPILER:BOOL=TRUE \
-D MPIEXEC=aprun \
-D USE_EXT_MPI_FOR_SERIAL_TESTS:BOOL=TRUE \
-D CMAKE_BUILD_TYPE:STRING=Debug \

View File

@@ -3,10 +3,11 @@
#include "StackTrace/StackTrace.h"
#include "common/MPI.h"
#include <functional>
#include "mpi.h"
namespace StackTrace
{

View File

@@ -7,7 +7,6 @@
#include <algorithm>
#include <atomic>
#include <cerrno>
#include <csignal>
#include <cstring>
#include <iostream>
@@ -349,11 +348,8 @@ static inline int exec3( const char *cmd, FUNCTION &fun )
if ( buffer[0] != 0 )
fun( buffer );
}
int code = pclose( pipe );
if ( errno == ECHILD ) {
errno = 0;
code = 0;
}
auto status = pclose( pipe );
int code = WEXITSTATUS( status );
std::this_thread::yield(); // Allow any signals to process
resetSignal( SIGCHLD ); // Clear child exited
return code;
@@ -856,7 +852,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 < 1024 && buf[j] != ':'; j++ ) {
for ( j = 0; j < 4095 && buf[j] != ':'; j++ ) {
}
buf[j] = 0;
copy( buf, info[i]->filename, info[i]->filenamePath );
@@ -1745,7 +1741,7 @@ std::vector<int> StackTrace::defaultSignalsToCatch()
* Set the signal handlers *
****************************************************************************/
static std::function<void( const StackTrace::abort_error &err )> abort_fun;
StackTrace::abort_error rethrow()
static StackTrace::abort_error rethrow()
{
StackTrace::abort_error error;
#ifdef USE_LINUX
@@ -1779,14 +1775,14 @@ StackTrace::abort_error rethrow()
}
return error;
}
void StackTrace::terminateFunctionSignal( int sig )
static void term_func_abort( int sig )
{
StackTrace::abort_error err;
err.type = StackTrace::terminateType::signal;
err.signal = sig;
err.bytes = StackTrace::Utilities::getMemoryUsage();
err.stack = StackTrace::backtrace();
err.stackType = StackTrace::getDefaultStackType();
err.stackType = StackTrace::printStackType::global;
abort_fun( err );
}
static bool signals_set[256] = { false };
@@ -1833,7 +1829,7 @@ void StackTrace::setErrorHandler( std::function<void( const StackTrace::abort_er
{
abort_fun = abort;
std::set_terminate( term_func );
setSignals( defaultSignalsToCatch(), &terminateFunctionSignal );
setSignals( defaultSignalsToCatch(), &term_func_abort );
std::set_unexpected( term_func );
}
void StackTrace::clearErrorHandler()
@@ -2219,7 +2215,7 @@ void StackTrace::cleanupStackTrace( multi_stack_info &stack )
// Remove callstack (and all children) for threads that are just contributing
bool test = function.find( "_callstack_signal_handler" ) != npos ||
function.find( "getGlobalCallStacks" ) != npos ||
function.find( "backtrace" ) != npos || function.find( "(" ) == npos;
function.find( "(" ) == npos;
if ( test ) {
it = stack.children.erase( it );
continue;
@@ -2519,11 +2515,3 @@ const char *StackTrace::abort_error::what() const noexcept
d_msg.erase( i, 1 );
return d_msg.c_str();
}
/****************************************************************************
* Get/Set default stack type *
****************************************************************************/
static StackTrace::printStackType abort_stackType = StackTrace::printStackType::global;
void StackTrace::setDefaultStackType( StackTrace::printStackType type ) { abort_stackType = type; }
StackTrace::printStackType StackTrace::getDefaultStackType() { return abort_stackType; }

View File

@@ -261,10 +261,6 @@ void clearSignals();
void raiseSignal( int signal );
//! Default function to abort after catching a signal
void terminateFunctionSignal( int signal );
//! Return a list of all signals that can be caught
std::vector<int> allSignalsToCatch();
@@ -308,13 +304,6 @@ multi_stack_info generateFromString( const std::vector<std::string> &str );
multi_stack_info generateFromString( const std::string &str );
//! Set default stack type
void setDefaultStackType( StackTrace::printStackType );
//! Get default stack type
StackTrace::printStackType getDefaultStackType();
} // namespace StackTrace

View File

@@ -8,10 +8,8 @@
#include <cstring>
#include <fstream>
#include <iostream>
#include <mutex>
#include <sstream>
#include <stdexcept>
#include <typeinfo>
#ifdef USE_MPI
#include "mpi.h"
@@ -21,10 +19,6 @@
#include "MemoryApp.h"
#endif
#ifdef USE_GCOV
extern "C" void __gcov_flush( void );
#endif
#define perr std::cerr
@@ -71,12 +65,6 @@ extern "C" void __gcov_flush( void );
// clang-format on
#ifdef __GNUC__
#define USE_ABI
#include <cxxabi.h>
#endif
namespace StackTrace {
@@ -108,12 +96,13 @@ inline size_t findfirst( const std::vector<TYPE> &X, TYPE Y )
/****************************************************************************
* Function to terminate the program *
****************************************************************************/
static bool abort_throwException = false;
static int force_exit = 0;
static bool abort_throwException = false;
static printStackType abort_stackType = printStackType::global;
static int force_exit = 0;
void Utilities::setAbortBehavior( bool throwException, int stackType )
{
abort_throwException = throwException;
StackTrace::setDefaultStackType( static_cast<printStackType>( stackType ) );
abort_stackType = static_cast<printStackType>( stackType );
}
void Utilities::abort( const std::string &message, const std::string &filename, const int line )
{
@@ -123,28 +112,16 @@ void Utilities::abort( const std::string &message, const std::string &filename,
err.type = terminateType::abort;
err.line = line;
err.bytes = Utilities::getMemoryUsage();
err.stackType = StackTrace::getDefaultStackType();
err.stackType = abort_stackType;
err.stack = StackTrace::backtrace();
throw err;
}
static std::mutex terminate_mutex;
static inline void callAbort()
static void terminate( const StackTrace::abort_error &err )
{
#ifdef USE_GCOV
__gcov_flush();
#endif
terminate_mutex.unlock();
std::abort();
}
void Utilities::terminate( const StackTrace::abort_error &err )
{
// Lock mutex to ensure multiple threads do not try to abort simultaneously
terminate_mutex.lock();
// Clear the error handlers
clearErrorHandler();
// Print the message and abort
if ( force_exit > 1 ) {
callAbort();
std::abort();
} else if ( !abort_throwException ) {
// Use MPI_abort (will terminate all processes)
force_exit = 2;
@@ -158,11 +135,10 @@ void Utilities::terminate( const StackTrace::abort_error &err )
MPI_Abort( MPI_COMM_WORLD, -1 );
}
#endif
callAbort();
std::abort();
} else {
perr << err.what();
perr.flush();
callAbort();
std::abort();
}
}
@@ -173,7 +149,7 @@ void Utilities::terminate( const StackTrace::abort_error &err )
static void setTerminateErrorHandler()
{
// Set the terminate routine for runtime errors
StackTrace::setErrorHandler( Utilities::terminate );
StackTrace::setErrorHandler( terminate );
}
void Utilities::setErrorHandlers()
{
@@ -317,18 +293,4 @@ std::string Utilities::exec( const string_view &cmd, int &exit_code )
}
/****************************************************************************
* Get the type name *
****************************************************************************/
std::string Utilities::getTypeName( const std::type_info &id )
{
std::string name = id.name();
#if defined( USE_ABI )
int status;
name = abi::__cxa_demangle( name.c_str(), 0, 0, &status );
#endif
return name;
}
} // namespace StackTrace

View File

@@ -4,7 +4,6 @@
#include <stdexcept>
#include <string>
#include <thread>
#include <typeinfo>
#include "StackTrace/StackTrace.h"
#include "StackTrace/string_view.h"
@@ -29,14 +28,9 @@ void abort( const std::string &message, const std::string &filename, const int l
void setAbortBehavior( bool throwException, int stackType = 2 );
//! Function to terminate the application
void terminate( const StackTrace::abort_error &err );
//! Function to set the error handlers
void setErrorHandlers();
//! Function to clear the error handlers
void clearErrorHandlers();
@@ -98,18 +92,6 @@ void cause_segfault();
std::string exec( const StackTrace::string_view &cmd, int &exit_code );
//! Return the hopefully demangled name of the given type
std::string getTypeName( const std::type_info &id );
//! Return the hopefully demangled name of the given type
template<class TYPE>
inline std::string getTypeName()
{
return getTypeName( typeid( TYPE ) );
}
} // namespace Utilities
} // namespace StackTrace

View File

@@ -119,7 +119,7 @@ public:
int result = 0;
for ( int i = 0; i < N && result == 0; i++ )
if ( d_data[i] != other[i] )
result = d_data[i] < other[i] ? -( i + 1 ) : ( i + 1 );
result = d_data[i] < other[i] ? -i : i;
if ( result == 0 )
result = size() == other.size() ? 0 : size() < other.size() ? -1 : 1;
return result;

View File

@@ -1,483 +0,0 @@
#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);
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);
}
}
void ElectroChemistryAnalyzer::SetParams(){
}
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;
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]);
fprintf(TIMELOG,"%.8g ",rho_mu_avg_local[ion]);
fprintf(TIMELOG,"%.8g ",rho_psi_avg_local[ion]);
fprintf(TIMELOG,"%.8g ",rho_mu_fluctuation_local[ion]);
fprintf(TIMELOG,"%.8g ",rho_psi_fluctuation_local[ion]);
}
fflush(TIMELOG);
} */
}
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);
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 );
//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++){
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>();
// 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_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);
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);
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);
visData[0].vars.push_back(VzVar);
}
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_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_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>( "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);
}
*/
}

View File

@@ -1,67 +0,0 @@
/*
* averaging tools for electrochemistry
*/
#ifndef ElectroChem_INC
#define ElectroChem_INC
#include <vector>
#include "common/Domain.h"
#include "common/Utilities.h"
#include "common/MPI.h"
#include "common/Communication.h"
#include "analysis/analysis.h"
#include "analysis/distance.h"
#include "analysis/Minkowski.h"
#include "IO/MeshDatabase.h"
#include "IO/Reader.h"
#include "IO/Writer.h"
#include "models/IonModel.h"
#include "models/PoissonSolver.h"
#include "models/StokesModel.h"
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;
//...........................................................................
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);
private:
FILE *TIMELOG;
};
#endif

View File

@@ -1,514 +0,0 @@
/* 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));
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));
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));
return(mass_loss);
}

View File

@@ -1,90 +0,0 @@
/* 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

View File

@@ -1,178 +0,0 @@
#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;
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);
}
}
void FreeEnergyAnalyzer::SetParams(){
}
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++){
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,"\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]);
fprintf(TIMELOG,"%.8g ",rho_mu_avg_local[ion]);
fprintf(TIMELOG,"%.8g ",rho_psi_avg_local[ion]);
fprintf(TIMELOG,"%.8g ",rho_mu_fluctuation_local[ion]);
fprintf(TIMELOG,"%.8g ",rho_psi_fluctuation_local[ion]);
}
fflush(TIMELOG);
} */
}
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);
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 );
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);
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);
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);
visData[0].vars.push_back(VisChemicalPotential);
}
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);
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);
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);
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_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_8bit_raw", true )){
char CurrentIDFilename[40];
sprintf(CurrentIDFilename,"id_t%d.raw",timestep);
Averages.AggregateLabels(CurrentIDFilename);
}
*/
}

View File

@@ -1,62 +0,0 @@
/*
* averaging tools for electrochemistry
*/
#ifndef FreeEnergyAnalyzer_INC
#define FreeEnergyAnalyzer_INC
#include <vector>
#include "common/Domain.h"
#include "common/Utilities.h"
#include "common/MPI.h"
#include "common/Communication.h"
#include "analysis/analysis.h"
#include "analysis/distance.h"
#include "analysis/Minkowski.h"
#include "analysis/SubPhase.h"
#include "IO/MeshDatabase.h"
#include "IO/Reader.h"
#include "IO/Writer.h"
#include "models/FreeLeeModel.h"
/**
* \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;
//...........................................................................
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);
private:
FILE *TIMELOG;
};
#endif

View File

@@ -1,263 +0,0 @@
#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);
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()
{
}
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;
grey_porosity = GreyPorosity;
}
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;
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);
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);
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);
//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;
// 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);
}
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,
double nx, double ny, double nz, double ux, double uy, double uz, interface &I){
double A1,A2,A3,A4,A5,A6;
double B1,B2,B3,B4,B5,B6;
double nAB,delta;
// Instantiate mass transport distributions
// Stationary value - distribution 0
nAB = 1.0/(nA+nB);
//...............................................
// q = 0,2,4
// Cq = {1,0,0}, {0,1,0}, {0,0,1}
delta = beta*nA*nB*nAB*0.1111111111111111*nx;
if (!(nA*nB*nAB>0)) delta=0;
A1 = nA*(0.1111111111111111*(1+4.5*ux))+delta;
B1 = nB*(0.1111111111111111*(1+4.5*ux))-delta;
A2 = nA*(0.1111111111111111*(1-4.5*ux))-delta;
B2 = nB*(0.1111111111111111*(1-4.5*ux))+delta;
//...............................................
// Cq = {0,1,0}
delta = beta*nA*nB*nAB*0.1111111111111111*ny;
if (!(nA*nB*nAB>0)) delta=0;
A3 = nA*(0.1111111111111111*(1+4.5*uy))+delta;
B3 = nB*(0.1111111111111111*(1+4.5*uy))-delta;
A4 = nA*(0.1111111111111111*(1-4.5*uy))-delta;
B4 = nB*(0.1111111111111111*(1-4.5*uy))+delta;
//...............................................
// q = 4
// Cq = {0,0,1}
delta = beta*nA*nB*nAB*0.1111111111111111*nz;
if (!(nA*nB*nAB>0)) delta=0;
A5 = nA*(0.1111111111111111*(1+4.5*uz))+delta;
B5 = nB*(0.1111111111111111*(1+4.5*uz))-delta;
A6 = nA*(0.1111111111111111*(1-4.5*uz))-delta;
B6 = nB*(0.1111111111111111*(1-4.5*uz))+delta;
double unx = (A1-A2);
double uny = (A3-A4);
double unz = (A5-A6);
double uwx = (B1-B2);
double uwy = (B3-B4);
double uwz = (B5-B6);
I.Mn += rA*nA;
I.Mw += rB*nB;
I.Pnx += rA*nA*unx;
I.Pny += rA*nA*uny;
I.Pnz += rA*nA*unz;
I.Pwx += rB*nB*uwx;
I.Pwy += rB*nB*uwy;
I.Pwz += rB*nB*uwz;
I.Kn += rA*nA*(unx*unx + uny*uny + unz*unz);
I.Kw += rB*nB*(uwx*uwx + uwy*uwy + uwz*uwz);
}
*/

View File

@@ -1,88 +0,0 @@
/*
* Sub-phase averaging tools
*/
#ifndef GreyPhase_INC
#define GreyPhase_INC
#include <vector>
#include "common/ScaLBL.h"
#include "common/Communication.h"
#include "analysis/analysis.h"
#include "common/Utilities.h"
#include "common/MPI.h"
#include "IO/MeshDatabase.h"
#include "IO/Reader.h"
#include "IO/Writer.h"
/**
* \class GreyPhase
*
* @brief
* The GreyPhase class tracks pressure, mass and momentum within a grey phase
*
*/
class GreyPhase{
public:
double p;
double M,Px,Py,Pz;
void reset(){
p=M=Px=Py=Pz=0.0;
}
private:
};
/**
* \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

View File

@@ -1,6 +1,5 @@
/*
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
@@ -20,7 +19,7 @@
#include "common/Domain.h"
#include "common/Communication.h"
#include "common/Utilities.h"
#include "common/MPI.h"
#include "common/MPI_Helpers.h"
#include "IO/MeshDatabase.h"
#include "IO/Reader.h"
#include "IO/Writer.h"
@@ -66,7 +65,7 @@ void Minkowski::ComputeScalar(const DoubleArray& Field, const double isovalue)
{
PROFILE_START("ComputeScalar");
Xi = Ji = Ai = 0.0;
DCEL object;
DECL object;
int e1,e2,e3;
double s,s1,s2,s3;
double a1,a2,a3;
@@ -107,21 +106,7 @@ void Minkowski::ComputeScalar(const DoubleArray& Field, const double isovalue)
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);
double nside_intern = double(npts)-3.0;
EulerChar=0.0;
if (npts > 0) EulerChar = (0.25*nvert - nside_intern - 0.5*nside_extern + nface); */
Xi += 0.25*double(object.VertexCount);
}
}
}
@@ -139,13 +124,13 @@ void Minkowski::ComputeScalar(const DoubleArray& Field, const double isovalue)
// convert X for 2D manifold to 3D object
Xi *= 0.5;
Dm->Comm.barrier();
MPI_Barrier(Dm->Comm);
// 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();
MPI_Allreduce(&Vi,&Vi_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&Xi,&Xi_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&Ai,&Ai_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&Ji,&Ji_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Barrier(Dm->Comm);
PROFILE_STOP("ComputeScalar");
}
@@ -158,7 +143,7 @@ void Minkowski::MeasureObject(){
* 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++){
@@ -167,44 +152,6 @@ void Minkowski::MeasureObject(){
}
}
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){
/*
* 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);
}
@@ -236,7 +183,7 @@ int Minkowski::MeasureConnectedPathway(){
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();
MPI_Barrier(Dm->Comm);
for (int k=0; k<Nz; k++){
for (int j=0; j<Ny; j++){
@@ -254,51 +201,6 @@ int Minkowski::MeasureConnectedPathway(){
return n_connected_components;
}
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;
}
void Minkowski::PrintAll()
{

View File

@@ -1,6 +1,5 @@
/*
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
@@ -26,22 +25,13 @@
#include "common/Communication.h"
#include "analysis/analysis.h"
#include "analysis/distance.h"
#include "analysis/filters.h"
#include "common/Utilities.h"
#include "common/MPI.h"
#include "common/MPI_Helpers.h"
#include "IO/MeshDatabase.h"
#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{
//...........................................................................
@@ -69,7 +59,6 @@ public:
int n_connected_components;
//...........................................................................
int Nx,Ny,Nz;
double V(){
return Vi;
}
@@ -84,56 +73,13 @@ public:
}
//..........................................................................
/**
* \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();
};

View File

@@ -1,6 +1,5 @@
/*
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
@@ -22,6 +21,9 @@
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) {}
LBPM_Point(const LBPM_Point& rhs): x(rhs.x), y(rhs.y), z(rhs.z) {}
//Point& operator=(const Point& rhs) { this->x=rhs.x; this->y=rhs.y; this->z=rhs.z; return *this; }
//~Point() {}
double x,y,z;
};
typedef LBPM_Point Point;

View File

@@ -23,7 +23,6 @@ SubPhase::SubPhase(std::shared_ptr <Domain> dm):
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);
Dissipation.resize(Nx,Ny,Nz); Dissipation.fill(0);
SDs.resize(Nx,Ny,Nz); SDs.fill(0);
//.........................................
@@ -41,18 +40,17 @@ SubPhase::SubPhase(std::shared_ptr <Domain> dm):
{
// If timelog is empty, write a short header to list the averages
//fprintf(SUBPHASE,"--------------------------------------------------------------------------------------\n");
fprintf(SUBPHASE,"time rn rw nun nuw Fx Fy Fz iftwn wet ");
fprintf(SUBPHASE,"time rn rw nun nuw Fx Fy Fz iftwn ");
fprintf(SUBPHASE,"pwc pwd pnc pnd "); // pressures
fprintf(SUBPHASE,"Mwc Mwd Mwi Mnc Mnd Mni Msw Msn "); // mass
fprintf(SUBPHASE,"Pwc_x Pwd_x Pwi_x Pnc_x Pnd_x Pni_x Psw_x Psn_x "); // momentum
fprintf(SUBPHASE,"Pwc_y Pwd_y Pwi_y Pnc_y Pnd_y Pni_y Psw_y Psn_y ");
fprintf(SUBPHASE,"Pwc_z Pwd_z Pwi_z Pnc_z Pnd_z Pni_z Psw_z Psn_z ");
fprintf(SUBPHASE,"Mwc Mwd Mwi Mnc Mnd Mni "); // mass
fprintf(SUBPHASE,"Pwc_x Pwd_x Pwi_x Pnc_x Pnd_x Pni_x "); // momentum
fprintf(SUBPHASE,"Pwc_y Pwd_y Pwi_y Pnc_y Pnd_y Pni_y ");
fprintf(SUBPHASE,"Pwc_z Pwd_z Pwi_z Pnc_z Pnd_z Pni_z ");
fprintf(SUBPHASE,"Kwc Kwd Kwi Knc Knd Kni "); // kinetic energy
fprintf(SUBPHASE,"Dwc Dwd Dnc Dnd "); // viscous dissipation
fprintf(SUBPHASE,"Vwc Awc Hwc Xwc "); // wc region
fprintf(SUBPHASE,"Vwd Awd Hwd Xwd Nwd "); // wd region
fprintf(SUBPHASE,"Vnc Anc Hnc Xnc "); // nc region
fprintf(SUBPHASE,"Vnd And Hnd Xnd Nnd "); // nd regionin
fprintf(SUBPHASE,"Vnd And Hnd Xnd Nnd "); // nd region
fprintf(SUBPHASE,"Vi Ai Hi Xi "); // interface region
fprintf(SUBPHASE,"Vic Aic Hic Xic Nic\n"); // interface region
@@ -67,14 +65,13 @@ SubPhase::SubPhase(std::shared_ptr <Domain> dm):
sprintf(LocalRankFilename,"%s%s","subphase.csv.",LocalRankString);
SUBPHASE = fopen(LocalRankFilename,"a+");
//fprintf(SUBPHASE,"--------------------------------------------------------------------------------------\n");
fprintf(SUBPHASE,"time rn rw nun nuw Fx Fy Fz iftwn wet ");
fprintf(SUBPHASE,"time rn rw nun nuw Fx Fy Fz iftwn ");
fprintf(SUBPHASE,"pwc pwd pnc pnd "); // pressures
fprintf(SUBPHASE,"Mwc Mwd Mwi Mnc Mnd Mni Msw Msn "); // mass
fprintf(SUBPHASE,"Pwc_x Pwd_x Pwi_x Pnc_x Pnd_x Pni_x Psw_x Psn_x "); // momentum
fprintf(SUBPHASE,"Pwc_y Pwd_y Pwi_y Pnc_y Pnd_y Pni_y Psw_y Psn_y ");
fprintf(SUBPHASE,"Pwc_z Pwd_z Pwi_z Pnc_z Pnd_z Pni_z Psw_z Psn_z ");
fprintf(SUBPHASE,"Mwc Mwd Mwi Mnc Mnd Mni "); // mass
fprintf(SUBPHASE,"Pwc_x Pwd_x Pwi_x Pnc_x Pnd_x Pni_x "); // momentum
fprintf(SUBPHASE,"Pwc_y Pwd_y Pwi_y Pnc_y Pnd_y Pni_y ");
fprintf(SUBPHASE,"Pwc_z Pwd_z Pwi_z Pnc_z Pnd_z Pni_z ");
fprintf(SUBPHASE,"Kwc Kwd Kwi Knc Knd Kni "); // kinetic energy
fprintf(SUBPHASE,"Dwc Dwd Dnc Dnd "); // viscous dissipation
fprintf(SUBPHASE,"Vwc Awc Hwc Xwc "); // wc region
fprintf(SUBPHASE,"Vwd Awd Hwd Xwd Nwd "); // wd region
fprintf(SUBPHASE,"Vnc Anc Hnc Xnc "); // nc region
@@ -96,7 +93,7 @@ SubPhase::SubPhase(std::shared_ptr <Domain> dm):
{
// If timelog is empty, write a short header to list the averages
//fprintf(TIMELOG,"--------------------------------------------------------------------------------------\n");
fprintf(TIMELOG,"sw krw krn krwf krnf vw vn force pw pn wet peff\n");
fprintf(TIMELOG,"sw krw krn vw vn pw pn\n");
}
}
}
@@ -112,14 +109,13 @@ SubPhase::~SubPhase()
void SubPhase::Write(int timestep)
{
if (Dm->rank()==0){
fprintf(SUBPHASE,"%i %.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g ",timestep,rho_n,rho_w,nu_n,nu_w,Fx,Fy,Fz,gamma_wn,total_wetting_interaction_global);
fprintf(SUBPHASE,"%i %.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g ",timestep,rho_n,rho_w,nu_n,nu_w,Fx,Fy,Fz,gamma_wn);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g ",gwc.p, gwd.p, gnc.p, gnd.p);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g ",gwc.M, gwd.M, giwn.Mw, gnc.M, gnd.M, giwn.Mn, gifs.Mw, gifs.Mn);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g ",gwc.Px, gwd.Px, giwn.Pwx, gnc.Px, gnd.Px, giwn.Pnx, gifs.Pwx, gifs.Pnx);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g ",gwc.Py, gwd.Py, giwn.Pwy, gnc.Py, gnd.Py, giwn.Pny, gifs.Pwy, gifs.Pny);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g ",gwc.Pz, gwd.Pz, giwn.Pwz, gnc.Pz, gnd.Pz, giwn.Pnz, gifs.Pwz, gifs.Pnz);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g ",gwc.M, gwd.M, giwn.Mw, gnc.M, gnd.M, giwn.Mn);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g ",gwc.Px, gwd.Px, giwn.Pwx, gnc.Px, gnd.Px, giwn.Pnx);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g ",gwc.Py, gwd.Py, giwn.Pwy, gnc.Py, gnd.Py, giwn.Pny);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g ",gwc.Pz, gwd.Pz, giwn.Pwz, gnc.Pz, gnd.Pz, giwn.Pnz);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g ",gwc.K, gwd.K, giwn.Kw, gnc.K, gnd.K, giwn.Kn);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g ",gwc.visc, gwd.visc, gnc.visc, gnd.visc);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g ",gwc.V, gwc.A, gwc.H, gwc.X);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %i ",gwd.V, gwd.A, gwd.H, gwd.X, gwd.Nc);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g ",gnc.V, gnc.A, gnc.H, gnc.X);
@@ -129,14 +125,13 @@ void SubPhase::Write(int timestep)
fflush(SUBPHASE);
}
else{
fprintf(SUBPHASE,"%i %.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g ",timestep,rho_n,rho_w,nu_n,nu_w,Fx,Fy,Fz,gamma_wn,total_wetting_interaction);
fprintf(SUBPHASE,"%i %.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g ",timestep,rho_n,rho_w,nu_n,nu_w,Fx,Fy,Fz,gamma_wn);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g ",wc.p, wd.p, nc.p, nd.p);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g ",wc.M, wd.M, iwn.Mw, nc.M, nd.M, iwn.Mn, ifs.Mw, ifs.Mn);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g ",wc.Px, wd.Px, iwn.Pwx, nc.Px, nd.Px, iwn.Pnx, ifs.Pwx, ifs.Pnx);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g ",wc.Py, wd.Py, iwn.Pwy, nc.Py, nd.Py, iwn.Pny, ifs.Pwy, ifs.Pny);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g ",wc.Pz, wd.Pz, iwn.Pwz, nc.Pz, nd.Pz, iwn.Pnz, ifs.Pwz, ifs.Pnz);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g ",wc.M, wd.M, iwn.Mw, nc.M, nd.M, iwn.Mn);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g ",wc.Px, wd.Px, iwn.Pwx, nc.Px, nd.Px, iwn.Pnx);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g ",wc.Py, wd.Py, iwn.Pwy, nc.Py, nd.Py, iwn.Pny);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g ",wc.Pz, wd.Pz, iwn.Pwz, nc.Pz, nd.Pz, iwn.Pnz);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %.8g %.8g ",wc.K, wd.K, iwn.Kw, nc.K, nd.K, iwn.Kn);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g ",wc.visc, wd.visc, nc.visc, nd.visc);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g ",wc.V, wc.A, wc.H, wc.X);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g %i ",wd.V, wd.A, wd.H, wd.X, wd.Nc);
fprintf(SUBPHASE,"%.8g %.8g %.8g %.8g ",nc.V, nc.A, nc.H, nc.X);
@@ -166,32 +161,18 @@ void SubPhase::Basic(){
// If external boundary conditions are set, do not average over the inlet
kmin=1; kmax=Nz-1;
imin=jmin=1;
/*// If inlet/outlet layers exist use these as default
// If inlet/outlet layers exist use these as default
if (Dm->inlet_layers_x > 0) imin = Dm->inlet_layers_x;
if (Dm->inlet_layers_y > 0) jmin = Dm->inlet_layers_y;
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;
*/
nb.reset(); wb.reset(); iwn.reset();
nb.reset(); wb.reset();
double nA,nB;
double count_w = 0.0;
double count_n = 0.0;
/* compute the laplacian */
Dm->CommunicateMeshHalo(Phi);
for (int k=1; k<Nz-1; k++){
for (int j=1; j<Ny-1; j++){
for (int i=1; i<Nx-1; i++){
// Compute all of the derivatives using finite differences
double fx = 0.5*(Phi(i+1,j,k) - Phi(i-1,j,k));
double fy = 0.5*(Phi(i,j+1,k) - Phi(i,j-1,k));
double fz = 0.5*(Phi(i,j,k+1) - Phi(i,j,k-1));
DelPhi(i,j,k) = sqrt(fx*fx+fy*fy+fz*fz);
}
}
}
Dm->CommunicateMeshHalo(DelPhi);
for (k=0; k<Nz; k++){
for (j=0; j<Ny; j++){
for (i=0; i<Nx; i++){
@@ -204,11 +185,6 @@ void SubPhase::Basic(){
double phi = (nA-nB)/(nA+nB);
Phi(n) = phi;
}
if (Phi(n) != Phi(n)){
// check for NaN
Phi(n) = 0.0;
//printf("Nan at %i %i %i \n",i,j,k);
}
}
}
}
@@ -250,79 +226,29 @@ void SubPhase::Basic(){
wb.p += Pressure(n);
count_w += 1.0;
}
/* compute the film contribution */
else if (SDs(i,j,k) < 2.0){
if ( phi > 0.0 ){
nA = 1.0;
iwn.V += 1.0;
iwn.Mn += nA*rho_n;
// velocity
iwn.Pnx += rho_n*nA*Vel_x(n);
iwn.Pny += rho_n*nA*Vel_y(n);
iwn.Pnz += rho_n*nA*Vel_z(n);
}
else{
nB = 1.0;
iwn.Mw += nB*rho_w;
iwn.V += 1.0;
iwn.Pwx += rho_w*nB*Vel_x(n);
iwn.Pwy += rho_w*nB*Vel_y(n);
iwn.Pwz += rho_w*nB*Vel_z(n);
}
}
}
}
}
}
gwb.V=sumReduce( Dm->Comm, wb.V);
gnb.V=sumReduce( Dm->Comm, nb.V);
gwb.M=sumReduce( Dm->Comm, wb.M);
gnb.M=sumReduce( Dm->Comm, nb.M);
gwb.Px=sumReduce( Dm->Comm, wb.Px);
gwb.Py=sumReduce( Dm->Comm, wb.Py);
gwb.Pz=sumReduce( Dm->Comm, wb.Pz);
gnb.Px=sumReduce( Dm->Comm, nb.Px);
gnb.Py=sumReduce( Dm->Comm, nb.Py);
gnb.Pz=sumReduce( Dm->Comm, nb.Pz);
total_wetting_interaction = count_wetting_interaction = 0.0;
total_wetting_interaction_global = count_wetting_interaction_global=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 contribution of wetting terms (within two voxels of solid)
if ( Dm->id[n] > 0 && SDs(i,j,k) < 2.0 ){
count_wetting_interaction += 1.0;
total_wetting_interaction += DelPhi(i,j,k);
}
}
}
}
//printf("wetting interaction = %f, count = %f\n",total_wetting_interaction,count_wetting_interaction);
total_wetting_interaction_global=Dm->Comm.sumReduce( total_wetting_interaction);
count_wetting_interaction_global=Dm->Comm.sumReduce( count_wetting_interaction);
gwb.V=Dm->Comm.sumReduce( wb.V);
gnb.V=Dm->Comm.sumReduce( nb.V);
gwb.M=Dm->Comm.sumReduce( wb.M);
gnb.M=Dm->Comm.sumReduce( nb.M);
gwb.Px=Dm->Comm.sumReduce( wb.Px);
gwb.Py=Dm->Comm.sumReduce( wb.Py);
gwb.Pz=Dm->Comm.sumReduce( wb.Pz);
gnb.Px=Dm->Comm.sumReduce( nb.Px);
gnb.Py=Dm->Comm.sumReduce( nb.Py);
gnb.Pz=Dm->Comm.sumReduce( nb.Pz);
giwn.Mw=Dm->Comm.sumReduce( iwn.Mw);
giwn.Pwx=Dm->Comm.sumReduce( iwn.Pwx);
giwn.Pwy=Dm->Comm.sumReduce( iwn.Pwy);
giwn.Pwz=Dm->Comm.sumReduce( iwn.Pwz);
giwn.Mn=Dm->Comm.sumReduce( iwn.Mn);
giwn.Pnx=Dm->Comm.sumReduce( iwn.Pnx);
giwn.Pny=Dm->Comm.sumReduce( iwn.Pny);
giwn.Pnz=Dm->Comm.sumReduce( iwn.Pnz);
count_w=Dm->Comm.sumReduce( count_w);
count_n=Dm->Comm.sumReduce( count_n);
count_w=sumReduce( Dm->Comm, count_w);
count_n=sumReduce( Dm->Comm, count_n);
if (count_w > 0.0)
gwb.p=Dm->Comm.sumReduce( wb.p) / count_w;
gwb.p=sumReduce( Dm->Comm, wb.p) / count_w;
else
gwb.p = 0.0;
if (count_n > 0.0)
gnb.p=Dm->Comm.sumReduce( nb.p) / count_n;
gnb.p=sumReduce( Dm->Comm, nb.p) / count_n;
else
gnb.p = 0.0;
@@ -340,29 +266,28 @@ void SubPhase::Basic(){
if (gnb.Pz != gnb.Pz) err=true;
if (Dm->rank() == 0){
/* align flow direction based on total mass flux */
double dir_x = gwb.Px + gnb.Px;
double dir_y = gwb.Py + gnb.Py;
double dir_z = gwb.Pz + gnb.Pz;
double flow_magnitude = dir_x*dir_x + dir_y*dir_y + dir_z*dir_z;
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 {
dir_x /= flow_magnitude;
dir_y /= flow_magnitude;
dir_z /= flow_magnitude;
// 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 ){
if (Dm->BoundaryCondition > 0 ){
// 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 && flow_magnitude == 0.0){
if (force_mag == 0.0){
// default to z direction
dir_x = 0.0;
dir_y = 0.0;
@@ -372,24 +297,14 @@ void SubPhase::Basic(){
double saturation=gwb.V/(gwb.V + gnb.V);
double water_flow_rate=gwb.V*(gwb.Px*dir_x + gwb.Py*dir_y + gwb.Pz*dir_z)/gwb.M / Dm->Volume;
double not_water_flow_rate=gnb.V*(gnb.Px*dir_x + gnb.Py*dir_y + gnb.Pz*dir_z)/gnb.M/ Dm->Volume;
/* contribution from water films */
double water_film_flow_rate=gwb.V*(giwn.Pwx*dir_x + giwn.Pwy*dir_y + giwn.Pwz*dir_z)/gwb.M / Dm->Volume;
double not_water_film_flow_rate=gnb.V*(giwn.Pnx*dir_x + giwn.Pny*dir_y + giwn.Pnz*dir_z)/gnb.M / Dm->Volume;
//double total_flow_rate = water_flow_rate + not_water_flow_rate;
//double fractional_flow = water_flow_rate / total_flow_rate;
double total_flow_rate = water_flow_rate + not_water_flow_rate;
double fractional_flow= water_flow_rate / total_flow_rate;
double h = Dm->voxel_length;
double krn = h*h*nu_n*not_water_flow_rate / force_mag ;
double krw = h*h*nu_w*water_flow_rate / force_mag;
/* not counting films */
double krnf = krn - h*h*nu_n*not_water_film_flow_rate / force_mag ;
double krwf = krw - h*h*nu_w*water_film_flow_rate / force_mag;
double eff_pressure = 1.0 / (krn + krw); // effective pressure drop
fprintf(TIMELOG,"%.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g %.8g\n",
saturation, krw, krn, krwf, krnf, h*water_flow_rate,
h*not_water_flow_rate, force_mag,
gwb.p, gnb.p, total_wetting_interaction_global, eff_pressure);
//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*not_water_flow_rate, gwb.p, gnb.p);
fflush(TIMELOG);
}
if (err==true){
@@ -405,7 +320,6 @@ inline void InterfaceTransportMeasures( double beta, double rA, double rB, doubl
double A1,A2,A3,A4,A5,A6;
double B1,B2,B3,B4,B5,B6;
double nAB,delta;
double phi = (nA-nB)/(nA+nB);
// Instantiate mass transport distributions
// Stationary value - distribution 0
nAB = 1.0/(nA+nB);
@@ -444,7 +358,7 @@ inline void InterfaceTransportMeasures( double beta, double rA, double rB, doubl
double uwx = (B1-B2);
double uwy = (B3-B4);
double uwz = (B5-B6);
/*
I.Mn += rA*nA;
I.Mw += rB*nB;
I.Pnx += rA*nA*unx;
@@ -455,21 +369,6 @@ inline void InterfaceTransportMeasures( double beta, double rA, double rB, doubl
I.Pwz += rB*nB*uwz;
I.Kn += rA*nA*(unx*unx + uny*uny + unz*unz);
I.Kw += rB*nB*(uwx*uwx + uwy*uwy + uwz*uwz);
*/
if (phi > 0.0){
I.Mn += rA;
I.Pnx += rA*ux;
I.Pny += rA*uy;
I.Pnz += rA*uz;
}
else {
I.Mw += rB;
I.Pwx += rB*ux;
I.Pwy += rB*uy;
I.Pwz += rB*uz;
}
I.Kn += rA*nA*(unx*unx + uny*uny + unz*unz);
I.Kw += rB*nB*(uwx*uwx + uwy*uwy + uwz*uwz);
}
@@ -478,18 +377,17 @@ void SubPhase::Full(){
// If external boundary conditions are set, do not average over the inlet
kmin=1; kmax=Nz-1;
/*if (Dm->BoundaryCondition > 0 && Dm->BoundaryCondition != 5 && Dm->kproc() == 0) kmin=4;
if (Dm->BoundaryCondition > 0 && Dm->BoundaryCondition != 5 && Dm->kproc() == Dm->nprocz()-1) kmax=Nz-4;
*/
if (Dm->BoundaryCondition > 0 && Dm->kproc() == 0) kmin=4;
if (Dm->BoundaryCondition > 0 && Dm->kproc() == Dm->nprocz()-1) kmax=Nz-4;
imin=jmin=1;
/*// If inlet layers exist use these as default
* NOTE -- excluding inlet / outlet will screw up topological averages!!!
// If inlet layers exist use these as default
if (Dm->inlet_layers_x > 0) imin = Dm->inlet_layers_x;
if (Dm->inlet_layers_y > 0) jmin = Dm->inlet_layers_y;
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;
*/
nd.reset(); nc.reset(); wd.reset(); wc.reset(); iwn.reset(); iwnc.reset(); ifs.reset();
nd.reset(); nc.reset(); wd.reset(); wc.reset(); iwn.reset(); iwnc.reset();
Dm->CommunicateMeshHalo(Phi);
for (int k=1; k<Nz-1; k++){
@@ -504,33 +402,6 @@ void SubPhase::Full(){
}
}
Dm->CommunicateMeshHalo(DelPhi);
Dm->CommunicateMeshHalo(Vel_x);
Dm->CommunicateMeshHalo(Vel_y);
Dm->CommunicateMeshHalo(Vel_z);
for (int k=1; k<Nz-1; k++){
for (int j=1; j<Ny-1; j++){
for (int i=1; i<Nx-1; i++){
// Compute velocity gradients using finite differences
double phi = Phi(i,j,k);
double nu = nu_n + 0.5*(1.0-phi)*(nu_w-nu_n);
double rho = rho_n + 0.5*(1.0-phi)*(rho_w-rho_n);
double ux = 0.5*(Vel_x(i+1,j,k) - Vel_x(i-1,j,k));
double uy = 0.5*(Vel_x(i,j+1,k) - Vel_x(i,j-1,k));
double uz = 0.5*(Vel_x(i,j,k+1) - Vel_x(i,j,k-1));
double vx = 0.5*(Vel_y(i+1,j,k) - Vel_y(i-1,j,k));
double vy = 0.5*(Vel_y(i,j+1,k) - Vel_y(i,j-1,k));
double vz = 0.5*(Vel_y(i,j,k+1) - Vel_y(i,j,k-1));
double wx = 0.5*(Vel_z(i+1,j,k) - Vel_z(i-1,j,k));
double wy = 0.5*(Vel_z(i,j+1,k) - Vel_z(i,j-1,k));
double wz = 0.5*(Vel_z(i,j,k+1) - Vel_z(i,j,k-1));
if (SDs(i,j,k) > 2.0){
Dissipation(i,j,k) = 2*rho*nu*( ux*ux + vy*vy + wz*wz + 0.5*(vx + uy)*(vx + uy)+ 0.5*(vz + wy)*(vz + wy)+ 0.5*(uz + wx)*(uz + wx));
}
}
}
}
/* Set up geometric analysis of each region */
@@ -556,13 +427,13 @@ void SubPhase::Full(){
}
}
// measure the whole object
morph_n->MeasureObject();//0.5/beta,Phi);
morph_n->MeasureObject();
nd.V = morph_n->V();
nd.A = morph_n->A();
nd.H = morph_n->H();
nd.X = morph_n->X();
// measure only the connected part
nd.Nc = morph_n->MeasureConnectedPathway();//0.5/beta,Phi);
nd.Nc = morph_n->MeasureConnectedPathway();
nc.V = morph_n->V();
nc.A = morph_n->A();
nc.H = morph_n->H();
@@ -574,14 +445,14 @@ void SubPhase::Full(){
nd.X -= nc.X;
// compute global entities
gnc.V=Dm->Comm.sumReduce( nc.V);
gnc.A=Dm->Comm.sumReduce( nc.A);
gnc.H=Dm->Comm.sumReduce( nc.H);
gnc.X=Dm->Comm.sumReduce( nc.X);
gnd.V=Dm->Comm.sumReduce( nd.V);
gnd.A=Dm->Comm.sumReduce( nd.A);
gnd.H=Dm->Comm.sumReduce( nd.H);
gnd.X=Dm->Comm.sumReduce( nd.X);
gnc.V=sumReduce( Dm->Comm, nc.V);
gnc.A=sumReduce( Dm->Comm, nc.A);
gnc.H=sumReduce( Dm->Comm, nc.H);
gnc.X=sumReduce( Dm->Comm, nc.X);
gnd.V=sumReduce( Dm->Comm, nd.V);
gnd.A=sumReduce( Dm->Comm, nd.A);
gnd.H=sumReduce( Dm->Comm, nd.H);
gnd.X=sumReduce( Dm->Comm, nd.X);
gnd.Nc = nd.Nc;
// wetting
for (k=0; k<Nz; k++){
@@ -604,13 +475,13 @@ void SubPhase::Full(){
}
}
}
morph_w->MeasureObject();//-0.5/beta,Phi);
morph_w->MeasureObject();
wd.V = morph_w->V();
wd.A = morph_w->A();
wd.H = morph_w->H();
wd.X = morph_w->X();
// measure only the connected part
wd.Nc = morph_w->MeasureConnectedPathway();//-0.5/beta,Phi);
wd.Nc = morph_w->MeasureConnectedPathway();
wc.V = morph_w->V();
wc.A = morph_w->A();
wc.H = morph_w->H();
@@ -621,14 +492,14 @@ void SubPhase::Full(){
wd.H -= wc.H;
wd.X -= wc.X;
// compute global entities
gwc.V=Dm->Comm.sumReduce( wc.V);
gwc.A=Dm->Comm.sumReduce( wc.A);
gwc.H=Dm->Comm.sumReduce( wc.H);
gwc.X=Dm->Comm.sumReduce( wc.X);
gwd.V=Dm->Comm.sumReduce( wd.V);
gwd.A=Dm->Comm.sumReduce( wd.A);
gwd.H=Dm->Comm.sumReduce( wd.H);
gwd.X=Dm->Comm.sumReduce( wd.X);
gwc.V=sumReduce( Dm->Comm, wc.V);
gwc.A=sumReduce( Dm->Comm, wc.A);
gwc.H=sumReduce( Dm->Comm, wc.H);
gwc.X=sumReduce( Dm->Comm, wc.X);
gwd.V=sumReduce( Dm->Comm, wd.V);
gwd.A=sumReduce( Dm->Comm, wd.A);
gwd.H=sumReduce( Dm->Comm, wd.H);
gwd.X=sumReduce( Dm->Comm, wd.X);
gwd.Nc = wd.Nc;
/* Set up geometric analysis of interface region */
@@ -656,20 +527,20 @@ void SubPhase::Full(){
iwn.A = morph_i->A();
iwn.H = morph_i->H();
iwn.X = morph_i->X();
giwn.V=Dm->Comm.sumReduce( iwn.V);
giwn.A=Dm->Comm.sumReduce( iwn.A);
giwn.H=Dm->Comm.sumReduce( iwn.H);
giwn.X=Dm->Comm.sumReduce( iwn.X);
giwn.V=sumReduce( Dm->Comm, iwn.V);
giwn.A=sumReduce( Dm->Comm, iwn.A);
giwn.H=sumReduce( Dm->Comm, iwn.H);
giwn.X=sumReduce( Dm->Comm, iwn.X);
// measure only the connected part
iwnc.Nc = morph_i->MeasureConnectedPathway();
iwnc.V = morph_i->V();
iwnc.A = morph_i->A();
iwnc.H = morph_i->H();
iwnc.X = morph_i->X();
giwnc.V=Dm->Comm.sumReduce( iwnc.V);
giwnc.A=Dm->Comm.sumReduce( iwnc.A);
giwnc.H=Dm->Comm.sumReduce( iwnc.H);
giwnc.X=Dm->Comm.sumReduce( iwnc.X);
giwnc.V=sumReduce( Dm->Comm, iwnc.V);
giwnc.A=sumReduce( Dm->Comm, iwnc.A);
giwnc.H=sumReduce( Dm->Comm, iwnc.H);
giwnc.X=sumReduce( Dm->Comm, iwnc.X);
giwnc.Nc = iwnc.Nc;
double vol_nc_bulk = 0.0;
@@ -689,33 +560,13 @@ void SubPhase::Full(){
double ux = Vel_x(n);
double uy = Vel_y(n);
double uz = Vel_z(n);
double visc = Dissipation(n);
if (DelPhi(n) > 1e-3 ){
// get the normal vector
if (DelPhi(n) > 1e-3){
// interface region
double nx = 0.5*(Phi(i+1,j,k)-Phi(i-1,j,k));
double ny = 0.5*(Phi(i,j+1,k)-Phi(i,j-1,k));
double nz = 0.5*(Phi(i,j,k+1)-Phi(i,j,k-1));
if (SDs(n) > 2.5){
// not a film region
InterfaceTransportMeasures( beta, rho_w, rho_n, nA, nB, nx, ny, nz, ux, uy, uz, iwn);
}
else{
// films that are close to the wetting fluid
if ( morph_w->distance(i,j,k) < 2.5 && phi > 0.0){
ifs.Mw += rho_w;
ifs.Pwx += rho_w*ux;
ifs.Pwy += rho_w*uy;
ifs.Pwz += rho_w*uz;
}
// films that are close to the NWP
if ( morph_n->distance(i,j,k) < 2.5 && phi < 0.0){
ifs.Mn += rho_n;
ifs.Pnx += rho_n*ux;
ifs.Pny += rho_n*uy;
ifs.Pnz += rho_n*uz;
}
}
InterfaceTransportMeasures( beta, rho_w, rho_n, nA, nB, nx, ny, nz, ux, uy, uz, iwn);
}
else if ( phi > 0.0){
if (morph_n->label(i,j,k) > 0 ){
@@ -746,7 +597,6 @@ void SubPhase::Full(){
nd.Py += nA*rho_n*uy;
nd.Pz += nA*rho_n*uz;
nd.K += nA*rho_n*(ux*ux + uy*uy + uz*uz);
nd.visc += visc;
}
else{
nA = 1.0;
@@ -755,7 +605,6 @@ void SubPhase::Full(){
nc.Py += nA*rho_n*uy;
nc.Pz += nA*rho_n*uz;
nc.K += nA*rho_n*(ux*ux + uy*uy + uz*uz);
nc.visc += visc;
}
}
else{
@@ -767,7 +616,6 @@ void SubPhase::Full(){
wd.Py += nB*rho_w*uy;
wd.Pz += nB*rho_w*uz;
wd.K += nB*rho_w*(ux*ux + uy*uy + uz*uz);
wd.visc += visc;
}
else{
nB = 1.0;
@@ -776,7 +624,6 @@ void SubPhase::Full(){
wc.Py += nB*rho_w*uy;
wc.Pz += nB*rho_w*uz;
wc.K += nB*rho_w*(ux*ux + uy*uy + uz*uz);
wc.visc += visc;
}
}
}
@@ -784,59 +631,46 @@ void SubPhase::Full(){
}
}
gnd.M=Dm->Comm.sumReduce( nd.M);
gnd.Px=Dm->Comm.sumReduce( nd.Px);
gnd.Py=Dm->Comm.sumReduce( nd.Py);
gnd.Pz=Dm->Comm.sumReduce( nd.Pz);
gnd.K=Dm->Comm.sumReduce( nd.K);
gnd.visc=Dm->Comm.sumReduce( nd.visc);
gnd.M=sumReduce( Dm->Comm, nd.M);
gnd.Px=sumReduce( Dm->Comm, nd.Px);
gnd.Py=sumReduce( Dm->Comm, nd.Py);
gnd.Pz=sumReduce( Dm->Comm, nd.Pz);
gnd.K=sumReduce( Dm->Comm, nd.K);
gwd.M=Dm->Comm.sumReduce( wd.M);
gwd.Px=Dm->Comm.sumReduce( wd.Px);
gwd.Py=Dm->Comm.sumReduce( wd.Py);
gwd.Pz=Dm->Comm.sumReduce( wd.Pz);
gwd.K=Dm->Comm.sumReduce( wd.K);
gwd.visc=Dm->Comm.sumReduce( wd.visc);
gwd.M=sumReduce( Dm->Comm, wd.M);
gwd.Px=sumReduce( Dm->Comm, wd.Px);
gwd.Py=sumReduce( Dm->Comm, wd.Py);
gwd.Pz=sumReduce( Dm->Comm, wd.Pz);
gwd.K=sumReduce( Dm->Comm, wd.K);
gnc.M=Dm->Comm.sumReduce( nc.M);
gnc.Px=Dm->Comm.sumReduce( nc.Px);
gnc.Py=Dm->Comm.sumReduce( nc.Py);
gnc.Pz=Dm->Comm.sumReduce( nc.Pz);
gnc.K=Dm->Comm.sumReduce( nc.K);
gnc.visc=Dm->Comm.sumReduce( nc.visc);
gnc.M=sumReduce( Dm->Comm, nc.M);
gnc.Px=sumReduce( Dm->Comm, nc.Px);
gnc.Py=sumReduce( Dm->Comm, nc.Py);
gnc.Pz=sumReduce( Dm->Comm, nc.Pz);
gnc.K=sumReduce( Dm->Comm, nc.K);
gwc.M=Dm->Comm.sumReduce( wc.M);
gwc.Px=Dm->Comm.sumReduce( wc.Px);
gwc.Py=Dm->Comm.sumReduce( wc.Py);
gwc.Pz=Dm->Comm.sumReduce( wc.Pz);
gwc.K=Dm->Comm.sumReduce( wc.K);
gwc.visc=Dm->Comm.sumReduce( wc.visc);
giwn.Mn=Dm->Comm.sumReduce( iwn.Mn);
giwn.Pnx=Dm->Comm.sumReduce( iwn.Pnx);
giwn.Pny=Dm->Comm.sumReduce( iwn.Pny);
giwn.Pnz=Dm->Comm.sumReduce( iwn.Pnz);
giwn.Kn=Dm->Comm.sumReduce( iwn.Kn);
giwn.Mw=Dm->Comm.sumReduce( iwn.Mw);
giwn.Pwx=Dm->Comm.sumReduce( iwn.Pwx);
giwn.Pwy=Dm->Comm.sumReduce( iwn.Pwy);
giwn.Pwz=Dm->Comm.sumReduce( iwn.Pwz);
giwn.Kw=Dm->Comm.sumReduce( iwn.Kw);
gwc.M=sumReduce( Dm->Comm, wc.M);
gwc.Px=sumReduce( Dm->Comm, wc.Px);
gwc.Py=sumReduce( Dm->Comm, wc.Py);
gwc.Pz=sumReduce( Dm->Comm, wc.Pz);
gwc.K=sumReduce( Dm->Comm, wc.K);
gifs.Mn= Dm->Comm.sumReduce( ifs.Mn);
gifs.Pnx=Dm->Comm.sumReduce( ifs.Pnx);
gifs.Pny=Dm->Comm.sumReduce( ifs.Pny);
gifs.Pnz=Dm->Comm.sumReduce( ifs.Pnz);
gifs.Mw= Dm->Comm.sumReduce( ifs.Mw);
gifs.Pwx=Dm->Comm.sumReduce( ifs.Pwx);
gifs.Pwy=Dm->Comm.sumReduce( ifs.Pwy);
gifs.Pwz=Dm->Comm.sumReduce( ifs.Pwz);
giwn.Mn=sumReduce( Dm->Comm, iwn.Mn);
giwn.Pnx=sumReduce( Dm->Comm, iwn.Pnx);
giwn.Pny=sumReduce( Dm->Comm, iwn.Pny);
giwn.Pnz=sumReduce( Dm->Comm, iwn.Pnz);
giwn.Kn=sumReduce( Dm->Comm, iwn.Kn);
giwn.Mw=sumReduce( Dm->Comm, iwn.Mw);
giwn.Pwx=sumReduce( Dm->Comm, iwn.Pwx);
giwn.Pwy=sumReduce( Dm->Comm, iwn.Pwy);
giwn.Pwz=sumReduce( Dm->Comm, iwn.Pwz);
giwn.Kw=sumReduce( Dm->Comm, iwn.Kw);
// pressure averaging
gnc.p=Dm->Comm.sumReduce( nc.p);
gnd.p=Dm->Comm.sumReduce( nd.p);
gwc.p=Dm->Comm.sumReduce( wc.p);
gwd.p=Dm->Comm.sumReduce( wd.p);
gnc.p=sumReduce( Dm->Comm, nc.p);
gnd.p=sumReduce( Dm->Comm, nd.p);
gwc.p=sumReduce( Dm->Comm, wc.p);
gwd.p=sumReduce( Dm->Comm, wd.p);
if (vol_wc_bulk > 0.0)
wc.p = wc.p /vol_wc_bulk;
@@ -847,10 +681,10 @@ void SubPhase::Full(){
if (vol_nd_bulk > 0.0)
nd.p = nd.p /vol_nd_bulk;
vol_wc_bulk=Dm->Comm.sumReduce( vol_wc_bulk);
vol_wd_bulk=Dm->Comm.sumReduce( vol_wd_bulk);
vol_nc_bulk=Dm->Comm.sumReduce( vol_nc_bulk);
vol_nd_bulk=Dm->Comm.sumReduce( vol_nd_bulk);
vol_wc_bulk=sumReduce( Dm->Comm, vol_wc_bulk);
vol_wd_bulk=sumReduce( Dm->Comm, vol_wd_bulk);
vol_nc_bulk=sumReduce( Dm->Comm, vol_nc_bulk);
vol_nd_bulk=sumReduce( Dm->Comm, vol_nd_bulk);
if (vol_wc_bulk > 0.0)
gwc.p = gwc.p /vol_wc_bulk;
@@ -863,8 +697,7 @@ void SubPhase::Full(){
}
void SubPhase::AggregateLabels( const std::string& filename )
{
void SubPhase::AggregateLabels(char *FILENAME){
int nx = Dm->Nx;
int ny = Dm->Ny;
@@ -886,9 +719,9 @@ void SubPhase::AggregateLabels( const std::string& filename )
}
}
}
Dm->Comm.barrier();
MPI_Barrier(Dm->Comm);
Dm->AggregateLabels( filename );
Dm->AggregateLabels(FILENAME);
}

View File

@@ -12,7 +12,7 @@
#include "analysis/distance.h"
#include "analysis/Minkowski.h"
#include "common/Utilities.h"
#include "common/MPI.h"
#include "common/MPI_Helpers.h"
#include "IO/MeshDatabase.h"
#include "IO/Reader.h"
#include "IO/Writer.h"
@@ -22,11 +22,10 @@ class phase{
public:
int Nc;
double p;
double M,Px,Py,Pz,K,visc;
double M,Px,Py,Pz,K;
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;
}
@@ -69,18 +68,12 @@ public:
* b - bulk (total)
*/
// local entities
phase wc,wd,wb,nc,nd,nb,solid;
phase wc,wd,wb,nc,nd,nb;
interface iwn,iwnc;
interface ifs;
// global entities
phase gwc,gwd,gwb,gnc,gnd,gnb,gsolid;
phase gwc,gwd,gwb,gnc,gnd,gnb;
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;
//...........................................................................
int Nx,Ny,Nz;
IntArray PhaseID; // Phase ID array (solid=0, non-wetting=1, wetting=2)
@@ -95,7 +88,6 @@ public:
DoubleArray Vel_x; // velocity field
DoubleArray Vel_y;
DoubleArray Vel_z;
DoubleArray Dissipation;
DoubleArray SDs;
std::shared_ptr<Minkowski> morph_w;
@@ -109,7 +101,7 @@ public:
void Basic();
void Full();
void Write(int time);
void AggregateLabels( const std::string& filename );
void AggregateLabels(char *FILENAME);
private:
FILE *TIMELOG;

View File

@@ -1,6 +1,5 @@
/*
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
@@ -16,7 +15,6 @@
*/
/*
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
@@ -37,7 +35,7 @@
#include "common/Domain.h"
#include "common/Communication.h"
#include "common/Utilities.h"
#include "common/MPI.h"
#include "common/MPI_Helpers.h"
#include "IO/MeshDatabase.h"
#include "IO/Reader.h"
#include "IO/Writer.h"
@@ -236,7 +234,6 @@ TwoPhase::~TwoPhase()
void TwoPhase::ColorToSignedDistance(double Beta, DoubleArray &ColorData, DoubleArray &DistData)
{
NULL_USE( Beta );
/*double factor,temp,value;
factor=0.5/Beta;
// Initialize to -1,1 (segmentation)
@@ -660,8 +657,8 @@ void TwoPhase::ComputeLocal()
void TwoPhase::AssignComponentLabels()
{
//int LabelNWP=1;
//int LabelWP=2;
int LabelNWP=1;
int LabelWP=2;
// NOTE: labeling the wetting phase components is tricky! One sandstone media had over 800,000 components
// NumberComponents_WP = ComputeGlobalPhaseComponent(Dm->Nx-2,Dm->Ny-2,Dm->Nz-2,Dm->rank_info,PhaseID,LabelWP,Label_WP);
// treat all wetting phase is connected
@@ -914,7 +911,7 @@ void TwoPhase::ComponentAverages()
}
}
Dm->Comm.barrier();
MPI_Barrier(Dm->Comm);
if (Dm->rank()==0){
printf("Component averages computed locally -- reducing result... \n");
}
@@ -922,14 +919,14 @@ void TwoPhase::ComponentAverages()
RecvBuffer.resize(BLOB_AVG_COUNT,NumberComponents_NWP);
/* for (int b=0; b<NumberComponents_NWP; b++){
Dm->Comm.barrier();
Dm->Comm.sumReduce(&ComponentAverages_NWP(0,b),&RecvBuffer(0),BLOB_AVG_COUNT);
MPI_Barrier(Dm->Comm);
MPI_Allreduce(&ComponentAverages_NWP(0,b),&RecvBuffer(0),BLOB_AVG_COUNT,MPI_DOUBLE,MPI_SUM,Dm->Comm);
for (int idx=0; idx<BLOB_AVG_COUNT; idx++) ComponentAverages_NWP(idx,b)=RecvBuffer(idx);
}
*/
Dm->Comm.barrier();
Dm->Comm.sumReduce(ComponentAverages_NWP.data(),RecvBuffer.data(),BLOB_AVG_COUNT*NumberComponents_NWP);
// Dm->Comm.sumReduce(ComponentAverages_NWP.data(),RecvBuffer.data(),BLOB_AVG_COUNT);
MPI_Barrier(Dm->Comm);
MPI_Allreduce(ComponentAverages_NWP.data(),RecvBuffer.data(),BLOB_AVG_COUNT*NumberComponents_NWP, MPI_DOUBLE,MPI_SUM,Dm->Comm);
// MPI_Reduce(ComponentAverages_NWP.data(),RecvBuffer.data(),BLOB_AVG_COUNT,MPI_DOUBLE,MPI_SUM,0,Dm->Comm);
if (Dm->rank()==0){
printf("rescaling... \n");
@@ -1025,8 +1022,9 @@ void TwoPhase::ComponentAverages()
// reduce the wetting phase averages
for (int b=0; b<NumberComponents_WP; b++){
Dm->Comm.barrier();
Dm->Comm.sumReduce(&ComponentAverages_WP(0,b),RecvBuffer.data(),BLOB_AVG_COUNT);
MPI_Barrier(Dm->Comm);
// MPI_Allreduce(&ComponentAverages_WP(0,b),RecvBuffer.data(),BLOB_AVG_COUNT,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Reduce(&ComponentAverages_WP(0,b),RecvBuffer.data(),BLOB_AVG_COUNT,MPI_DOUBLE,MPI_SUM,0,Dm->Comm);
for (int idx=0; idx<BLOB_AVG_COUNT; idx++) ComponentAverages_WP(idx,b)=RecvBuffer(idx);
}
@@ -1109,48 +1107,43 @@ void TwoPhase::Reduce()
int i;
double iVol_global=1.0/Volume;
//...........................................................................
Dm->Comm.barrier();
nwp_volume_global = Dm->Comm.sumReduce( nwp_volume );
wp_volume_global = Dm->Comm.sumReduce( wp_volume );
awn_global = Dm->Comm.sumReduce( awn );
ans_global = Dm->Comm.sumReduce( ans );
aws_global = Dm->Comm.sumReduce( aws );
lwns_global = Dm->Comm.sumReduce( lwns );
As_global = Dm->Comm.sumReduce( As );
Jwn_global = Dm->Comm.sumReduce( Jwn );
Kwn_global = Dm->Comm.sumReduce( Kwn );
KGwns_global = Dm->Comm.sumReduce( KGwns );
KNwns_global = Dm->Comm.sumReduce( KNwns );
efawns_global = Dm->Comm.sumReduce( efawns );
wwndnw_global = Dm->Comm.sumReduce( wwndnw );
wwnsdnwn_global = Dm->Comm.sumReduce( wwnsdnwn );
Jwnwwndnw_global = Dm->Comm.sumReduce( Jwnwwndnw );
MPI_Barrier(Dm->Comm);
MPI_Allreduce(&nwp_volume,&nwp_volume_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&wp_volume,&wp_volume_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&awn,&awn_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&ans,&ans_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&aws,&aws_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&lwns,&lwns_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&As,&As_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&Jwn,&Jwn_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&Kwn,&Kwn_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&KGwns,&KGwns_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&KNwns,&KNwns_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&efawns,&efawns_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&wwndnw,&wwndnw_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&wwnsdnwn,&wwnsdnwn_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&Jwnwwndnw,&Jwnwwndnw_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
// Phase averages
vol_w_global = Dm->Comm.sumReduce( vol_w );
vol_n_global = Dm->Comm.sumReduce( vol_n );
paw_global = Dm->Comm.sumReduce( paw );
pan_global = Dm->Comm.sumReduce( pan );
for (int idx=0; idx<3; idx++)
vaw_global(idx) = Dm->Comm.sumReduce( vaw(idx) );
for (int idx=0; idx<3; idx++)
van_global(idx) = Dm->Comm.sumReduce( van(idx));
for (int idx=0; idx<3; idx++)
vawn_global(idx) = Dm->Comm.sumReduce( vawn(idx) );
for (int idx=0; idx<3; idx++)
vawns_global(idx) = Dm->Comm.sumReduce( vawns(idx) );
for (int idx=0; idx<6; idx++){
Gwn_global(idx) = Dm->Comm.sumReduce( Gwn(idx) );
Gns_global(idx) = Dm->Comm.sumReduce( Gns(idx) );
Gws_global(idx) = Dm->Comm.sumReduce( Gws(idx) );
}
trawn_global = Dm->Comm.sumReduce( trawn );
trJwn_global = Dm->Comm.sumReduce( trJwn );
trRwn_global = Dm->Comm.sumReduce( trRwn );
euler_global = Dm->Comm.sumReduce( euler );
An_global = Dm->Comm.sumReduce( An );
Jn_global = Dm->Comm.sumReduce( Jn );
Kn_global = Dm->Comm.sumReduce( Kn );
Dm->Comm.barrier();
MPI_Allreduce(&vol_w,&vol_w_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&vol_n,&vol_n_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&paw,&paw_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&pan,&pan_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&vaw(0),&vaw_global(0),3,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&van(0),&van_global(0),3,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&vawn(0),&vawn_global(0),3,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&vawns(0),&vawns_global(0),3,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&Gwn(0),&Gwn_global(0),6,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&Gns(0),&Gns_global(0),6,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&Gws(0),&Gws_global(0),6,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&trawn,&trawn_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&trJwn,&trJwn_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&trRwn,&trRwn_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&euler,&euler_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&An,&An_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&Jn,&Jn_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Allreduce(&Kn,&Kn_global,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
MPI_Barrier(Dm->Comm);
// Normalize the phase averages
// (density of both components = 1.0)
@@ -1209,8 +1202,6 @@ void TwoPhase::Reduce()
void TwoPhase::NonDimensionalize(double D, double viscosity, double IFT)
{
NULL_USE( viscosity );
NULL_USE( IFT );
awn_global *= D;
ans_global *= D;
ans_global *= D;

View File

@@ -1,6 +1,5 @@
/*
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
@@ -28,7 +27,7 @@
#include "common/Domain.h"
#include "common/Communication.h"
#include "common/Utilities.h"
#include "common/MPI.h"
#include "common/MPI_Helpers.h"
#include "IO/MeshDatabase.h"
#include "IO/Reader.h"
#include "IO/Writer.h"

View File

@@ -1,6 +1,5 @@
/*
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
@@ -204,7 +203,7 @@ int ComputeLocalPhaseComponent(const IntArray &PhaseID, int &VALUE, BlobIDArray
/******************************************************************
* Reorder the global blob ids *
******************************************************************/
static int ReorderBlobIDs2( BlobIDArray& ID, int N_blobs, int ngx, int ngy, int ngz, const Utilities::MPI& comm )
static int ReorderBlobIDs2( BlobIDArray& ID, int N_blobs, int ngx, int ngy, int ngz, MPI_Comm comm )
{
if ( N_blobs==0 )
return 0;
@@ -228,7 +227,7 @@ static int ReorderBlobIDs2( BlobIDArray& ID, int N_blobs, int ngx, int ngy, int
}
}
ASSERT(max_id<N_blobs);
comm.sumReduce(local_size,global_size,N_blobs);
MPI_Allreduce(local_size,global_size,N_blobs,MPI_DOUBLE,MPI_SUM,comm);
std::vector<std::pair<double,int> > map1(N_blobs);
int N_blobs2 = 0;
for (int i=0; i<N_blobs; i++) {
@@ -251,12 +250,12 @@ static int ReorderBlobIDs2( BlobIDArray& ID, int N_blobs, int ngx, int ngy, int
PROFILE_STOP("ReorderBlobIDs2",1);
return N_blobs2;
}
void ReorderBlobIDs( BlobIDArray& ID, const Utilities::MPI& comm )
void ReorderBlobIDs( BlobIDArray& ID, MPI_Comm comm )
{
PROFILE_START("ReorderBlobIDs");
int tmp = ID.max()+1;
int N_blobs = 0;
N_blobs = comm.maxReduce( tmp );
MPI_Allreduce(&tmp,&N_blobs,1,MPI_INT,MPI_MAX,comm);
ReorderBlobIDs2(ID,N_blobs,1,1,1,comm);
PROFILE_STOP("ReorderBlobIDs");
}
@@ -276,29 +275,30 @@ static void updateRemoteIds(
int N_send, const std::vector<int>& N_recv,
int64_t *send_buf, std::vector<int64_t*>& recv_buf,
std::map<int64_t,int64_t>& remote_map,
const Utilities::MPI& comm )
MPI_Comm comm )
{
std::vector<MPI_Request> send_req(neighbors.size());
std::vector<MPI_Request> recv_req(neighbors.size());
auto it = map.begin();
std::vector<MPI_Status> status(neighbors.size());
std::map<int64_t,global_id_info_struct>::const_iterator it = map.begin();
ASSERT(N_send==(int)map.size());
for (size_t i=0; i<map.size(); i++, ++it) {
send_buf[2*i+0] = it->first;
send_buf[2*i+1] = it->second.new_id;
}
for (size_t i=0; i<neighbors.size(); i++) {
send_req[i] = comm.Isend( send_buf, 2*N_send, neighbors[i], 0 );
recv_req[i] = comm.Irecv( recv_buf[i], 2*N_recv[i], neighbors[i], 0 );
MPI_Isend( send_buf, 2*N_send, MPI_LONG_LONG, neighbors[i], 0, comm, &send_req[i] );
MPI_Irecv( recv_buf[i], 2*N_recv[i], MPI_LONG_LONG, neighbors[i], 0, comm, &recv_req[i] );
}
for (it=map.begin(); it!=map.end(); ++it) {
remote_map[it->first] = it->second.new_id;
}
for (size_t i=0; i<neighbors.size(); i++) {
comm.wait( recv_req[i] );
MPI_Wait(&recv_req[i],&status[i]);
for (int j=0; j<N_recv[i]; j++)
remote_map[recv_buf[i][2*j+0]] = recv_buf[i][2*j+1];
}
comm.waitAll(neighbors.size(),getPtr(send_req));
MPI_Waitall(neighbors.size(),getPtr(send_req),getPtr(status));
}
// Compute a new local id for each local id
static bool updateLocalIds( const std::map<int64_t,int64_t>& remote_map,
@@ -319,18 +319,18 @@ static bool updateLocalIds( const std::map<int64_t,int64_t>& remote_map,
return changed;
}
static int LocalToGlobalIDs( int nx, int ny, int nz, const RankInfoStruct& rank_info,
int nblobs, BlobIDArray& IDs, const Utilities::MPI& comm )
int nblobs, BlobIDArray& IDs, MPI_Comm comm )
{
PROFILE_START("LocalToGlobalIDs",1);
const int rank = rank_info.rank[1][1][1];
int nprocs = comm.getSize();
int nprocs = comm_size(comm);
const int ngx = (IDs.size(0)-nx)/2;
const int ngy = (IDs.size(1)-ny)/2;
const int ngz = (IDs.size(2)-nz)/2;
// Get the number of blobs for each rank
std::vector<int> N_blobs(nprocs,0);
PROFILE_START("LocalToGlobalIDs-Allgather",1);
comm.allGather(nblobs,getPtr(N_blobs));
MPI_Allgather(&nblobs,1,MPI_INT,getPtr(N_blobs),1,MPI_INT,comm);
PROFILE_STOP("LocalToGlobalIDs-Allgather",1);
int64_t N_blobs_tot = 0;
int offset = 0;
@@ -378,12 +378,13 @@ static int LocalToGlobalIDs( int nx, int ny, int nz, const RankInfoStruct& rank_
std::vector<int> N_recv(neighbors.size(),0);
std::vector<MPI_Request> send_req(neighbors.size());
std::vector<MPI_Request> recv_req(neighbors.size());
std::vector<MPI_Status> status(neighbors.size());
for (size_t i=0; i<neighbors.size(); i++) {
send_req[i] = comm.Isend( &N_send, 1, neighbors[i], 0 );
recv_req[i] = comm.Irecv( &N_recv[i], 1, neighbors[i], 0 );
MPI_Isend( &N_send, 1, MPI_INT, neighbors[i], 0, comm, &send_req[i] );
MPI_Irecv( &N_recv[i], 1, MPI_INT, neighbors[i], 0, comm, &recv_req[i] );
}
comm.waitAll(neighbors.size(),getPtr(send_req));
comm.waitAll(neighbors.size(),getPtr(recv_req));
MPI_Waitall(neighbors.size(),getPtr(send_req),getPtr(status));
MPI_Waitall(neighbors.size(),getPtr(recv_req),getPtr(status));
// Allocate memory for communication
int64_t *send_buf = new int64_t[2*N_send];
std::vector<int64_t*> recv_buf(neighbors.size());
@@ -412,7 +413,8 @@ static int LocalToGlobalIDs( int nx, int ny, int nz, const RankInfoStruct& rank_
bool changed = updateLocalIds( remote_map, map );
// Check if we are finished
int test = changed ? 1:0;
int result = comm.sumReduce( test );
int result = 0;
MPI_Allreduce(&test,&result,1,MPI_INT,MPI_SUM,comm);
if ( result==0 )
break;
}
@@ -448,7 +450,7 @@ static int LocalToGlobalIDs( int nx, int ny, int nz, const RankInfoStruct& rank_
}
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 )
BlobIDArray& GlobalBlobID, MPI_Comm comm )
{
PROFILE_START("ComputeGlobalBlobIDs");
// First compute the local ids
@@ -459,7 +461,7 @@ int ComputeGlobalBlobIDs( int nx, int ny, int nz, const RankInfoStruct& rank_inf
return nglobal;
}
int ComputeGlobalPhaseComponent( int nx, int ny, int nz, const RankInfoStruct& rank_info,
const IntArray &PhaseID, int &VALUE, BlobIDArray &GlobalBlobID, const Utilities::MPI& comm )
const IntArray &PhaseID, int &VALUE, BlobIDArray &GlobalBlobID, MPI_Comm comm )
{
PROFILE_START("ComputeGlobalPhaseComponent");
// First compute the local ids
@@ -475,27 +477,37 @@ int ComputeGlobalPhaseComponent( int nx, int ny, int nz, const RankInfoStruct& r
* Compute the mapping of blob ids between timesteps *
******************************************************************/
typedef std::map<BlobIDType,std::map<BlobIDType,int64_t> > map_type;
template<class TYPE> inline MPI_Datatype getMPIType();
template<> inline MPI_Datatype getMPIType<int32_t>() { return MPI_INT; }
template<> inline MPI_Datatype getMPIType<int64_t>() {
if ( sizeof(int64_t)==sizeof(long int) )
return MPI_LONG;
else if ( sizeof(int64_t)==sizeof(double) )
return MPI_DOUBLE;
}
template<class TYPE>
void gatherSet( std::set<TYPE>& set, const Utilities::MPI& comm )
void gatherSet( std::set<TYPE>& set, MPI_Comm comm )
{
int nprocs = comm.getSize();
int nprocs = comm_size(comm);
MPI_Datatype type = getMPIType<TYPE>();
std::vector<TYPE> send_data(set.begin(),set.end());
int send_count = send_data.size();
std::vector<int> recv_count(nprocs,0), recv_disp(nprocs,0);
comm.allGather( send_count, getPtr(recv_count) );
MPI_Allgather(&send_count,1,MPI_INT,getPtr(recv_count),1,MPI_INT,comm);
for (int i=1; i<nprocs; i++)
recv_disp[i] = recv_disp[i-1] + recv_count[i-1];
std::vector<TYPE> recv_data(recv_disp[nprocs-1]+recv_count[nprocs-1]);
comm.allGather( getPtr(send_data), send_count, getPtr(recv_data),
getPtr(recv_count), getPtr(recv_disp), true );
MPI_Allgatherv(getPtr(send_data),send_count,type,
getPtr(recv_data),getPtr(recv_count),getPtr(recv_disp),type,comm);
for (size_t i=0; i<recv_data.size(); i++)
set.insert(recv_data[i]);
}
void gatherSrcIDMap( map_type& src_map, const Utilities::MPI& comm )
void gatherSrcIDMap( map_type& src_map, MPI_Comm comm )
{
int nprocs = comm.getSize();
int nprocs = comm_size(comm);
MPI_Datatype type = getMPIType<int64_t>();
std::vector<int64_t> send_data;
for (auto it=src_map.begin(); it!=src_map.end(); ++it) {
for (map_type::const_iterator it=src_map.begin(); it!=src_map.end(); ++it) {
int id = it->first;
const std::map<BlobIDType,int64_t>& src_ids = it->second;
send_data.push_back(id);
@@ -508,21 +520,21 @@ void gatherSrcIDMap( map_type& src_map, const Utilities::MPI& comm )
}
int send_count = send_data.size();
std::vector<int> recv_count(nprocs,0), recv_disp(nprocs,0);
comm.allGather(send_count,getPtr(recv_count));
MPI_Allgather(&send_count,1,MPI_INT,getPtr(recv_count),1,MPI_INT,comm);
for (int i=1; i<nprocs; i++)
recv_disp[i] = recv_disp[i-1] + recv_count[i-1];
std::vector<int64_t> recv_data(recv_disp[nprocs-1]+recv_count[nprocs-1]);
comm.allGather(getPtr(send_data),send_count,
getPtr(recv_data),getPtr(recv_count),getPtr(recv_disp),true);
MPI_Allgatherv(getPtr(send_data),send_count,type,
getPtr(recv_data),getPtr(recv_count),getPtr(recv_disp),type,comm);
size_t i=0;
src_map.clear();
while ( i < recv_data.size() ) {
BlobIDType id = recv_data[i];
size_t count = recv_data[i+1];
i += 2;
auto& src_ids = src_map[id];
std::map<BlobIDType,int64_t>& src_ids = src_map[id];
for (size_t j=0; j<count; j++,i+=2) {
auto it = src_ids.find(recv_data[i]);
std::map<BlobIDType,int64_t>::iterator it = src_ids.find(recv_data[i]);
if ( it == src_ids.end() )
src_ids.insert(std::pair<BlobIDType,int64_t>(recv_data[i],recv_data[i+1]));
else
@@ -541,7 +553,7 @@ void addSrcDstIDs( BlobIDType src_id, map_type& src_map, map_type& dst_map,
}
}
ID_map_struct computeIDMap( int nx, int ny, int nz,
const BlobIDArray& ID1, const BlobIDArray& ID2, const Utilities::MPI& comm )
const BlobIDArray& ID1, const BlobIDArray& ID2, MPI_Comm comm )
{
ASSERT(ID1.size()==ID2.size());
PROFILE_START("computeIDMap");
@@ -783,7 +795,7 @@ void renumberIDs( const std::vector<BlobIDType>& new_ids, BlobIDArray& IDs )
******************************************************************/
void writeIDMap( const ID_map_struct& map, long long int timestep, const std::string& filename )
{
int rank = Utilities::MPI( MPI_COMM_WORLD ).getRank();
int rank = MPI_WORLD_RANK();
if ( rank!=0 )
return;
bool empty = map.created.empty() && map.destroyed.empty() &&

View File

@@ -1,6 +1,5 @@
/*
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
@@ -38,8 +37,8 @@ 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,
@@ -64,18 +63,17 @@ 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[out] GlobalBlobID The ids of the blobs
* @param[in] comm MPI communicator
* @param[in] S S
* @param[out] LocalBlobID The ids of the blobs
* @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 );
BlobIDArray& GlobalBlobID, MPI_Comm comm );
/*!
@@ -85,25 +83,26 @@ 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_info MPI communication info
* @param[in] rank_in 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 );
const IntArray &PhaseID, int &VALUE, BlobIDArray &GlobalBlobID, MPI_Comm comm );
/*!
* @brief Reorder the blobs
* @details Reorder the blobs based on the number of cells they contain
* largest first.
* @param[in,out] ID The ids of the blobs
* @param[in] comm MPI communicator
* @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
*/
void ReorderBlobIDs( BlobIDArray& ID, const Utilities::MPI& comm );
void ReorderBlobIDs( BlobIDArray& ID, MPI_Comm comm );
typedef std::pair<BlobIDType,std::vector<BlobIDType> > BlobIDSplitStruct;
@@ -133,21 +132,17 @@ struct ID_map_struct {
* @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, MPI_Comm 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())
*/
@@ -159,9 +154,9 @@ void getNewIDs( ID_map_struct& map, BlobIDType& id_max, std::vector<BlobIDType>&
* @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_ids, BlobIDArray& IDs );
void renumberIDs( const std::vector<BlobIDType>& new_id_list, BlobIDArray& IDs );
/*!

View File

@@ -1,38 +1,21 @@
#include "analysis/dcel.h"
DCEL::DCEL(){
DECL::DECL(){
}
DCEL::~DCEL(){
DECL::~DECL(){
TriangleCount=0;
VertexCount=0;
}
int DCEL::Face(int index){
int DECL::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);
}
void DCEL::LocalIsosurface(const DoubleArray& A, double value, const int i, const int j, const int k){
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;
@@ -174,7 +157,7 @@ void DCEL::LocalIsosurface(const DoubleArray& A, double value, const int i, cons
}
int nTris = TriangleCount;
// Now add the local values to the DCEL data structure
// Now add the local values to the DECL data structure
if (nTris>0){
FaceData.resize(TriangleCount);
//printf("Construct halfedge structure... \n");
@@ -250,7 +233,7 @@ void DCEL::LocalIsosurface(const DoubleArray& A, double value, const int i, cons
}
}
Point DCEL::TriNormal(int edge)
Point DECL::TriNormal(int edge)
{
Point P,Q,R;
Point U,V,W;
@@ -294,7 +277,7 @@ Point DCEL::TriNormal(int edge)
return W;
}
double DCEL::EdgeAngle(int edge)
double DECL::EdgeAngle(int edge)
{
double angle;
double dotprod;
@@ -367,43 +350,241 @@ double DCEL::EdgeAngle(int edge)
return angle;
}
void iso_surface(const Array<double>&Field, const double isovalue)
void Isosurface(DoubleArray &A, const double &v)
{
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");
Point P,Q;
Point PlaceHolder;
Point C0,C1,C2,C3,C4,C5,C6,C7;
int TriangleCount;
int VertexCount;
int CubeIndex;
Point VertexList[12];
Point NewVertexList[12];
int LocalRemap[12];
Point cellvertices[20];
std::array<std::array<int,3>,20> Triangles;
Triangles.fill( { 0 } );
// Values from array 'A' at the cube corners
double CubeValues[8];
int Nx = A.size(0);
int Ny = A.size(1);
int Nz = A.size(2);
// 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;
std::vector<std::array<int,6>> HalfEdge;
for (int k=1; k<Nz-1; k++){
for (int j=1; j<Ny-1; j++){
for (int i=1; i<Nx-1; i++){
// Set the corner values for this cube
CubeValues[0] = A(i,j,k);
CubeValues[1] = A(i+1,j,k);
CubeValues[2] = A(i+1,j+1,k);
CubeValues[3] = A(i,j+1,k);
CubeValues[4] = A(i,j,k+1);
CubeValues[5] = A(i+1,j,k+1);
CubeValues[6] = A(i+1,j+1,k+1);
CubeValues[7] = A(i,j+1,k+1);
//Determine the index into the edge table which
//tells us which vertices are inside of the surface
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++;
}
}
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
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];
// first edge: V1->V2
HalfEdge[idx_edge][0] = V1; // first vertex
HalfEdge[idx_edge][1] = V2; // second vertex
HalfEdge[idx_edge][2] = idx; // triangle
HalfEdge[idx_edge][3] = -1; // twin
HalfEdge[idx_edge][4] = idx_edge+2; // previous edge
HalfEdge[idx_edge][5] = idx_edge+1; // next edge
idx_edge++;
// second edge: V2->V3
HalfEdge[idx_edge][0] = V2; // first vertex
HalfEdge[idx_edge][1] = V3; // second vertex
HalfEdge[idx_edge][2] = idx; // triangle
HalfEdge[idx_edge][3] = -1; // twin
HalfEdge[idx_edge][4] = idx_edge-1; // previous edge
HalfEdge[idx_edge][5] = idx_edge+1; // next edge
idx_edge++;
// third edge: V3->V1
HalfEdge[idx_edge][0] = V3; // first vertex
HalfEdge[idx_edge][1] = V1; // second vertex
HalfEdge[idx_edge][2] = idx; // triangle
HalfEdge[idx_edge][3] = -1; // twin
HalfEdge[idx_edge][4] = idx_edge-1; // previous edge
HalfEdge[idx_edge][5] = idx_edge-2; // next edge
idx_edge++;
}
int EdgeCount=idx_edge;
for (int idx=0; idx<EdgeCount; idx++){
int V1=HalfEdge[idx][0];
int V2=HalfEdge[idx][1];
// Find all the twins within the cube
for (int jdx=0; idx<EdgeCount; jdx++){
if (HalfEdge[jdx][1] == V1 && HalfEdge[jdx][0] == V2){
// this is the pair
HalfEdge[idx][3] = jdx;
HalfEdge[jdx][3] = idx;
}
if (HalfEdge[jdx][1] == V2 && HalfEdge[jdx][0] == 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[idx_edge][3] = -1; // ghost twin for x=0 face
if (P.x == 1.0 && Q.x == 1.0) HalfEdge[idx_edge][3] = -2; // ghost twin for x=1 face
if (P.y == 0.0 && Q.y == 0.0) HalfEdge[idx_edge][3] = -3; // ghost twin for y=0 face
if (P.y == 1.0 && Q.y == 1.0) HalfEdge[idx_edge][3] = -4; // ghost twin for y=1 face
if (P.z == 0.0 && Q.z == 0.0) HalfEdge[idx_edge][3] = -5; // ghost twin for z=0 face
if (P.z == 1.0 && Q.z == 1.0) HalfEdge[idx_edge][3] = -6; // ghost twin for z=1 face
}
// Find all the angles
for (int idx=0; idx<EdgeCount; idx++){
int V1=HalfEdge[idx][0];
int V2=HalfEdge[idx][1];
int T1= HalfEdge[idx_edge][2];
int twin=HalfEdge[idx_edge][3];
if (twin == -1){
}
}
// Map vertices to global coordinates
for (int idx=0;idx<VertexCount;idx++) {
P = cellvertices[idx];
P.x += i;
P.y += j;
P.z += k;
cellvertices[idx] = P;
}
}
}
}
}
}
}
}
fprintf(TRIANGLES,"endsolid isosurface\n");
fclose(TRIANGLES);
}

View File

@@ -1,12 +1,8 @@
#ifndef DCEL_INC
#define DCEL_INC
#include <vector>
#include "analysis/pmmc.h"
/**
* \class Vertex
* @brief store vertex for DCEL data structure
/*
Doubly-connected edge list (DECL)
*/
// Vertex structure
@@ -35,10 +31,8 @@ private:
};
/**
* \class Halfedge
* @brief store half edge for DCEL data structure
*/
// Halfedge structure
// Face
class Halfedge{
public:
Halfedge() = default;
@@ -63,20 +57,16 @@ private:
std::vector<std::array<int,6>> d_data;
};
/**
* \class DCEL
* @details doubly connected edge list data structure
*/
class DCEL{
// DECL
class DECL{
public:
DCEL();
~DCEL();
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);
@@ -88,7 +78,3 @@ public:
private:
std::vector<int> FaceData;
};
void iso_surface(const Array<double>&Field, const double isovalue);
#endif

View File

@@ -1,6 +1,5 @@
/*
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
@@ -192,7 +191,7 @@ void CalcVecDist( Array<Vec> &d, const Array<int> &ID0, const Domain &Dm,
// Update distance
double err = calcVecUpdateInterior( d, dx[0], dx[1], dx[2] );
// Check if we are finished
err = Dm.Comm.maxReduce( err );
err = maxReduce( Dm.Comm, err );
if ( err < tol )
break;
}

View File

@@ -1,6 +1,5 @@
/*
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
@@ -40,7 +39,6 @@ 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,
@@ -53,7 +51,6 @@ 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} );

View File

@@ -1,6 +1,5 @@
/*
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
@@ -18,33 +17,6 @@
#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;
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");
}
void Med3D( const Array<float> &Input, Array<float> &Output )
{

View File

@@ -1,6 +1,5 @@
/*
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
@@ -20,13 +19,6 @@
#include "common/Array.h"
/*!
* @brief Filter image
* @details This routine performs a mean filter
* @param[in] Input Input image
* @param[out] Output Output image
*/
void Mean3D( const Array<double> &Input, Array<double> &Output );
/*!
* @brief Filter image
@@ -36,15 +28,13 @@ void Mean3D( const Array<double> &Input, Array<double> &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);

View File

@@ -1,6 +1,5 @@
/*
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

View File

@@ -1,6 +1,5 @@
/*
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
@@ -105,7 +104,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] Nh The filter size
* @param[in] H The filter [2*Nhx+1,2*Nhy+1,...]
* @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
@@ -130,7 +129,6 @@ 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

View File

@@ -1,6 +1,5 @@
/*
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
@@ -16,7 +15,6 @@
*/
/*
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

File diff suppressed because it is too large Load Diff

View File

@@ -5,94 +5,4 @@
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
double MorphGrow(DoubleArray &BoundaryDist, DoubleArray &Dist, Array<char> &id, std::shared_ptr<Domain> Dm, double TargetVol);

View File

@@ -1,6 +1,5 @@
/*
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

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
/*
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
@@ -17,51 +16,41 @@
#ifndef RunAnalysis_H_INC
#define RunAnalysis_H_INC
#include "analysis/SubPhase.h"
#include "analysis/TwoPhase.h"
#include "analysis/analysis.h"
#include "analysis/TwoPhase.h"
#include "analysis/SubPhase.h"
#include "common/Communication.h"
#include "common/ScaLBL.h"
#include "threadpool/thread_pool.h"
#include "models/ColorModel.h"
#include <limits.h>
typedef std::shared_ptr<std::pair<int,IntArray>> BlobIDstruct;
typedef std::shared_ptr<std::vector<BlobIDType>> BlobIDList;
// Types of analysis
enum class AnalysisType : uint64_t {
AnalyzeNone = 0,
IdentifyBlobs = 0x01,
CopyPhaseIndicator = 0x02,
CopySimState = 0x04,
ComputeAverages = 0x08,
CreateRestart = 0x10,
WriteVis = 0x20,
ComputeSubphase = 0x40
};
enum class AnalysisType : uint64_t { AnalyzeNone=0, IdentifyBlobs=0x01, CopyPhaseIndicator=0x02,
CopySimState=0x04, ComputeAverages=0x08, CreateRestart=0x10, WriteVis=0x20, ComputeSubphase=0x40 };
//! Class to run the analysis in multiple threads
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 );
//! Destructor
~runAnalysis();
//! Run the next analysis
void run( int timestep, std::shared_ptr<Database> db, TwoPhase &Averages, const double *Phi,
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();
@@ -70,8 +59,7 @@ public:
* \brief Set the affinities
* \details This function will create the analysis threads and set the affinity
* of this thread and all analysis threads. If MPI_THREAD_MULTIPLE is not
* enabled, the analysis threads will be disabled and the analysis will run in the current
* thread.
* enabled, the analysis threads will be disabled and the analysis will run in the current thread.
* @param[in] method Method used to control the affinities:
* none - Don't use threads (runs all analysis in the current thread)
* default - Create the specified number of threads, but don't load balance
@@ -80,36 +68,38 @@ 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 );
public:
class commWrapper
{
public:
Utilities::MPI comm;
public:
MPI_Comm comm;
int tag;
runAnalysis *analysis;
commWrapper( int tag, const Utilities::MPI &comm, runAnalysis *analysis );
commWrapper() = delete;
commWrapper( int tag, MPI_Comm comm, runAnalysis *analysis );
commWrapper( ) = delete;
commWrapper( const commWrapper &rhs ) = delete;
commWrapper &operator=( const commWrapper &rhs ) = delete;
commWrapper& operator=( const commWrapper &rhs ) = delete;
commWrapper( commWrapper &&rhs );
~commWrapper();
};
// Get a comm (not thread safe)
commWrapper getComm();
commWrapper getComm( );
private:
std::array<int, 3> d_n; // Number of local cells
std::array<int, 3> d_N; // Number of local cells with ghosts
int d_N[3];
int d_Np;
int d_rank;
int d_restart_interval, d_analysis_interval, d_blobid_interval, d_visualization_interval;
@@ -119,13 +109,14 @@ private:
ThreadPool d_tpool;
RankInfoStruct d_rank_info;
IntArray d_Map;
std::shared_ptr<std::pair<int, IntArray>> d_last_ids;
std::shared_ptr<std::pair<int, IntArray>> d_last_index;
std::shared_ptr<std::vector<BlobIDType>> d_last_id_map;
BlobIDstruct d_last_ids;
BlobIDstruct d_last_index;
BlobIDList d_last_id_map;
std::vector<IO::MeshDataStruct> d_meshData;
fillHalo<double> d_fillData;
std::string d_restartFile;
Utilities::MPI d_comm;
Utilities::MPI d_comms[1024];
MPI_Comm d_comm;
MPI_Comm d_comms[1024];
volatile bool d_comm_used[1024];
std::shared_ptr<ScaLBL_Communicator> d_ScaLBL_Comm;
@@ -138,6 +129,8 @@ private:
// Friends
friend commWrapper::~commWrapper();
};
#endif

View File

@@ -1,6 +1,5 @@
/*
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
@@ -173,7 +172,6 @@ void solve( const Array<float>& VOL, Array<float>& Mean, Array<char>& ID,
// int depth = 5;
// float sigsq=0.1;
int nlm_count = NLM3D( MultiScaleSmooth, Mean, Dist, NonLocalMean, depth, sigsq);
NULL_USE( nlm_count );
fillFloat.fill(NonLocalMean);
}
@@ -218,7 +216,6 @@ void refine( const Array<float>& Dist_coarse,
// 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++) {
@@ -244,7 +241,8 @@ void filter_final( Array<char>& ID, Array<float>& Dist,
Array<float>& Mean, Array<float>& Dist1, Array<float>& Dist2 )
{
PROFILE_SCOPED(timer,"filter_final");
int rank = Dm.Comm.getRank();
int rank;
MPI_Comm_rank(Dm.Comm,&rank);
int Nx = Dm.Nx-2;
int Ny = Dm.Ny-2;
int Nz = Dm.Nz-2;
@@ -257,7 +255,7 @@ void filter_final( Array<char>& ID, Array<float>& Dist,
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()) );
tmp = sqrt( sumReduce(Dm.Comm,tmp) / sumReduce(Dm.Comm,(float)Dist0.length()) );
const float dx1 = 0.3*tmp;
const float dx2 = 1.05*dx1;
if (rank==0)
@@ -300,7 +298,7 @@ void filter_final( Array<char>& ID, Array<float>& Dist,
Phase.fill(1);
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);
int N_blobs = maxReduce(Dm.Comm,GlobalBlobID.max()+1);
std::vector<float> mean(N_blobs,0);
std::vector<int> count(N_blobs,0);
for (int k=1; k<=Nz; k++) {
@@ -336,8 +334,8 @@ void filter_final( Array<char>& ID, Array<float>& Dist,
}
}
}
mean = Dm.Comm.sumReduce(mean);
count = Dm.Comm.sumReduce(count);
mean = sumReduce(Dm.Comm,mean);
count = sumReduce(Dm.Comm,count);
for (size_t i=0; i<mean.size(); i++)
mean[i] /= count[i];
/*if (rank==0) {

View File

@@ -1,6 +1,5 @@
/*
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

View File

@@ -1,84 +0,0 @@
#!/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

362
cmake/FindMPI.cmake Normal file
View File

@@ -0,0 +1,362 @@
# - Message Passing Interface (MPI) module.
#
# The Message Passing Interface (MPI) is a library used to write
# high-performance parallel applications that use message passing, and
# is typically deployed on a cluster. MPI is a standard interface
# (defined by the MPI forum) for which many implementations are
# available. All of these implementations have somewhat different
# compilation approaches (different include paths, libraries to link
# against, etc.), and this module tries to smooth out those differences.
#
# This module will set the following variables:
# MPI_FOUND TRUE if we have found MPI
# MPI_COMPILE_FLAGS Compilation flags for MPI programs
# MPI_INCLUDE_PATH Include path(s) for MPI header
# MPI_LINK_FLAGS Linking flags for MPI programs
# MPI_LIBRARY First MPI library to link against (cached)
# MPI_EXTRA_LIBRARY Extra MPI libraries to link against (cached)
# MPI_LIBRARIES All libraries to link MPI programs against
# MPIEXEC Executable for running MPI programs
# MPIEXEC_NUMPROC_FLAG Flag to pass to MPIEXEC before giving it the
# number of processors to run on
# MPIEXEC_PREFLAGS Flags to pass to MPIEXEC directly before the
# executable to run.
# MPIEXEC_POSTFLAGS Flags to pass to MPIEXEC after all other flags.
#
# This module will attempt to auto-detect these settings, first by
# looking for a MPI compiler, which many MPI implementations provide
# as a pass-through to the native compiler to simplify the compilation
# of MPI programs. The MPI compiler is stored in the cache variable
# MPI_COMPILER, and will attempt to look for commonly-named drivers
# mpic++, mpicxx, mpiCC, or mpicc. If the compiler driver is found and
# recognized, it will be used to set all of the module variables. To
# skip this auto-detection, set MPI_LIBRARY and MPI_INCLUDE_PATH in
# the CMake cache.
#
# If no compiler driver is found or the compiler driver is not
# recognized, this module will then search for common include paths
# and library names to try to detect MPI.
#
# If CMake initially finds a different MPI than was intended, and you
# want to use the MPI compiler auto-detection for a different MPI
# implementation, set MPI_COMPILER to the MPI compiler driver you want
# to use (e.g., mpicxx) and then set MPI_LIBRARY to the string
# MPI_LIBRARY-NOTFOUND. When you re-configure, auto-detection of MPI
# will run again with the newly-specified MPI_COMPILER.
#
# When using MPIEXEC to execute MPI applications, you should typically
# use all of the MPIEXEC flags as follows:
# ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} PROCS ${MPIEXEC_PREFLAGS} EXECUTABLE
# ${MPIEXEC_POSTFLAGS} ARGS
# where PROCS is the number of processors on which to execute the program,
# EXECUTABLE is the MPI program, and ARGS are the arguments to pass to the
# MPI program.
#=============================================================================
# Copyright 2001-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
# This module is maintained by David Partyka <dave.partyka@kitware.com>.
# A set of directories to search through in addition to the standard system paths
# that find_program will search through.
# Microsoft HPC SDK is automatically added to the system path
# Argonne National Labs MPICH2 sets a registry key that we can use.
set(_MPI_PACKAGE_DIR
mpi
mpich
openmpi
lib/mpi
lib/mpich
lib/openmpi
"MPICH/SDK"
"Microsoft Compute Cluster Pack"
"Microsoft HPC Pack 2008 R2"
)
set(_MPI_PREFIX_PATH)
if(WIN32)
list(APPEND _MPI_PREFIX_PATH "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MPICH\\SMPD;binary]/..")
list(APPEND _MPI_PREFIX_PATH "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MPICH2;Path]")
endif()
foreach(SystemPrefixDir ${CMAKE_SYSTEM_PREFIX_PATH})
foreach(MpiPackageDir ${_MPI_PREFIX_PATH})
if(EXISTS ${SystemPrefixDir}/${MpiPackageDir})
list(APPEND _MPI_PREFIX_PATH "${SystemPrefixDir}/${MpiPackageDir}")
endif()
endforeach(MpiPackageDir)
endforeach(SystemPrefixDir)
# Most mpi distros have some form of mpiexec which gives us something we can reliably look for.
find_program(MPIEXEC
NAMES mpiexec mpirun lamexec
PATHS ${_MPI_PREFIX_PATH}
PATH_SUFFIXES bin
DOC "Executable for running MPI programs."
)
# call get_filename_component twice to remove mpiexec and the directory it exists in (typically bin).
# This gives us a fairly reliable base directory to search for /bin /lib and /include from.
get_filename_component(_MPI_BASE_DIR "${MPIEXEC}" PATH)
get_filename_component(_MPI_BASE_DIR "${_MPI_BASE_DIR}" PATH)
# If there is an mpi compiler find it and interogate (farther below) it for the include
# and lib dirs otherwise we will continue to search from ${_MPI_BASE_DIR}.
find_program(MPI_COMPILER
NAMES mpic++ mpicxx mpiCC mpicc
HINTS "${_MPI_BASE_DIR}"
PATH_SUFFIXES bin
DOC "MPI compiler. Used only to detect MPI compilation flags.")
mark_as_advanced(MPI_COMPILER)
set(MPIEXEC_NUMPROC_FLAG "-np" CACHE STRING "Flag used by MPI to specify the number of processes for MPIEXEC; the next option will be the number of processes.")
set(MPIEXEC_PREFLAGS "" CACHE STRING "These flags will be directly before the executable that is being run by MPIEXEC.")
set(MPIEXEC_POSTFLAGS "" CACHE STRING "These flags will come after all flags given to MPIEXEC.")
set(MPIEXEC_MAX_NUMPROCS "2" CACHE STRING "Maximum number of processors available to run MPI applications.")
mark_as_advanced(MPIEXEC MPIEXEC_NUMPROC_FLAG MPIEXEC_PREFLAGS
MPIEXEC_POSTFLAGS MPIEXEC_MAX_NUMPROCS)
if (MPI_INCLUDE_PATH AND MPI_LIBRARY)
# Do nothing: we already have MPI_INCLUDE_PATH and MPI_LIBRARY in
# the cache, and we don't want to override those settings.
elseif (MPI_COMPILER)
# Check whether the -showme:compile option works. This indicates
# that we have either Open MPI or a newer version of LAM-MPI, and
# implies that -showme:link will also work.
# Note that Windows distros do not have an mpi compiler to interogate.
exec_program(${MPI_COMPILER}
ARGS -showme:compile
OUTPUT_VARIABLE MPI_COMPILE_CMDLINE
RETURN_VALUE MPI_COMPILER_RETURN)
if (MPI_COMPILER_RETURN EQUAL 0)
# If we appear to have -showme:compile, then we should also have
# -showme:link. Try it.
exec_program(${MPI_COMPILER}
ARGS -showme:link
OUTPUT_VARIABLE MPI_LINK_CMDLINE
RETURN_VALUE MPI_COMPILER_RETURN)
# Note that we probably have -showme:incdirs and -showme:libdirs
# as well.
set(MPI_COMPILER_MAY_HAVE_INCLIBDIRS TRUE)
endif (MPI_COMPILER_RETURN EQUAL 0)
if (MPI_COMPILER_RETURN EQUAL 0)
# Do nothing: we have our command lines now
else (MPI_COMPILER_RETURN EQUAL 0)
# Older versions of LAM-MPI have "-showme". Try it.
exec_program(${MPI_COMPILER}
ARGS -showme
OUTPUT_VARIABLE MPI_COMPILE_CMDLINE
RETURN_VALUE MPI_COMPILER_RETURN)
endif (MPI_COMPILER_RETURN EQUAL 0)
if (MPI_COMPILER_RETURN EQUAL 0)
# Do nothing: we have our command lines now
else (MPI_COMPILER_RETURN EQUAL 0)
# MPICH uses "-show". Try it.
exec_program(${MPI_COMPILER}
ARGS -show
OUTPUT_VARIABLE MPI_COMPILE_CMDLINE
RETURN_VALUE MPI_COMPILER_RETURN)
endif (MPI_COMPILER_RETURN EQUAL 0)
if (MPI_COMPILER_RETURN EQUAL 0)
# We have our command lines, but we might need to copy
# MPI_COMPILE_CMDLINE into MPI_LINK_CMDLINE, if the underlying
if (NOT MPI_LINK_CMDLINE)
SET(MPI_LINK_CMDLINE ${MPI_COMPILE_CMDLINE})
endif (NOT MPI_LINK_CMDLINE)
else (MPI_COMPILER_RETURN EQUAL 0)
message(STATUS "Unable to determine MPI from MPI driver ${MPI_COMPILER}")
endif (MPI_COMPILER_RETURN EQUAL 0)
endif (MPI_INCLUDE_PATH AND MPI_LIBRARY)
if (MPI_INCLUDE_PATH AND MPI_LIBRARY)
# Do nothing: we already have MPI_INCLUDE_PATH and MPI_LIBRARY in
# the cache, and we don't want to override those settings.
elseif (MPI_COMPILE_CMDLINE)
# Extract compile flags from the compile command line.
string(REGEX MATCHALL "(^| )-[Df]([^\" ]+|\"[^\"]+\")" MPI_ALL_COMPILE_FLAGS "${MPI_COMPILE_CMDLINE}")
set(MPI_COMPILE_FLAGS_WORK)
foreach(FLAG ${MPI_ALL_COMPILE_FLAGS})
if (MPI_COMPILE_FLAGS_WORK)
set(MPI_COMPILE_FLAGS_WORK "${MPI_COMPILE_FLAGS_WORK} ${FLAG}")
else(MPI_COMPILE_FLAGS_WORK)
set(MPI_COMPILE_FLAGS_WORK ${FLAG})
endif(MPI_COMPILE_FLAGS_WORK)
endforeach(FLAG)
# Extract include paths from compile command line
string(REGEX MATCHALL "(^| )-I([^\" ]+|\"[^\"]+\")" MPI_ALL_INCLUDE_PATHS "${MPI_COMPILE_CMDLINE}")
set(MPI_INCLUDE_PATH_WORK)
foreach(IPATH ${MPI_ALL_INCLUDE_PATHS})
string(REGEX REPLACE "^ ?-I" "" IPATH ${IPATH})
string(REGEX REPLACE "//" "/" IPATH ${IPATH})
list(APPEND MPI_INCLUDE_PATH_WORK ${IPATH})
endforeach(IPATH)
if (NOT MPI_INCLUDE_PATH_WORK)
if (MPI_COMPILER_MAY_HAVE_INCLIBDIRS)
# The compile command line didn't have any include paths on it,
# but we may have -showme:incdirs. Use it.
exec_program(${MPI_COMPILER}
ARGS -showme:incdirs
OUTPUT_VARIABLE MPI_INCLUDE_PATH_WORK
RETURN_VALUE MPI_COMPILER_RETURN)
separate_arguments(MPI_INCLUDE_PATH_WORK)
endif (MPI_COMPILER_MAY_HAVE_INCLIBDIRS)
endif (NOT MPI_INCLUDE_PATH_WORK)
if (NOT MPI_INCLUDE_PATH_WORK)
# If all else fails, just search for mpi.h in the normal include
# paths.
find_path(MPI_INCLUDE_PATH mpi.h
HINTS ${_MPI_BASE_DIR} ${_MPI_PREFIX_PATH}
PATH_SUFFIXES include
)
set(MPI_INCLUDE_PATH_WORK ${MPI_INCLUDE_PATH})
endif (NOT MPI_INCLUDE_PATH_WORK)
# Extract linker paths from the link command line
string(REGEX MATCHALL "(^| |-Wl,)-L([^\" ]+|\"[^\"]+\")" MPI_ALL_LINK_PATHS "${MPI_LINK_CMDLINE}")
set(MPI_LINK_PATH)
foreach(LPATH ${MPI_ALL_LINK_PATHS})
string(REGEX REPLACE "^(| |-Wl,)-L" "" LPATH ${LPATH})
string(REGEX REPLACE "//" "/" LPATH ${LPATH})
list(APPEND MPI_LINK_PATH ${LPATH})
endforeach(LPATH)
if (NOT MPI_LINK_PATH)
if (MPI_COMPILER_MAY_HAVE_INCLIBDIRS)
# The compile command line didn't have any linking paths on it,
# but we may have -showme:libdirs. Use it.
exec_program(${MPI_COMPILER}
ARGS -showme:libdirs
OUTPUT_VARIABLE MPI_LINK_PATH
RETURN_VALUE MPI_COMPILER_RETURN)
separate_arguments(MPI_LINK_PATH)
endif (MPI_COMPILER_MAY_HAVE_INCLIBDIRS)
endif (NOT MPI_LINK_PATH)
# Extract linker flags from the link command line
string(REGEX MATCHALL "(^| )-Wl,([^\" ]+|\"[^\"]+\")" MPI_ALL_LINK_FLAGS "${MPI_LINK_CMDLINE}")
set(MPI_LINK_FLAGS_WORK)
foreach(FLAG ${MPI_ALL_LINK_FLAGS})
if (MPI_LINK_FLAGS_WORK)
set(MPI_LINK_FLAGS_WORK "${MPI_LINK_FLAGS_WORK} ${FLAG}")
else(MPI_LINK_FLAGS_WORK)
set(MPI_LINK_FLAGS_WORK ${FLAG})
endif(MPI_LINK_FLAGS_WORK)
endforeach(FLAG)
if ( MPI_LINK_FLAGS_WORK )
string ( REGEX REPLACE "^ " "" MPI_LINK_FLAGS_WORK ${MPI_LINK_FLAGS_WORK} )
endif ()
# Extract the set of libraries to link against from the link command
# line
string(REGEX MATCHALL "(^| )-l([^\" ]+|\"[^\"]+\")" MPI_LIBNAMES "${MPI_LINK_CMDLINE}")
# Determine full path names for all of the libraries that one needs
# to link against in an MPI program
set(MPI_LIBRARIES)
foreach(LIB ${MPI_LIBNAMES})
string(REGEX REPLACE "^ ?-l" "" LIB ${LIB})
set(MPI_LIB "MPI_LIB-NOTFOUND" CACHE FILEPATH "Cleared" FORCE)
find_library(MPI_LIB ${LIB} HINTS ${MPI_LINK_PATH})
if (MPI_LIB)
list(APPEND MPI_LIBRARIES ${MPI_LIB})
elseif (NOT MPI_FIND_QUIETLY)
message(WARNING "Unable to find MPI library ${LIB}")
endif ()
endforeach(LIB)
set(MPI_LIB "MPI_LIB-NOTFOUND" CACHE INTERNAL "Scratch variable for MPI detection" FORCE)
# Chop MPI_LIBRARIES into the old-style MPI_LIBRARY and
# MPI_EXTRA_LIBRARY.
list(LENGTH MPI_LIBRARIES MPI_NUMLIBS)
list(LENGTH MPI_LIBNAMES MPI_NUMLIBS_EXPECTED)
if (MPI_NUMLIBS EQUAL MPI_NUMLIBS_EXPECTED)
list(GET MPI_LIBRARIES 0 MPI_LIBRARY_WORK)
set(MPI_LIBRARY ${MPI_LIBRARY_WORK} CACHE FILEPATH "MPI library to link against" FORCE)
else (MPI_NUMLIBS EQUAL MPI_NUMLIBS_EXPECTED)
set(MPI_LIBRARY "MPI_LIBRARY-NOTFOUND" CACHE FILEPATH "MPI library to link against" FORCE)
endif (MPI_NUMLIBS EQUAL MPI_NUMLIBS_EXPECTED)
if (MPI_NUMLIBS GREATER 1)
set(MPI_EXTRA_LIBRARY_WORK ${MPI_LIBRARIES})
list(REMOVE_AT MPI_EXTRA_LIBRARY_WORK 0)
set(MPI_EXTRA_LIBRARY ${MPI_EXTRA_LIBRARY_WORK} CACHE STRING "Extra MPI libraries to link against" FORCE)
else (MPI_NUMLIBS GREATER 1)
set(MPI_EXTRA_LIBRARY "MPI_EXTRA_LIBRARY-NOTFOUND" CACHE STRING "Extra MPI libraries to link against" FORCE)
endif (MPI_NUMLIBS GREATER 1)
# Set up all of the appropriate cache entries
set(MPI_COMPILE_FLAGS ${MPI_COMPILE_FLAGS_WORK} CACHE STRING "MPI compilation flags" FORCE)
set(MPI_INCLUDE_PATH ${MPI_INCLUDE_PATH_WORK} CACHE STRING "MPI include path" FORCE)
set(MPI_LINK_FLAGS ${MPI_LINK_FLAGS_WORK} CACHE STRING "MPI linking flags" FORCE)
else (MPI_COMPILE_CMDLINE)
# No MPI compiler to interogate so attempt to find everything with find functions.
find_path(MPI_INCLUDE_PATH mpi.h
HINTS ${_MPI_BASE_DIR} ${_MPI_PREFIX_PATH}
PATH_SUFFIXES include Inc
)
# Decide between 32-bit and 64-bit libraries for Microsoft's MPI
if("${CMAKE_SIZEOF_VOID_P}" EQUAL 8)
set(MS_MPI_ARCH_DIR amd64)
else()
set(MS_MPI_ARCH_DIR i386)
endif()
find_library(MPI_LIBRARY
NAMES mpi mpich msmpi
HINTS ${_MPI_BASE_DIR} ${_MPI_PREFIX_PATH}
PATH_SUFFIXES lib lib/${MS_MPI_ARCH_DIR} Lib Lib/${MS_MPI_ARCH_DIR}
)
find_library(MPI_EXTRA_LIBRARY
NAMES mpi++
HINTS ${_MPI_BASE_DIR} ${_MPI_PREFIX_PATH}
PATH_SUFFIXES lib
DOC "Extra MPI libraries to link against.")
set(MPI_COMPILE_FLAGS "" CACHE STRING "MPI compilation flags")
set(MPI_LINK_FLAGS "" CACHE STRING "MPI linking flags")
endif (MPI_INCLUDE_PATH AND MPI_LIBRARY)
# Set up extra variables to conform to
if (MPI_EXTRA_LIBRARY)
set(MPI_LIBRARIES ${MPI_LIBRARY} ${MPI_EXTRA_LIBRARY})
else (MPI_EXTRA_LIBRARY)
set(MPI_LIBRARIES ${MPI_LIBRARY})
endif (MPI_EXTRA_LIBRARY)
if (MPI_INCLUDE_PATH AND MPI_LIBRARY)
set(MPI_FOUND TRUE)
else (MPI_INCLUDE_PATH AND MPI_LIBRARY)
set(MPI_FOUND FALSE)
endif (MPI_INCLUDE_PATH AND MPI_LIBRARY)
#include("${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake")
# handle the QUIETLY and REQUIRED arguments
#find_package_handle_standard_args(MPI DEFAULT_MSG MPI_LIBRARY MPI_INCLUDE_PATH)
mark_as_advanced(MPI_INCLUDE_PATH MPI_COMPILE_FLAGS MPI_LINK_FLAGS MPI_LIBRARY
MPI_EXTRA_LIBRARY)
# unset to cleanup namespace
unset(_MPI_PACKAGE_DIR)
unset(_MPI_PREFIX_PATH)
unset(_MPI_BASE_DIR)

View File

@@ -4,7 +4,7 @@
# CONFIGURE_TIMER( DEFAULT_USE_TIMER NULL_TIMER_DIR )
# This function assumes that USE_TIMER is set to indicate if the timer should be used
# If USE_TIMER is set, TIMER_DIRECTORY specifies the install path for the timer
# If USE_TIMER is not set we will create a dummy timer that does nothing.
# If USE_TIMER is not set we will create a summy timer that does nothing.
# The input argument DEFAULT_USE_TIMER specifies if the timer library is included by default.
# The input argument NULL_TIMER_DIR specifies the location to install the dummy timer.
# If it is an empty string, the default install path "${CMAKE_CURRENT_BINARY_DIR}/null_timer" is used.
@@ -13,7 +13,7 @@
# TIMER_CXXFLAGS - C++ flags for the timer library
# TIMER_LDFLAGS - Linker flags to link the timer library
# TIMER_LDLIBS - Linker libraries to link the timer library
FUNCTION( CONFIGURE_TIMER DEFAULT_USE_TIMER NULL_TIMER_DIR QUIET )
FUNCTION( CONFIGURE_TIMER DEFAULT_USE_TIMER NULL_TIMER_DIR )
# Determine if we want to use the timer utility
CHECK_ENABLE_FLAG( USE_TIMER ${DEFAULT_USE_TIMER} )
SET( TIMER_INCLUDE )
@@ -33,23 +33,20 @@ FUNCTION( CONFIGURE_TIMER DEFAULT_USE_TIMER NULL_TIMER_DIR QUIET )
FIND_LIBRARY( TIMER_LIBS NAMES timerutility PATHS ${TIMER_DIRECTORY}/lib NO_DEFAULT_PATH )
SET( TIMER_INCLUDE ${TIMER_DIRECTORY}/include )
SET( TIMER_CXXFLAGS "-DUSE_TIMER -I${TIMER_DIRECTORY}/include" )
SET( TIMER_LDFLAGS )
SET( TIMER_LDLIBS "${TIMER_LIBS}" )
SET( TIMER_LDFLAGS -L${TIMER_DIRECTORY}/lib )
SET( TIMER_LDLIBS -ltimerutility )
ELSE()
MESSAGE( FATAL_ERROR "Default search for TIMER is not yet supported. Use -D TIMER_DIRECTORY=" )
ENDIF()
SET( CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} "${TIMER_DIRECTORY}/lib" PARENT_SCOPE )
SET(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} "${TIMER_DIRECTORY}/lib" PARENT_SCOPE )
INCLUDE_DIRECTORIES( "${TIMER_INCLUDE}" )
ADD_DEFINITIONS( -DUSE_TIMER )
IF ( NOT QUIET )
MESSAGE( STATUS "Using timer utility" )
MESSAGE( STATUS " TIMER_LIBRARIES = ${TIMER_LIBS}" )
ENDIF()
MESSAGE( "Using timer utility" )
MESSAGE( " TIMER_LIBRARIES = ${TIMER_LIBS}" )
ELSE()
IF ( "${NULL_TIMER_DIR}" STREQUAL "" )
SET( NULL_TIMER_DIR "${CMAKE_CURRENT_BINARY_DIR}/null_timer" )
ENDIF()
# Write ProfilerApp.h
FILE(WRITE "${NULL_TIMER_DIR}/ProfilerApp.h" "#define PROFILE_START(...) do {} while(0)\n" )
FILE(APPEND "${NULL_TIMER_DIR}/ProfilerApp.h" "#define PROFILE_STOP(...) do {} while(0)\n" )
FILE(APPEND "${NULL_TIMER_DIR}/ProfilerApp.h" "#define PROFILE_START2(...) do {} while(0)\n" )
@@ -64,25 +61,9 @@ FUNCTION( CONFIGURE_TIMER DEFAULT_USE_TIMER NULL_TIMER_DIR QUIET )
FILE(APPEND "${NULL_TIMER_DIR}/ProfilerApp.h" "#define PROFILE_DISABLE_TRACE() do {} while(0)\n" )
FILE(APPEND "${NULL_TIMER_DIR}/ProfilerApp.h" "#define PROFILE_ENABLE_MEMORY() do {} while(0)\n" )
FILE(APPEND "${NULL_TIMER_DIR}/ProfilerApp.h" "#define PROFILE_DISABLE_MEMORY() do {} while(0)\n" )
# Write MemoryApp.h
FILE(WRITE "${NULL_TIMER_DIR}/MemoryApp.h" "#include <cstring>\n" )
FILE(APPEND "${NULL_TIMER_DIR}/MemoryApp.h" "class MemoryApp final {\n" )
FILE(APPEND "${NULL_TIMER_DIR}/MemoryApp.h" "public:\n" )
FILE(APPEND "${NULL_TIMER_DIR}/MemoryApp.h" " struct MemoryStats {\n" )
FILE(APPEND "${NULL_TIMER_DIR}/MemoryApp.h" " size_t bytes_new, bytes_delete, N_new, N_delete, tot_bytes_used, system_memory, stack_used, stack_size;\n" )
FILE(APPEND "${NULL_TIMER_DIR}/MemoryApp.h" " MemoryStats() { memset(this,0,sizeof(MemoryStats)); }\n" )
FILE(APPEND "${NULL_TIMER_DIR}/MemoryApp.h" " };\n" )
FILE(APPEND "${NULL_TIMER_DIR}/MemoryApp.h" " static inline void print( std::ostream& ) {}\n" )
FILE(APPEND "${NULL_TIMER_DIR}/MemoryApp.h" " static inline size_t getMemoryUsage() { return 0; }\n" )
FILE(APPEND "${NULL_TIMER_DIR}/MemoryApp.h" " static inline size_t getTotalMemoryUsage() { return 0; }\n" )
FILE(APPEND "${NULL_TIMER_DIR}/MemoryApp.h" " static inline size_t getSystemMemory() { return 0; }\n" )
FILE(APPEND "${NULL_TIMER_DIR}/MemoryApp.h" " static inline MemoryStats getMemoryStats() { return MemoryStats(); }\n" )
FILE(APPEND "${NULL_TIMER_DIR}/MemoryApp.h" "};\n" )
SET( TIMER_INCLUDE "${NULL_TIMER_DIR}" )
INCLUDE_DIRECTORIES( "${TIMER_INCLUDE}" )
IF ( NOT QUIET )
MESSAGE( STATUS "Disabling timer utility" )
ENDIF()
MESSAGE( "Disabling timer utility" )
ENDIF()
SET( TIMER_INCLUDE "${TIMER_INCLUDE}" PARENT_SCOPE )
SET( TIMER_CXXFLAGS "${TIMER_CXXFLAGS}" PARENT_SCOPE )
@@ -107,12 +88,12 @@ MACRO( CHECK_ENABLE_FLAG FLAG DEFAULT )
SET( ${FLAG} ${DEFAULT} )
ELSEIF( ${FLAG} STREQUAL "" )
SET( ${FLAG} ${DEFAULT} )
ELSEIF( ( ${${FLAG}} STREQUAL "FALSE" ) OR ( ${${FLAG}} STREQUAL "false" ) OR ( ${${FLAG}} STREQUAL "0" ) OR ( ${${FLAG}} STREQUAL "OFF" ) )
ELSEIF( ( ${${FLAG}} STREQUAL "false" ) OR ( ${${FLAG}} STREQUAL "0" ) OR ( ${${FLAG}} STREQUAL "OFF" ) )
SET( ${FLAG} 0 )
ELSEIF( ( ${${FLAG}} STREQUAL "TRUE" ) OR ( ${${FLAG}} STREQUAL "true" ) OR ( ${${FLAG}} STREQUAL "1" ) OR ( ${${FLAG}} STREQUAL "ON" ) )
ELSEIF( ( ${${FLAG}} STREQUAL "true" ) OR ( ${${FLAG}} STREQUAL "1" ) OR ( ${${FLAG}} STREQUAL "ON" ) )
SET( ${FLAG} 1 )
ELSE()
MESSAGE( FATAL_ERROR "Bad value for ${FLAG} (${${FLAG}}); use true or false" )
MESSAGE( "Bad value for ${FLAG} (${${FLAG}}); use true or false" )
ENDIF ()
ENDMACRO()

View File

@@ -32,6 +32,7 @@ SET( CMAKE_MAKE_PROGRAM $ENV{CMAKE_MAKE_PROGRAM} )
SET( CTEST_CMAKE_GENERATOR $ENV{CTEST_CMAKE_GENERATOR} )
SET( LDLIBS $ENV{LDLIBS} )
SET( LDFLAGS $ENV{LDFLAGS} )
SET( MPI_COMPILER $ENV{MPI_COMPILER} )
SET( MPI_DIRECTORY $ENV{MPI_DIRECTORY} )
SET( MPI_INCLUDE $ENV{MPI_INCLUDE} )
SET( MPI_LINK_FLAGS $ENV{MPI_LINK_FLAGS} )
@@ -197,7 +198,7 @@ SET( CTEST_OPTIONS "${CTEST_OPTIONS};-DCMAKE_C_FLAGS='${CFLAGS}';-DCMAKE_CXX_FLA
SET( CTEST_OPTIONS "${CTEST_OPTIONS};-DLDFLAGS:STRING='${FLAGS}';-DLDLIBS:STRING='${LDLIBS}'" )
SET( CTEST_OPTIONS "${CTEST_OPTIONS};-DENABLE_GCOV:BOOL=${ENABLE_GCOV}" )
IF ( USE_MPI )
SET( CTEST_OPTIONS "${CTEST_OPTIONS};-DMPIEXEC=${MPIEXEC}")
SET( CTEST_OPTIONS "${CTEST_OPTIONS};-DMPI_COMPILER:BOOL=true;-DMPIEXEC=${MPIEXEC}")
IF ( NOT USE_VALGRIND )
SET( CTEST_OPTIONS "${CTEST_OPTIONS};-DUSE_MPI_FOR_SERIAL_TESTS:BOOL=true")
ENDIF()

View File

@@ -41,61 +41,93 @@ ENDMACRO()
# Macro to find and configure the MPI libraries
MACRO( CONFIGURE_MPI )
# Determine if we want to use MPI
CHECK_ENABLE_FLAG( USE_MPI 1 )
CHECK_ENABLE_FLAG(USE_MPI 1 )
IF ( USE_MPI )
MESSAGE( "Configuring MPI" )
IF ( MPIEXEC )
SET( MPIEXEC_EXECUTABLE ${MPIEXEC} )
ENDIF()
IF ( NOT MPI_SKIP_SEARCH )
FIND_PACKAGE( MPI )
ELSE()
# Write mpi test
SET( MPI_TEST_SRC "${CMAKE_CURRENT_BINARY_DIR}/test_mpi.cpp" )
FILE(WRITE ${MPI_TEST_SRC} "#include <mpi.h>\n" )
FILE(APPEND ${MPI_TEST_SRC} "int main(int argc, char** argv) {\n" )
FILE(APPEND ${MPI_TEST_SRC} " MPI_Init(NULL, NULL);\n")
FILE(APPEND ${MPI_TEST_SRC} " MPI_Finalize();\n" )
FILE(APPEND ${MPI_TEST_SRC} "}\n" )
# Test the compile
IF ( CMAKE_CXX_COMPILER )
SET( TMP_FLAGS -DINCLUDE_DIRECTORIES=${MPI_CXX_INCLUDE_PATH} )
TRY_COMPILE( MPI_TEST_CXX ${CMAKE_CURRENT_BINARY_DIR} ${MPI_TEST_SRC}
CMAKE_FLAGS ${TMP_FLAGS}
LINK_OPTIONS ${MPI_CXX_LINK_FLAGS}
LINK_LIBRARIES ${MPI_CXX_LIBRARIES}
OUTPUT_VARIABLE OUT_TXT)
IF ( NOT ${MPI_TEST} )
MESSAGE( FATAL_ERROR "Skipping MPI search and default compile fails:\n${OUT_TXT}" )
ENDIF()
SET( MPI_C_FOUND TRUE )
SET( MPI_CXX_FOUND TRUE )
SET( MPI_Fortran_FOUND TRUE )
# Check if we specified the MPI directory
IF ( MPI_DIRECTORY )
# Check the provided MPI directory for include files
VERIFY_PATH( "${MPI_DIRECTORY}" )
IF ( EXISTS "${MPI_DIRECTORY}/include/mpi.h" )
SET( MPI_INCLUDE_PATH "${MPI_DIRECTORY}/include" )
ELSEIF ( EXISTS "${MPI_DIRECTORY}/Inc/mpi.h" )
SET( MPI_INCLUDE_PATH "${MPI_DIRECTORY}/Inc" )
ELSE()
MESSAGE( FATAL_ERROR "mpi.h not found in ${MPI_DIRECTORY}/include" )
ENDIF ()
INCLUDE_DIRECTORIES ( ${MPI_INCLUDE_PATH} )
SET ( MPI_INCLUDE ${MPI_INCLUDE_PATH} )
# Set MPI libraries
IF ( ${CMAKE_SYSTEM_NAME} STREQUAL "Windows" )
FIND_LIBRARY( MSMPI_LIB NAMES msmpi PATHS "${MPI_DIRECTORY}/Lib/x64" NO_DEFAULT_PATH )
FIND_LIBRARY( MSMPI_LIB NAMES msmpi PATHS "${MPI_DIRECTORY}/Lib/amd64" NO_DEFAULT_PATH )
FIND_LIBRARY( MSMPIFEC_LIB NAMES msmpifec PATHS "${MPI_DIRECTORY}/Lib/x64" NO_DEFAULT_PATH )
FIND_LIBRARY( MSMPIFEC_LIB NAMES msmpifec PATHS "${MPI_DIRECTORY}/Lib/amd64" NO_DEFAULT_PATH )
FIND_LIBRARY( MSMPIFMC_LIB NAMES msmpifmc PATHS "${MPI_DIRECTORY}/Lib/x64" NO_DEFAULT_PATH )
FIND_LIBRARY( MSMPIFMC_LIB NAMES msmpifmc PATHS "${MPI_DIRECTORY}/Lib/amd64" NO_DEFAULT_PATH )
SET( MPI_LIBRARIES ${MSMPI_LIB} ${MSMPIFEC_LIB} ${MSMPIFMC_LIB} )
ENDIF()
# Set the mpi executable
IF ( MPIEXEC )
# User specified the MPI command directly, use as is
ELSEIF ( MPIEXEC_CMD )
# User specified the name of the MPI executable
SET ( MPIEXEC ${MPI_DIRECTORY}/bin/${MPIEXEC_CMD} )
IF ( NOT EXISTS ${MPIEXEC} )
MESSAGE( FATAL_ERROR "${MPIEXEC_CMD} not found in ${MPI_DIRECTORY}/bin" )
ENDIF ()
ELSE ()
# Search for the MPI executable in the current directory
FIND_PROGRAM ( MPIEXEC NAMES mpiexec mpirun lamexec PATHS ${MPI_DIRECTORY}/bin NO_DEFAULT_PATH )
IF ( NOT MPIEXEC )
MESSAGE( FATAL_ERROR "Could not locate mpi executable" )
ENDIF()
ENDIF ()
# Set MPI flags
IF ( NOT MPIEXEC_NUMPROC_FLAG )
SET( MPIEXEC_NUMPROC_FLAG "-np" )
ENDIF()
ELSEIF ( MPI_COMPILER )
# The mpi compiler should take care of everything
IF ( MPI_INCLUDE )
INCLUDE_DIRECTORIES( ${MPI_INCLUDE} )
ENDIF()
ELSE()
# Perform the default search for MPI
INCLUDE ( FindMPI )
IF ( NOT MPI_FOUND )
MESSAGE( " MPI_INCLUDE = ${MPI_INCLUDE}" )
MESSAGE( " MPI_LINK_FLAGS = ${MPI_LINK_FLAGS}" )
MESSAGE( " MPI_LIBRARIES = ${MPI_LIBRARIES}" )
MESSAGE( FATAL_ERROR "Did not find MPI" )
ENDIF ()
INCLUDE_DIRECTORIES( "${MPI_INCLUDE_PATH}" )
SET( MPI_INCLUDE "${MPI_INCLUDE_PATH}" )
ENDIF()
STRING( STRIP "${MPI_CXX_COMPILE_FLAGS}" MPI_CXX_COMPILE_FLAGS )
STRING( STRIP "${MPI_CXX_LINK_FLAGS}" MPI_CXX_LINK_FLAGS )
STRING( STRIP "${MPI_CXX_LIBRARIES}" MPI_CXX_LIBRARIES )
MESSAGE( " MPI_CXX_FOUND = ${MPI_CXX_FOUND}" )
MESSAGE( " MPI_CXX_COMPILER = ${MPI_CXX_COMPILER}" )
MESSAGE( " MPI_CXX_COMPILE_FLAGS = ${MPI_CXX_COMPILE_FLAGS}" )
MESSAGE( " MPI_CXX_INCLUDE_PATH = ${MPI_CXX_INCLUDE_PATH}" )
MESSAGE( " MPI_CXX_LINK_FLAGS = ${MPI_CXX_LINK_FLAGS}" )
MESSAGE( " MPI_CXX_LIBRARIES = ${MPI_CXX_LIBRARIES}" )
MESSAGE( " MPIEXEC = ${MPIEXEC}" )
MESSAGE( " MPIEXEC_NUMPROC_FLAG = ${MPIEXEC_NUMPROC_FLAG}" )
MESSAGE( " MPIEXEC_PREFLAGS = ${MPIEXEC_PREFLAGS}" )
MESSAGE( " MPIEXEC_POSTFLAGS = ${MPIEXEC_POSTFLAGS}" )
ADD_DEFINITIONS( -DUSE_MPI )
INCLUDE_DIRECTORIES( ${MPI_CXX_INCLUDE_PATH} )
SET( MPI_LIBRARIES ${MPI_CXX_LIBRARIES} )
SET( MPI_LINK_FLAGS ${MPI_CXX_LINK_FLAGS} )
IF ( NOT MPI_CXX_FOUND )
MESSAGE( FATAL_ERROR "MPI not found" )
# Check if we need to use MPI for serial tests
CHECK_ENABLE_FLAG( USE_MPI_FOR_SERIAL_TESTS 0 )
# Set defaults if they have not been set
IF ( NOT MPIEXEC )
SET( MPIEXEC mpirun )
ENDIF()
IF ( USE_MPI AND NOT MPIEXEC )
MESSAGE( FATAL_ERROR "Unable to find MPIEXEC, please set it before continuing" )
IF ( NOT MPIEXEC_NUMPROC_FLAG )
SET( MPIEXEC_NUMPROC_FLAG "-np" )
ENDIF()
# Set the definitions
ADD_DEFINITIONS( "-DUSE_MPI" )
MESSAGE( "Using MPI" )
MESSAGE( " MPIEXEC = ${MPIEXEC}" )
MESSAGE( " MPIEXEC_NUMPROC_FLAG = ${MPIEXEC_NUMPROC_FLAG}" )
MESSAGE( " MPI_INCLUDE = ${MPI_INCLUDE}" )
MESSAGE( " MPI_LINK_FLAGS = ${MPI_LINK_FLAGS}" )
MESSAGE( " MPI_LIBRARIES = ${MPI_LIBRARIES}" )
ELSE()
SET( USE_MPI_FOR_SERIAL_TESTS 0 )
SET( MPIEXEC "" )
SET( MPIEXEC_NUMPROC_FLAG "" )
SET( MPI_INCLUDE "" )
SET( MPI_LINK_FLAGS "" )
SET( MPI_LIBRARIES "" )
MESSAGE( "Not using MPI, all parallel tests will be disabled" )
ENDIF()
ENDMACRO()
@@ -103,12 +135,12 @@ ENDMACRO()
# Macro to find and configure hdf5
MACRO ( CONFIGURE_HDF5 )
CHECK_ENABLE_FLAG( USE_HDF5 0 )
IF ( USE_HDF5 AND NOT FOUND_HDF5 )
# Check if we specified the hdf5 directory
IF ( USE_HDF5 )
# Check if we specified the silo 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,8 +150,6 @@ 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}" )
@@ -153,7 +183,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} ${EXTERNAL_LIBS} )
SET( EXTERNAL_LIBS ${NETCDF_LIBS} ${HDF5_LIBS} ${EXTERNAL_LIBS} )
ADD_DEFINITIONS ( -DUSE_NETCDF )
MESSAGE( "Using netcdf" )
MESSAGE( " ${NETCDF_LIBS}" )
@@ -181,7 +211,7 @@ MACRO ( CONFIGURE_SILO )
SET ( SILO_LIBS
${SILO_LIB}
)
SET( EXTERNAL_LIBS ${SILO_LIBS} ${EXTERNAL_LIBS} )
SET( EXTERNAL_LIBS ${SILO_LIBS} ${HDF5_LIBS} ${EXTERNAL_LIBS} )
ADD_DEFINITIONS ( -DUSE_SILO )
MESSAGE( "Using silo" )
MESSAGE( " ${SILO_LIB}" )
@@ -263,7 +293,7 @@ ENDMACRO ()
# Macro to configure LBPM specific options
MACRO ( CONFIGURE_LBPM )
# Set the maximum number of processors for the tests
IF ( NOT DEFINED TEST_MAX_PROCS )
IF ( NOT TEST_MAX_PROCS )
SET( TEST_MAX_PROCS 32 )
ENDIF()
# Add the correct paths to rpath in case we build shared libraries
@@ -275,9 +305,4 @@ MACRO ( CONFIGURE_LBPM )
SET( CMAKE_BUILD_WITH_INSTALL_RPATH TRUE )
SET( CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} "${TIMER_DIRECTORY}" "${LBPM_INSTALL_DIR}/lib" )
ENDIF()
# Suppress some common warnings
IF ( USING_GCC )
SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder -Wno-unused-parameter")
SET( CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --compiler-options -Wno-reorder,-Wno-unused-parameter")
ENDIF()
ENDMACRO ()

View File

@@ -1,9 +1,3 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.10.0)
CMAKE_POLICY( SET CMP0057 NEW )
if( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.20.0")
CMAKE_POLICY( SET CMP0115 OLD )
endif()
INCLUDE(CheckCCompilerFlag)
INCLUDE(CheckCSourceCompiles)
INCLUDE(CheckCXXCompilerFlag)
@@ -53,24 +47,12 @@ ELSEIF( NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION )
ENDIF()
# Check for gold linker
IF ( UNIX AND NOT APPLE AND NOT DISABLE_GOLD )
EXECUTE_PROCESS( COMMAND ${CMAKE_CXX_COMPILER} -fuse-ld=gold -Wl,--version ERROR_QUIET OUTPUT_VARIABLE LD_VERSION )
IF ( "${LD_VERSION}" MATCHES "GNU gold" )
MESSAGE( "Using gold linker" )
SET( GOLD_LINK_FLAGS "-fuse-ld=gold -Wl,--disable-new-dtags -Wl,--no-map-whole-files" )
SET( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GOLD_LINK_FLAGS}" )
SET( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GOLD_LINK_FLAGS}" )
ENDIF()
ENDIF()
# Add some default targets if they do not exist
IF ( NOT TARGET copy-${PROJ}-Data )
ADD_CUSTOM_TARGET( copy-${PROJ}-Data ALL )
ENDIF()
IF ( NOT TARGET copy-${PROJ}-include )
ADD_CUSTOM_TARGET( copy-${PROJ}-include ALL )
ADD_CUSTOM_TARGET ( copy-${PROJ}-include ALL )
ENDIF()
@@ -93,7 +75,7 @@ ENDMACRO()
MACRO( PRINT_ALL_VARIABLES )
GET_CMAKE_PROPERTY(_variableNames VARIABLES)
FOREACH(_variableName ${_variableNames})
MESSAGE(STATUS "${_variableName}=${${_variableName}}")
message(STATUS "${_variableName}=${${_variableName}}")
ENDFOREACH()
ENDMACRO()
@@ -126,28 +108,28 @@ MACRO( CONVERT_M4_FORTRAN IN LOCAL_PATH OUT_PATH )
IF ( NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/${OUT_PATH}" )
FILE(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${OUT_PATH}" )
ENDIF()
CONFIGURE_FILE( ${IN} ${IN} COPYONLY )
CONFIGURE_FILE ( ${IN} ${IN} COPYONLY )
IF ("${CMAKE_GENERATOR}" STREQUAL "Xcode")
STRING(REGEX REPLACE ".F" ".o" OUT2 "${OUT}" )
STRING(REGEX REPLACE ";" " " COMPILE_CMD "${CMAKE_Fortran_COMPILER} -c ${OUT} ${CMAKE_Fortran_FLAGS} -o ${OUT2}")
STRING(REGEX REPLACE "\\\\" "" COMPILE_CMD "${COMPILE_CMD}")
MESSAGE("COMPILE_CMD = ${COMPILE_CMD}")
SET( COMPILE_CMD ${COMPILE_CMD} )
ADD_CUSTOM_COMMAND(
add_custom_command(
OUTPUT ${OUT2}
COMMAND m4 -I${LOCAL_PATH} -I${SAMRAI_FORTDIR} ${M4DIRS} ${IN} > ${OUT}
COMMAND ${COMPILE_CMD}
DEPENDS ${IN}
)
SET_SOURCE_FILES_PROPERTIES(${OUT2} PROPERTIES GENERATED true)
set_source_files_properties(${OUT2} PROPERTIES GENERATED true)
SET( SOURCES ${SOURCES} "${OUT2}" )
ELSE()
ADD_CUSTOM_COMMAND(
add_custom_command(
OUTPUT ${OUT}
COMMAND m4 -I${LOCAL_PATH} -I${SAMRAI_FORTDIR} ${M4DIRS} ${M4_OPTIONS} ${IN} > ${OUT}
DEPENDS ${IN}
)
SET_SOURCE_FILES_PROPERTIES(${OUT} PROPERTIES GENERATED true)
set_source_files_properties(${OUT} PROPERTIES GENERATED true)
SET( SOURCES ${SOURCES} "${OUT}" )
ENDIF()
ENDMACRO()
@@ -163,10 +145,6 @@ ENDMACRO()
# Add a project executable
MACRO( ADD_${PROJ}_EXECUTABLE EXEFILE )
IF ( TARGET ${EXEFILE} AND NOT INCLUDE_${EXEFILE} )
MESSAGE( FATAL_ERROR "ADD_${PROJ}_EXECUTABLE should be called before adding tests" )
ENDIF()
SET( INCLUDE_${EXEFILE} TRUE )
ADD_PROJ_PROVISIONAL_TEST( ${EXEFILE} )
INSTALL( TARGETS ${EXEFILE} DESTINATION ${${PROJ}_INSTALL_DIR}/bin )
ENDMACRO()
@@ -186,7 +164,7 @@ ENDMACRO ()
# Find the source files
MACRO( FIND_FILES )
MACRO (FIND_FILES)
# Find the C/C++ headers
SET( T_HEADERS "" )
FILE( GLOB T_HEADERS "*.h" "*.H" "*.hh" "*.hpp" "*.I" )
@@ -215,7 +193,7 @@ MACRO( FIND_FILES )
SET( CSOURCES ${CSOURCES} ${T_CSOURCES} )
SET( FSOURCES ${FSOURCES} ${T_FSOURCES} )
SET( M4FSOURCES ${M4FSOURCES} ${T_M4FSOURCES} )
SET( SOURCES ${SOURCES} ${T_CXXSOURCES} ${T_CSOURCES} ${T_FSOURCES} ${T_M4FSOURCES} ${CUDASOURCES} )
SET( SOURCES ${SOURCES} ${T_CXXSOURCES} ${T_CSOURCES} ${T_FSOURCES} ${T_M4FSOURCES} )
ENDMACRO()
@@ -325,7 +303,7 @@ MACRO( INSTALL_${PROJ}_TARGET PACKAGE )
IF ( TARGET write_repo_version )
ADD_DEPENDENCIES( ${PACKAGE} write_repo_version )
ENDIF()
ADD_DEPENDENCIES( ${PACKAGE} copy-${PROJ}-include )
ADD_DEPENDENCIES ( ${PACKAGE} copy-${PROJ}-include )
IF ( NOT ${PROJ}_LIB )
INSTALL( TARGETS ${PACKAGE} DESTINATION ${${PROJ}_INSTALL_DIR}/lib )
ENDIF()
@@ -362,7 +340,7 @@ ENDMACRO()
# Macro to verify that a path has been set
MACRO( VERIFY_PATH PATH_NAME )
IF ("${PATH_NAME}" STREQUAL "")
MESSAGE( FATAL_ERROR "Path is not set: ${PATH_NAME}" )
MESSAGE ( FATAL_ERROR "Path is not set: ${PATH_NAME}" )
ENDIF()
IF ( NOT EXISTS "${PATH_NAME}" )
MESSAGE( FATAL_ERROR "Path does not exist: ${PATH_NAME}" )
@@ -442,9 +420,6 @@ MACRO( IDENTIFY_COMPILER )
ELSEIF ( ${CMAKE_Fortran_COMPILER_ID} MATCHES "PGI")
SET(USING_PGF90 TRUE)
MESSAGE("Using pgf90")
ELSEIF( (${CMAKE_Fortran_COMPILER_ID} MATCHES "CRAY") OR (${CMAKE_Fortran_COMPILER_ID} MATCHES "Cray") )
SET(USING_CRAY TRUE)
MESSAGE("Using Cray")
ELSEIF ( (${CMAKE_Fortran_COMPILER_ID} MATCHES "CLANG") OR (${CMAKE_Fortran_COMPILER_ID} MATCHES "Clang") OR
(${CMAKE_Fortran_COMPILER_ID} MATCHES "FLANG") OR (${CMAKE_Fortran_COMPILER_ID} MATCHES "Flang") )
SET(USING_FLANG TRUE)
@@ -465,7 +440,7 @@ MACRO( SET_WARNINGS )
# Note: adding -Wlogical-op causes a wierd linking error on Titan using the nvcc wrapper:
# /usr/bin/ld: cannot find gical-op: No such file or directory
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic -Woverloaded-virtual -Wsign-compare -Wformat-security")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Woverloaded-virtual -Wsign-compare")
ELSEIF ( USING_MSVC )
# Add Microsoft specifc compiler options
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _SCL_SECURE_NO_WARNINGS /D _CRT_SECURE_NO_WARNINGS /D _ITERATOR_DEBUG_LEVEL=0 /wd4267" )
@@ -473,7 +448,7 @@ MACRO( SET_WARNINGS )
ELSEIF ( USING_ICC )
# Add Intel specifc compiler options
SET(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -Wall" )
SET(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -Wall -wd1011" )
SET(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -Wall" )
ELSEIF ( USING_CRAY )
# Add default compiler options
SET(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS}")
@@ -486,8 +461,8 @@ MACRO( SET_WARNINGS )
SET(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} --diag_suppress 111,128,185")
ELSEIF ( USING_CLANG )
# Add default compiler options
SET(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -Wall -Wextra")
SET(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -Wno-missing-braces -Wmissing-field-initializers -ftemplate-depth=1024")
SET(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -Wall")
SET(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -Wall -Wno-missing-braces -Wmissing-field-initializers -ftemplate-depth=1024")
ELSEIF ( USING_XL )
# Add default compiler options
SET(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -Wall")
@@ -676,7 +651,7 @@ MACRO( COPY_MESH_FILE MESHNAME )
ENDFOREACH()
# We have either found the mesh or failed
IF ( NOT MESHPATH )
MESSAGE( WARNING "Cannot find mesh: " ${MESHNAME} )
MESSAGE ( WARNING "Cannot find mesh: " ${MESHNAME} )
ELSE ()
SET( MESHPATH2 )
FOREACH( tmp ${MESHPATH} )
@@ -691,16 +666,25 @@ ENDMACRO()
# Link the libraries to the given target
MACRO( TARGET_LINK_EXTERNAL_LIBRARIES TARGET_NAME )
# Include external libraries
FOREACH ( tmp ${EXTERNAL_LIBS} )
TARGET_LINK_LIBRARIES( ${TARGET_NAME} ${ARGN} ${tmp} )
ENDFOREACH()
# Include libraries found through the TPL builder
FOREACH ( tmp ${TPL_LIBS} )
TARGET_LINK_LIBRARIES( ${TARGET_NAME} ${ARGN} ${tmp} )
ENDFOREACH()
# Include CMake implicit libraries
FOREACH ( tmp ${CMAKE_CUDA_IMPLICIT_LINK_LIBRARIES} ${CMAKE_C_IMPLICIT_LINK_LIBRARIES}
FOREACH ( tmp ${EXTERNAL_LIBS} )
TARGET_LINK_LIBRARIES( ${TARGET_NAME} ${ARGN} ${tmp} )
ENDFOREACH()
FOREACH ( tmp ${LAPACK_LIBS} )
TARGET_LINK_LIBRARIES( ${TARGET_NAME} ${ARGN} ${tmp} )
ENDFOREACH()
FOREACH ( tmp ${BLAS_LIBS} )
TARGET_LINK_LIBRARIES( ${TARGET_NAME} ${ARGN} ${tmp} )
ENDFOREACH()
FOREACH ( tmp ${BLAS_LAPACK_LIBS} )
TARGET_LINK_LIBRARIES( ${TARGET_NAME} ${ARGN} ${tmp} )
ENDFOREACH()
FOREACH ( MPI_LIBRARIES )
TARGET_LINK_LIBRARIES( ${EXE} ${ARGN} ${tmp} )
ENDFOREACH()
FOREACH ( tmp ${CMAKE_C_IMPLICIT_LINK_LIBRARIES}
${CMAKE_CXX_IMPLICIT_LINK_LIBRARIES} ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES} )
TARGET_LINK_LIBRARIES( ${TARGET_NAME} ${ARGN} ${tmp} )
ENDFOREACH()
@@ -731,8 +715,8 @@ ENDFUNCTION()
MACRO( ADD_PROJ_EXE_DEP EXE )
# Add the package dependencies
IF( ${PROJ}_TEST_LIB_EXISTS )
ADD_DEPENDENCIES( ${EXE} ${PACKAGE_TEST_LIB} )
TARGET_LINK_LIBRARIES( ${EXE} ${PACKAGE_TEST_LIB} )
ADD_DEPENDENCIES ( ${EXE} ${PACKAGE_TEST_LIB} )
TARGET_LINK_LIBRARIES ( ${EXE} ${PACKAGE_TEST_LIB} )
ENDIF()
# Add the executable to the dependencies of check and build-test
ADD_DEPENDENCIES( check ${EXE} )
@@ -799,7 +783,7 @@ FUNCTION( ADD_PROJ_PROVISIONAL_TEST EXEFILE )
SET( CXXFILE ${EXEFILE} )
SET( TESTS_SO_FAR ${TESTS_SO_FAR} ${EXEFILE} )
# Check if we want to add the test to all
IF ( NOT EXCLUDE_TESTS_FROM_ALL OR INCLUDE_${EXEFILE} )
IF ( NOT EXCLUDE_TESTS_FROM_ALL )
ADD_EXECUTABLE( ${EXEFILE} ${CXXFILE} )
ELSE()
ADD_EXECUTABLE( ${EXEFILE} EXCLUDE_FROM_ALL ${CXXFILE} )
@@ -834,218 +818,123 @@ MACRO( CREATE_TEST_NAME TEST ${ARGN} )
FOREACH( tmp ${ARGN})
SET( TESTNAME "${TESTNAME}--${tmp}")
endforeach()
# STRING(REGEX REPLACE "--" "-" TESTNAME ${TESTNAME} )
SET( LAST_TESTNAME ${TESTNAME} PARENT_SCOPE )
ENDMACRO()
# Function to add the resource locks to an executable
FUNCTION( ADD_RESOURCE TESTNAME RESOURCE )
SET_TESTS_PROPERTIES( ${TESTNAME} PROPERTIES RESOURCE_LOCK ${RESOURCE} )
ENDFUNCTION()
FUNCTION( ADD_RESOURCE_LOCKS TESTNAME EXEFILE ${ARGN} )
FUNCTION( ADD_RESOURCE_LOCK TESTNAME EXEFILE ${ARGN} )
IF ( NOT DISABLE_RESOURCE_LOCK )
IF ( NOT ARGN )
ADD_RESOURCE( ${TESTNAME} ${EXEFILE} )
SET_TESTS_PROPERTIES( ${TESTNAME} PROPERTIES RESOURCE_LOCK ${EXEFILE} )
ELSE()
FOREACH( tmp ${ARGN} )
ADD_RESOURCE( ${TESTNAME} ${tmp} )
SET_TESTS_PROPERTIES( ${TESTNAME} PROPERTIES RESOURCE_LOCK ${tmp} )
ENDFOREACH()
ENDIF()
ENDIF()
ENDFUNCTION()
# Function to add a test
FUNCTION( CALL_ADD_TEST EXEFILE PROCS THREADS WEEKLY TESTBUILDER ${ARGN} )
# Add a executable as a test
FUNCTION( ADD_${PROJ}_TEST EXEFILE ${ARGN} )
# Check if we actually want to add the test
KEEP_TEST( RESULT )
IF ( NOT RESULT )
MESSAGE( "Discarding test: ${EXEFILE}" )
RETURN()
ENDIF()
# Check if we are dealing with a TestBuilder test
IF ( ${TESTBUILDER} )
# Add the test to the TestBuilder sources
SET( TESTBUILDER_SOURCES ${TESTBUILDER_SOURCES} ${EXEFILE} PARENT_SCOPE )
# Add the provisional test
ADD_PROJ_PROVISIONAL_TEST( ${EXEFILE} )
CREATE_TEST_NAME( ${EXEFILE} ${ARGN} )
IF ( USE_MPI_FOR_SERIAL_TESTS )
ADD_TEST( NAME ${TESTNAME} COMMAND ${MPIEXEC} "${MPIEXEC_NUMPROC_FLAG}" 1 $<TARGET_FILE:${LAST_TEST}> ${ARGN} )
SET_PROPERTY( TEST ${TESTNAME} APPEND PROPERTY ENVIRONMENT OMPI_MCA_hwloc_base_binding_policy=none )
ELSE()
# Add the provisional test
ADD_PROJ_PROVISIONAL_TEST( ${EXEFILE} )
ADD_TEST( NAME ${TESTNAME} COMMAND $<TARGET_FILE:${LAST_TEST}> ${ARGN} )
ENDIF()
# Create the test name
SET( TESTNAME ${EXEFILE} )
#IF ( ${TESTBUILDER} )
# SET( TESTNAME TB_${TESTNAME} )
#ENDIF()
IF ( "${PROCS}" GREATER "1")
SET( TESTNAME ${TESTNAME}_${PROCS}procs )
SET_TESTS_PROPERTIES( ${TESTNAME} PROPERTIES FAIL_REGULAR_EXPRESSION "${TEST_FAIL_REGULAR_EXPRESSION}" PROCESSORS 1 )
ADD_RESOURCE_LOCK( ${TESTNAME} ${EXEFILE} ${ARGN} )
ENDFUNCTION()
# Add a executable as a weekly test
FUNCTION( ADD_${PROJ}_WEEKLY_TEST EXEFILE PROCS ${ARGN} )
# Check if we actually want to add the test
KEEP_TEST( RESULT )
IF ( NOT RESULT )
RETURN()
ENDIF()
IF ( "${THREADS}" GREATER "1")
SET( TESTNAME ${TESTNAME}_${THREADS}threads )
# Add the provisional test
ADD_PROJ_PROVISIONAL_TEST( ${EXEFILE} )
IF( ${PROCS} STREQUAL "1" )
CREATE_TEST_NAME( "${EXEFILE}_WEEKLY" ${ARGN} )
ELSEIF( (USE_MPI OR USE_EXT_MPI) AND NOT (${PROCS} GREATER ${TEST_MAX_PROCS}) )
CREATE_TEST_NAME( "${EXEFILE}_${PROCS}procs_WEEKLY" ${ARGN} )
ENDIF()
IF ( ${WEEKLY} )
SET( TESTNAME ${TESTNAME}_WEEKLY )
ENDIF()
CREATE_TEST_NAME( ${TESTNAME} ${ARGN} )
# Create the tests for ctest
MATH( EXPR TOT_PROCS "${PROCS} * ${THREADS}" )
IF ( ${TOT_PROCS} EQUAL 0 )
# Skip test (provisional)
ELSEIF ( ${TOT_PROCS} GREATER ${TEST_MAX_PROCS} )
IF ( ${PROCS} GREATER ${TEST_MAX_PROCS} )
MESSAGE("Disabling test ${TESTNAME} (exceeds maximum number of processors ${TEST_MAX_PROCS})")
ELSEIF ( ( ${PROCS} STREQUAL "1" ) AND NOT USE_MPI_FOR_SERIAL_TESTS )
IF ( ${TESTBUILDER} )
ADD_TEST( NAME ${TESTNAME} COMMAND $<TARGET_FILE:${TB_TARGET}> ${EXEFILE} ${ARGN} )
ELSEIF( ${PROCS} STREQUAL "1" )
CREATE_TEST_NAME( "${EXEFILE}_WEEKLY" ${ARGN} )
IF ( USE_MPI_FOR_SERIAL_TESTS )
ADD_TEST( NAME ${TESTNAME} COMMAND ${MPIEXEC} "${MPIEXEC_NUMPROC_FLAG}" 1 $<TARGET_FILE:${LAST_TEST}> ${ARGN} )
SET_PROPERTY( TEST ${TESTNAME} APPEND PROPERTY ENVIRONMENT OMPI_MCA_hwloc_base_binding_policy=none )
ELSE()
ADD_TEST( NAME ${TESTNAME} COMMAND $<TARGET_FILE:${LAST_TEST}> ${ARGN} )
ENDIF()
SET_TESTS_PROPERTIES( ${TESTNAME} PROPERTIES FAIL_REGULAR_EXPRESSION "${TEST_FAIL_REGULAR_EXPRESSION}" PROCESSORS ${TOT_PROCS} )
ADD_RESOURCE_LOCKS( ${TESTNAME} ${EXEFILE} ${ARGN} )
ELSEIF ( USE_MPI OR USE_EXT_MPI )
IF ( ${TESTBUILDER} )
ADD_TEST( NAME ${TESTNAME} COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${PROCS} $<TARGET_FILE:${TB_TARGET}> ${EXEFILE} ${ARGN} )
ELSE()
ADD_TEST( NAME ${TESTNAME} COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${PROCS} $<TARGET_FILE:${LAST_TEST}> ${ARGN} )
ENDIF()
SET_TESTS_PROPERTIES( ${TESTNAME} PROPERTIES FAIL_REGULAR_EXPRESSION "${TEST_FAIL_REGULAR_EXPRESSION}" PROCESSORS 1 )
ADD_RESOURCE_LOCK( ${TESTNAME} ${EXEFILE} ${ARGN} )
ELSEIF( (USE_MPI OR USE_EXT_MPI) AND NOT (${PROCS} GREATER ${TEST_MAX_PROCS}) )
CREATE_TEST_NAME( "${EXEFILE}_${PROCS}procs_WEEKLY" ${ARGN} )
ADD_TEST( NAME ${TESTNAME} COMMAND ${MPIEXEC} "${MPIEXEC_NUMPROC_FLAG}" ${PROCS} $<TARGET_FILE:${LAST_TEST}> ${ARGN} )
SET_TESTS_PROPERTIES( ${TESTNAME} PROPERTIES FAIL_REGULAR_EXPRESSION "${TEST_FAIL_REGULAR_EXPRESSION}" PROCESSORS ${PROCS} )
SET_PROPERTY( TEST ${TESTNAME} APPEND PROPERTY ENVIRONMENT OMPI_MCA_hwloc_base_binding_policy=none )
SET_TESTS_PROPERTIES( ${TESTNAME} PROPERTIES FAIL_REGULAR_EXPRESSION "${TEST_FAIL_REGULAR_EXPRESSION}" PROCESSORS ${TOT_PROCS} )
ADD_RESOURCE_LOCKS( ${TESTNAME} ${EXEFILE} ${ARGN} )
ADD_RESOURCE_LOCK( ${TESTNAME} ${EXEFILE} ${ARGN} )
ENDIF()
ENDFUNCTION()
# Functions to create a test builder
FUNCTION( INITIALIZE_TESTBUILDER )
SET( TESTBUILDER_SOURCES PARENT_SCOPE )
# Add a executable as a parallel test
FUNCTION( ADD_${PROJ}_TEST_PARALLEL EXEFILE PROCS ${ARGN} )
# Check if we actually want to add the test
KEEP_TEST( RESULT )
IF ( NOT RESULT )
RETURN()
ENDIF()
# Check if the target does not exist (may not be added yet or we are re-configuring)
STRING(REGEX REPLACE "${${PROJ}_SOURCE_DIR}/" "" TB_TARGET "TB-${PROJ}-${CMAKE_CURRENT_SOURCE_DIR}" )
STRING(REGEX REPLACE "/" "-" TB_TARGET ${TB_TARGET} )
IF ( NOT TARGET ${TB_TARGET} )
GLOBAL_SET( ${TB_TARGET}-BINDIR )
# Add the provisional test
ADD_PROJ_PROVISIONAL_TEST( ${EXEFILE} )
CREATE_TEST_NAME( "${EXEFILE}_${PROCS}procs" ${ARGN} )
IF ( NOT ( USE_MPI OR USE_EXT_MPI ) )
MESSAGE("Disabling test ${TESTNAME} (configured without MPI)")
ELSEIF ( ${PROCS} GREATER ${TEST_MAX_PROCS} )
MESSAGE("Disabling test ${TESTNAME} (exceeds maximum number of processors ${TEST_MAX_PROCS})")
ELSE()
ADD_TEST( NAME ${TESTNAME} COMMAND ${MPIEXEC} "${MPIEXEC_NUMPROC_FLAG}" ${PROCS} $<TARGET_FILE:${LAST_TEST}> ${ARGN} )
SET_PROPERTY( TEST ${TESTNAME} APPEND PROPERTY ENVIRONMENT OMPI_MCA_hwloc_base_binding_policy=none )
SET_TESTS_PROPERTIES( ${TESTNAME} PROPERTIES FAIL_REGULAR_EXPRESSION "${TEST_FAIL_REGULAR_EXPRESSION}" PROCESSORS ${PROCS} )
ADD_RESOURCE_LOCK( ${TESTNAME} ${EXEFILE} ${ARGN} )
ENDIF()
# Check if test has already been added
IF ( NOT ${TB_TARGET}-BINDIR )
GLOBAL_SET( ${TB_TARGET}-BINDIR "${CMAKE_CURRENT_BINARY_DIR}" )
# Create the initial file
IF ( NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/TestBuilder.cpp" )
FILE( WRITE "${CMAKE_CURRENT_BINARY_DIR}/TestBuilder.cpp" "// Auto generated file\n\n" )
ENDIF()
# The target has not been added
SET( CXXFILE "${CMAKE_CURRENT_BINARY_DIR}/TestBuilder.cpp" )
SET( TESTS_SO_FAR ${TESTS_SO_FAR} ${TB_TARGET} )
# Check if we want to add the test to all
IF ( NOT EXCLUDE_TESTS_FROM_ALL )
ADD_EXECUTABLE( ${TB_TARGET} ${CXXFILE} )
ELSE()
ADD_EXECUTABLE( ${TB_TARGET} EXCLUDE_FROM_ALL ${CXXFILE} )
ENDIF()
SET_TARGET_PROPERTIES( ${TB_TARGET} PROPERTIES OUTPUT_NAME "TB" )
ELSEIF ( NOT ${TB-BINDIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR} )
# We are trying to add 2 different tests with the same name
MESSAGE( "Existing test: ${TB-BINDIR}/${TB_TARGET}" )
MESSAGE( "New test: ${CMAKE_CURRENT_BINARY_DIR}/${TB_TARGET}}" )
MESSAGE( FATAL_ERROR "Trying to add 2 different tests with the same name" )
ENDIF()
SET( TB_TARGET ${TB_TARGET} PARENT_SCOPE )
ENDFUNCTION()
FUNCTION( FINALIZE_TESTBUILDER )
# Check if we actually want to add the test
KEEP_TEST( RESULT )
IF ( NOT RESULT )
RETURN()
ENDIF()
# Create the library for the test builder
IF ( TESTBUILDER_SOURCES )
LIST( REMOVE_DUPLICATES TESTBUILDER_SOURCES )
SET( TB_TARGET_SOURCES "${CMAKE_CURRENT_BINARY_DIR}/TestBuilder.cpp" )
FOREACH ( tmp ${TESTBUILDER_SOURCES} )
GET_FILENAME_COMPONENT( tmp ${tmp} ABSOLUTE )
SET( TB_TARGET_SOURCES ${TB_TARGET_SOURCES} ${tmp} )
ENDFOREACH()
TARGET_SOURCES( ${TB_TARGET} PUBLIC ${TB_TARGET_SOURCES} )
ADD_DEPENDENCIES( ${TB_TARGET} copy-${PROJ}-include )
ENDIF()
# Add the dependencies to the test builder
ADD_PROJ_EXE_DEP( ${TB_TARGET} )
IF ( CURRENT_LIBRARY )
IF ( NOT TARGET ${CURRENT_LIBRARY}-test )
ADD_CUSTOM_TARGET( ${CURRENT_LIBRARY}-test )
ENDIF()
ADD_DEPENDENCIES( ${CURRENT_LIBRARY}-test ${TB_TARGET} )
ENDIF()
SET( TB_TARGET ${TB_TARGET} PARENT_SCOPE )
# Finish generating TestBuilder.cpp
SET( TB_FILE "${CMAKE_CURRENT_BINARY_DIR}/TestBuilder-tmp.cpp" )
FILE( WRITE "${TB_FILE}" "// Auto generated file\n\n" )
FILE( APPEND "${TB_FILE}" "#include <cstring>\n" )
FILE( APPEND "${TB_FILE}" "#include <iostream>\n\n" )
FOREACH( tmp ${TESTBUILDER_SOURCES} )
FILE( APPEND "${TB_FILE}" "extern int ${tmp}( int argc, char *argv[] );\n" )
ENDFOREACH()
FILE( APPEND "${TB_FILE}" "\n\n// Main Program\n" )
FILE( APPEND "${TB_FILE}" "int main( int argc, char *argv[] )\n" )
FILE( APPEND "${TB_FILE}" "{\n" )
FILE( APPEND "${TB_FILE}" " if ( argc < 2 ) {\n" )
FILE( APPEND "${TB_FILE}" " std::cerr << \"Invaild number of arguments for TestBuilder\";\n " )
FILE( APPEND "${TB_FILE}" " return 1;\n" )
FILE( APPEND "${TB_FILE}" " }\n\n" )
FILE( APPEND "${TB_FILE}" " int rtn = 0;\n" )
FILE( APPEND "${TB_FILE}" " if ( strcmp( argv[1], \"NULL\" ) == 0 ) {\n" )
FOREACH( tmp ${TESTBUILDER_SOURCES} )
FILE( APPEND "${TB_FILE}" " } else if ( strcmp( argv[1], \"${tmp}\" ) == 0 ) {\n" )
FILE( APPEND "${TB_FILE}" " rtn = ${tmp}( argc-1, &argv[1] );\n" )
ENDFOREACH()
FILE( APPEND "${TB_FILE}" " } else {\n" )
FILE( APPEND "${TB_FILE}" " std::cerr << \"Unknown test\";\n" )
FILE( APPEND "${TB_FILE}" " return 1;\n" )
FILE( APPEND "${TB_FILE}" " }\n\n" )
FILE( APPEND "${TB_FILE}" " return rtn;\n" )
FILE( APPEND "${TB_FILE}" "}\n" )
EXECUTE_PROCESS( COMMAND ${CMAKE_COMMAND} -E copy_if_different "${TB_FILE}" "${CMAKE_CURRENT_BINARY_DIR}/TestBuilder.cpp" )
ENDFUNCTION()
# Convience functions to add a test
MACRO( ADD_${PROJ}_TEST EXEFILE ${ARGN} )
CALL_ADD_TEST( ${EXEFILE} 1 1 FALSE FALSE ${ARGN} )
ENDMACRO()
MACRO( ADD_${PROJ}_TEST_PARALLEL EXEFILE PROCS ${ARGN} )
CALL_ADD_TEST( ${EXEFILE} ${PROCS} 1 FALSE FALSE ${ARGN} )
ENDMACRO()
MACRO( ADD_${PROJ}_WEEKLY_TEST EXEFILE PROCS ${ARGN} )
CALL_ADD_TEST( ${EXEFILE} ${PROCS} 1 TRUE FALSE ${ARGN} )
ENDMACRO()
# Add a parallel test that may use both MPI and threads
# This allows us to correctly compute the number of processors used by the test
MACRO( ADD_${PROJ}_TEST_THREAD_MPI EXEFILE PROCS THREADS ${ARGN} )
CALL_ADD_TEST( ${EXEFILE} ${PROCS} ${THREADS} FALSE FALSE ${ARGN} )
ENDMACRO()
MACRO( ADD_${PROJ}_TEST_1_2_4 EXEFILE ${ARGN} )
CALL_ADD_TEST( ${EXEFILE} 1 1 FALSE FALSE ${ARGN} )
CALL_ADD_TEST( ${EXEFILE} 2 1 FALSE FALSE ${ARGN} )
CALL_ADD_TEST( ${EXEFILE} 4 1 FALSE FALSE ${ARGN} )
ENDMACRO()
MACRO( ADD_TB_PROVISIONAL_TEST EXEFILE ${ARGN} )
CALL_ADD_TEST( ${EXEFILE} 0 1 FALSE TRUE ${ARGN} )
ENDMACRO()
MACRO( ADD_TB_TEST EXEFILE ${ARGN} )
CALL_ADD_TEST( ${EXEFILE} 1 1 FALSE TRUE ${ARGN} )
ENDMACRO()
MACRO( ADD_TB_TEST_PARALLEL EXEFILE PROCS ${ARGN} )
CALL_ADD_TEST( ${EXEFILE} ${PROCS} 1 FALSE TRUE ${ARGN} )
ENDMACRO()
MACRO( ADD_TB_WEEKLY_TEST EXEFILE PROCS ${ARGN} )
CALL_ADD_TEST( ${EXEFILE} ${PROCS} 1 TRUE TRUE ${ARGN} )
ENDMACRO()
MACRO( ADD_TB_TEST_THREAD_MPI EXEFILE PROCS THREADS ${ARGN} )
CALL_ADD_TEST( ${EXEFILE} ${PROCS} ${THREADS} FALSE TRUE ${ARGN} )
ENDMACRO()
MACRO( ADD_TB_TEST_1_2_4 EXEFILE ${ARGN} )
CALL_ADD_TEST( ${EXEFILE} 1 1 FALSE TRUE ${ARGN} )
CALL_ADD_TEST( ${EXEFILE} 2 1 FALSE TRUE ${ARGN} )
CALL_ADD_TEST( ${EXEFILE} 4 1 FALSE TRUE ${ARGN} )
ADD_PROJ_PROVISIONAL_TEST( ${EXEFILE} )
CREATE_TEST_NAME( "${EXEFILE}_${PROCS}procs_${THREADS}threads" ${ARGN} )
MATH( EXPR TOT_PROCS "${PROCS} * ${THREADS}" )
IF ( ${TOT_PROCS} GREATER ${TEST_MAX_PROCS} )
MESSAGE("Disabling test ${TESTNAME} (exceeds maximum number of processors ${TEST_MAX_PROCS})")
ELSEIF ( ( ${PROCS} STREQUAL "1" ) AND NOT USE_MPI_FOR_SERIAL_TESTS )
ADD_TEST( NAME ${TESTNAME} COMMAND $<TARGET_FILE:${LAST_TEST}> ${ARGN} )
SET_TESTS_PROPERTIES ( ${TESTNAME} PROPERTIES FAIL_REGULAR_EXPRESSION "${TEST_FAIL_REGULAR_EXPRESSION}" PROCESSORS ${TOT_PROCS} )
ADD_RESOURCE_LOCK( ${TESTNAME} ${EXEFILE} ${ARGN} )
ELSEIF ( USE_MPI OR USE_EXT_MPI )
ADD_TEST( NAME ${TESTNAME} COMMAND ${MPIEXEC} "${MPIEXEC_NUMPROC_FLAG}" ${PROCS} $<TARGET_FILE:${LAST_TEST}> ${ARGN} )
SET_PROPERTY( TEST ${TESTNAME} APPEND PROPERTY ENVIRONMENT OMPI_MCA_hwloc_base_binding_policy=none )
SET_TESTS_PROPERTIES ( ${TESTNAME} PROPERTIES FAIL_REGULAR_EXPRESSION "${TEST_FAIL_REGULAR_EXPRESSION}" PROCESSORS ${TOT_PROCS} )
ADD_RESOURCE_LOCK( ${TESTNAME} ${EXEFILE} ${ARGN} )
ENDIF()
ENDMACRO()
@@ -1077,7 +966,7 @@ FUNCTION( ADD_${PROJ}_EXAMPLE EXEFILE PROCS ${ARGN} )
ADD_TEST( NAME ${TESTNAME} COMMAND $<TARGET_FILE:${LAST_TEST}> ${ARGN} )
ELSEIF ( USE_EXT_MPI AND NOT (${PROCS} GREATER ${TEST_MAX_PROCS}) )
CREATE_TEST_NAME( "example--${EXEFILE}_${PROCS}procs" ${ARGN} )
ADD_TEST( NAME ${TESTNAME} COMMAND ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${PROCS} $<TARGET_FILE:${LAST_TEST}> ${ARGN} )
ADD_TEST( NAME ${TESTNAME} COMMAND ${MPIEXEC} "${MPIEXEC_NUMPROC_FLAG}" ${PROCS} $<TARGET_FILE:${LAST_TEST}> ${ARGN} )
SET_PROPERTY( TEST ${TESTNAME} APPEND PROPERTY ENVIRONMENT OMPI_MCA_hwloc_base_binding_policy=none )
ENDIF()
SET_TESTS_PROPERTIES( ${TESTNAME} PROPERTIES FAIL_REGULAR_EXPRESSION "${TEST_FAIL_REGULAR_EXPRESSION}" PROCESSORS ${PROCS} )
@@ -1149,8 +1038,6 @@ FUNCTION( ADD_MATLAB_MEX SOURCE )
MATLAB_ADD_MEX(
NAME ${TARGET}
SRC ${SOURCE}
MODULE
R2017b
)
TARGET_LINK_LIBRARIES( ${TARGET} ${MATLAB_TARGET} )
ADD_PROJ_EXE_DEP( ${TARGET} )
@@ -1187,11 +1074,9 @@ ENDMACRO()
# Create a script to start matlab preloading libraries
FUNCTION( CREATE_MATLAB_WRAPPER )
SET( MATLABPATH ${MATLABPATH} "${${PROJ}_INSTALL_DIR}/mex" )
SET( tmp_libs ${MEX_LIBCXX} ${MEX_FILES} )
LIST( REMOVE_DUPLICATES MATLABPATH )
STRING( REGEX REPLACE ";" ":" tmp_libs "${tmp_libs}" )
STRING( REGEX REPLACE ";" ":" tmp_path "${MATLABPATH}" )
STRING(REGEX REPLACE ";" ":" tmp_libs "${tmp_libs}")
STRING(REGEX REPLACE ";" ":" tmp_path "${MATLABPATH}")
IF ( USING_MSVC )
# Create a matlab wrapper for windows
SET( MATLAB_GUI "${CMAKE_CURRENT_BINARY_DIR}/tmp/matlab-gui.bat" )
@@ -1300,7 +1185,7 @@ MACRO( ADD_DISTCLEAN ${ARGN} )
compile_commands.json
${ARGN}
)
ADD_CUSTOM_TARGET(distclean @echo cleaning for source distribution)
ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution)
IF (UNIX)
ADD_CUSTOM_COMMAND(
DEPENDS clean
@@ -1384,4 +1269,3 @@ FUNCTION( FIND_PYTHON_MODULE MODULE)
ENDIF()
SET( PY_${MODULE2}_FOUND ${PY_${MODULE2}_FOUND} PARENT_SCOPE )
ENDFUNCTION(FIND_PYTHON_MODULE)

View File

@@ -1,74 +1,117 @@
// 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<long 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>;
/********************************************************
* Explicit instantiations of Array<bool> *
********************************************************/
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& );
// 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
/********************************************************
* Explicit instantiations of Array<std::complex> *
********************************************************/
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;
// 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
/********************************************************
* Explicit instantiations of Array<std::string> *
********************************************************/
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
// 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

View File

@@ -1,6 +1,5 @@
/*
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
@@ -24,7 +23,6 @@
#include <initializer_list>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
@@ -91,7 +89,13 @@ public: // Constructors / assignment operators
* @param N Number of elements in each dimension
* @param data Optional raw array to copy the src data
*/
explicit Array( const std::vector<size_t> &N, const TYPE *data = nullptr );
explicit Array( const std::vector<size_t> &N, const TYPE *data = NULL );
/*!
* Create a 1D Array with the range
* @param range Range of the data
*/
explicit Array( const Range<TYPE> &range );
/*!
* Create a 1D Array using a string that mimic's MATLAB
@@ -105,12 +109,6 @@ public: // Constructors / assignment operators
*/
Array( std::initializer_list<TYPE> data );
/*!
* Create a 2D Array with the given initializer lists
* @param data Input data
*/
Array( std::initializer_list<std::initializer_list<TYPE>> data );
/*!
* Copy constructor
@@ -161,7 +159,7 @@ public: // Views/copies/subset
* @param N Number of elements in each dimension
* @param data Pointer to the data
*/
static std::unique_ptr<Array> view( const ArraySize &N, std::shared_ptr<TYPE> data );
static std::unique_ptr<Array> view( const ArraySize &N, std::shared_ptr<TYPE> &data );
/*!
@@ -169,8 +167,8 @@ public: // Views/copies/subset
* @param N Number of elements in each dimension
* @param data Pointer to the data
*/
static std::unique_ptr<const Array> constView( const ArraySize &N,
std::shared_ptr<const TYPE> const &data );
static std::unique_ptr<const Array> constView(
const ArraySize &N, std::shared_ptr<const TYPE> const &data );
/*!
@@ -184,7 +182,7 @@ public: // Views/copies/subset
* @param N Number of elements in each dimension
* @param data Pointer to the data
*/
void view2( const ArraySize &N, std::shared_ptr<TYPE> data );
void view2( const ArraySize &N, std::shared_ptr<TYPE> const &data );
/*!
* Make this object a view of the raw data (expert use only).
@@ -219,30 +217,14 @@ public: // Views/copies/subset
*/
void viewRaw( const ArraySize &N, TYPE *data, bool isCopyable = true, bool isFixedSize = true );
/*!
* Create an array view of the given data (expert use only).
* Use view2( N, shared_ptr(data,[](TYPE*){}) ) instead.
* Note: this interface is not recommended as it does not protect from
* the src data being deleted while still being used by the Array.
* Additionally for maximum performance it does not set the internal shared_ptr
* so functions like getPtr and resize will not work correctly.
* @param N Number of elements in each dimension
* @param data Pointer to the data
*/
static inline Array staticView( const ArraySize &N, TYPE *data )
{
Array x;
x.viewRaw( N, data, true, true );
return x;
}
/*!
* Convert an array of one type to another. This may or may not allocate new memory.
* @param array Input array
*/
template<class TYPE2>
static inline std::unique_ptr<Array<TYPE2, FUN, Allocator>>
convert( std::shared_ptr<Array<TYPE, FUN, Allocator>> array )
static inline std::unique_ptr<Array<TYPE2, FUN, Allocator>> convert(
std::shared_ptr<Array<TYPE, FUN, Allocator>> array )
{
auto array2 = std::make_unique<Array<TYPE2>>( array->size() );
array2.copy( *array );
@@ -255,8 +237,8 @@ public: // Views/copies/subset
* @param array Input array
*/
template<class TYPE2>
static inline std::unique_ptr<const Array<TYPE2, FUN, Allocator>>
convert( std::shared_ptr<const Array<TYPE, FUN, Allocator>> array )
static inline std::unique_ptr<const Array<TYPE2, FUN, Allocator>> convert(
std::shared_ptr<const Array<TYPE, FUN, Allocator>> array )
{
auto array2 = std::make_unique<Array<TYPE2>>( array->size() );
array2.copy( *array );
@@ -268,8 +250,8 @@ public: // Views/copies/subset
* Copy and convert data from another array to this array
* @param array Source array
*/
template<class TYPE2, class FUN2, class Allocator2>
void inline copy( const Array<TYPE2, FUN2, Allocator2> &array )
template<class TYPE2>
void inline copy( const Array<TYPE2, FUN, Allocator> &array )
{
resize( array.size() );
copy( array.data() );
@@ -278,55 +260,51 @@ public: // Views/copies/subset
/*!
* Copy and convert data from a raw vector to this array.
* Note: The current array must be allocated to the proper size first.
* @param data Source data
* @param array Source array
*/
template<class TYPE2>
inline void copy( const TYPE2 *data );
void inline copy( const TYPE2 *data )
{
for ( size_t i = 0; i < d_size.length(); i++ )
d_data[i] = static_cast<TYPE>( data[i] );
}
/*!
* Copy and convert data from this array to a raw vector.
* @param data Source data
* @param array Source array
*/
template<class TYPE2>
inline void copyTo( TYPE2 *data ) const;
void inline copyTo( TYPE2 *data ) const
{
for ( size_t i = 0; i < d_size.length(); i++ )
data[i] = static_cast<TYPE2>( d_data[i] );
}
/*!
* Copy and convert data from this array to a new array
*/
template<class TYPE2>
Array<TYPE2, FUN, std::allocator<TYPE2>> inline cloneTo() const
Array<TYPE2, FUN, Allocator> inline cloneTo() const
{
Array<TYPE2, FUN, std::allocator<TYPE2>> dst( this->size() );
Array<TYPE2, FUN> dst( this->size() );
copyTo( dst.data() );
return dst;
}
/*! swap the raw data pointers for the Arrays after checking for compatibility */
void swap( Array &other );
/*!
* Fill the array with the given value
* @param y Value to fill
* @param value Value to fill
*/
inline void fill( const TYPE &y )
{
for ( auto &x : *this )
x = y;
}
void fill( const TYPE &value );
/*!
* Scale the array by the given value
* @param y Value to scale by
* @param scale Value to scale by
*/
template<class TYPE2>
inline void scale( const TYPE2 &y )
{
for ( auto &x : *this )
x *= y;
}
void scale( const TYPE &scale );
/*!
* Set the values of this array to pow(base, exp)
@@ -335,7 +313,6 @@ public: // Views/copies/subset
*/
void pow( const Array &base, const TYPE &exp );
//! Destructor
~Array();
@@ -364,10 +341,6 @@ public: // Views/copies/subset
inline bool empty() const { return d_size.length() == 0; }
//! Return true if the Array is not empty
inline operator bool() const { return d_size.length() != 0; }
/*!
* Resize the Array
* @param N NUmber of elements
@@ -413,12 +386,6 @@ public: // Views/copies/subset
void reshape( const ArraySize &N );
/*!
* Remove singleton dimensions.
*/
void squeeze();
/*!
* Reshape the Array so that the number of dimensions is the
* max of ndim and the largest dim>1.
@@ -547,8 +514,8 @@ public: // Accessors
* @param i3 The third index
* @param i4 The fourth index
*/
ARRAY_ATTRIBUTE inline const TYPE &
operator()( size_t i1, size_t i2, size_t i3, size_t i4 ) const
ARRAY_ATTRIBUTE inline const TYPE &operator()(
size_t i1, size_t i2, size_t i3, size_t i4 ) const
{
return d_data[d_size.index( i1, i2, i3, i4 )];
}
@@ -574,8 +541,8 @@ public: // Accessors
* @param i4 The fourth index
* @param i5 The fifth index
*/
ARRAY_ATTRIBUTE inline const TYPE &
operator()( size_t i1, size_t i2, size_t i3, size_t i4, size_t i5 ) const
ARRAY_ATTRIBUTE inline const TYPE &operator()(
size_t i1, size_t i2, size_t i3, size_t i4, size_t i5 ) const
{
return d_data[d_size.index( i1, i2, i3, i4, i5 )];
}
@@ -648,17 +615,11 @@ public: // Math operations
//! Concatenates the arrays along the dimension dim.
static Array cat( const std::vector<Array> &x, int dim = 0 );
//! Concatenates the arrays along the dimension dim.
static Array cat( const std::initializer_list<Array> &x, int dim = 0 );
//! Concatenates the arrays along the dimension dim.
static Array cat( size_t N_array, const Array *x, int dim );
//! Concatenates a given array with the current array
void cat( const Array &x, int dim = 0 );
//! Initialize the array with random values (defined from the function table)
//void rand();
void rand();
//! Return true if NaNs are present
bool NaNs() const;
@@ -709,37 +670,20 @@ public: // Math operations
TYPE mean( const std::vector<Range<size_t>> &index ) const;
//! Find all elements that match the operator
std::vector<size_t> find( const TYPE &value,
std::function<bool( const TYPE &, const TYPE & )> compare ) const;
std::vector<size_t> find(
const TYPE &value, std::function<bool( const TYPE &, const TYPE & )> compare ) const;
//! Print an array
void
print( std::ostream &os, const std::string &name = "A", const std::string &prefix = "" ) const;
void print(
std::ostream &os, const std::string &name = "A", const std::string &prefix = "" ) const;
//! Multiply two arrays
static Array multiply( const Array &a, const Array &b );
//! Transpose an array
Array reverseDim() const;
/*!
* @brief Shift dimensions
* @details Shifts the dimensions of the array by N. When N is positive,
* shiftDim shifts the dimensions to the left and wraps the
* N leading dimensions to the end. When N is negative,
* shiftDim shifts the dimensions to the right and pads with singletons.
* @param N Desired shift
*/
Array shiftDim( int N ) const;
/*!
* @brief Permute array dimensions
* @details Rearranges the dimensions of the array so that they
* are in the order specified by the vector index.
* The array produced has the same values as A but the order of the subscripts
* needed to access any particular element are rearranged as specified.
* @param index Desired order of the subscripts
*/
Array permute( const std::vector<uint8_t> &index ) const;
//! Replicate an array a given number of times in each direction
Array repmat( const std::vector<size_t> &N ) const;
@@ -747,8 +691,8 @@ public: // Math operations
Array coarsen( const Array &filter ) const;
//! Coarsen an array using the given filter
Array coarsen( const std::vector<size_t> &ratio,
std::function<TYPE( const Array & )> filter ) const;
Array coarsen(
const std::vector<size_t> &ratio, std::function<TYPE( const Array & )> filter ) const;
/*!
* Perform a element-wise operation y = f(x)
@@ -763,9 +707,8 @@ public: // Math operations
* @param[in] x The first array
* @param[in] y The second array
*/
static Array transform( std::function<TYPE( const TYPE &, const TYPE & )> fun,
const Array &x,
const Array &y );
static Array transform(
std::function<TYPE( const TYPE &, const TYPE & )> fun, const Array &x, const Array &y );
/*!
* axpby operation: this = alpha*x + beta*this
@@ -779,13 +722,7 @@ public: // Math operations
* Linear interpolation
* @param[in] x Position as a decimal index
*/
inline TYPE interp( const std::vector<double> &x ) const { return interp( x.data() ); }
/*!
* Linear interpolation
* @param[in] x Position as a decimal index
*/
TYPE interp( const double *x ) const;
TYPE interp( const std::vector<double> &x ) const;
/**
* \fn equals (Array & const rhs, TYPE tol )
@@ -808,10 +745,8 @@ private:
inline void checkSubsetIndex( const std::vector<Range<size_t>> &range ) const;
inline std::vector<Range<size_t>> convert( const std::vector<size_t> &index ) const;
static inline void getSubsetArrays( const std::vector<Range<size_t>> &range,
std::array<size_t, 5> &first,
std::array<size_t, 5> &last,
std::array<size_t, 5> &inc,
std::array<size_t, 5> &N );
std::array<size_t, 5> &first, std::array<size_t, 5> &last, std::array<size_t, 5> &inc,
std::array<size_t, 5> &N );
};
@@ -836,8 +771,8 @@ inline Array<TYPE, FUN, Allocator> operator+(
const Array<TYPE, FUN, Allocator> &a, const Array<TYPE, FUN, Allocator> &b )
{
Array<TYPE, FUN, Allocator> c;
const auto &op = []( const TYPE &a, const TYPE &b ) { return a + b; };
FUN::transform( op, a, b, c );
const auto &fun = []( const TYPE &a, const TYPE &b ) { return a + b; };
FUN::transform( fun, a, b, c );
return c;
}
template<class TYPE, class FUN, class Allocator>
@@ -845,78 +780,30 @@ inline Array<TYPE, FUN, Allocator> operator-(
const Array<TYPE, FUN, Allocator> &a, const Array<TYPE, FUN, Allocator> &b )
{
Array<TYPE, FUN, Allocator> c;
const auto &op = []( const TYPE &a, const TYPE &b ) { return a - b; };
FUN::transform( op, a, b, c );
const auto &fun = []( const TYPE &a, const TYPE &b ) { return a - b; };
FUN::transform( fun, a, b, c );
return c;
}
template<class TYPE, class FUN, class Allocator>
inline Array<TYPE, FUN, Allocator> operator*(
const Array<TYPE, FUN, Allocator> &a, const Array<TYPE, FUN, Allocator> &b )
{
Array<TYPE, FUN, Allocator> c;
FUN::multiply( a, b, c );
return c;
return Array<TYPE, FUN, Allocator>::multiply( a, b );
}
template<class TYPE, class FUN, class Allocator>
inline Array<TYPE, FUN, Allocator> operator*(
const Array<TYPE, FUN, Allocator> &a, const std::vector<TYPE> &b )
{
Array<TYPE, FUN, Allocator> b2, c;
Array<TYPE, FUN, Allocator> b2;
b2.viewRaw( { b.size() }, const_cast<TYPE *>( b.data() ) );
FUN::multiply( a, b2, c );
return c;
}
template<class TYPE, class FUN, class Allocator>
inline Array<TYPE, FUN, Allocator> operator*( const TYPE &a,
const Array<TYPE, FUN, Allocator> &b )
{
auto c = b;
c.scale( a );
return c;
}
template<class TYPE, class FUN, class Allocator>
inline Array<TYPE, FUN, Allocator> operator*( const Array<TYPE, FUN, Allocator> &a,
const TYPE &b )
{
auto c = a;
c.scale( b );
return c;
}
/********************************************************
* Copy array *
********************************************************/
template<class TYPE, class FUN, class Allocator>
template<class TYPE2>
inline void Array<TYPE, FUN, Allocator>::copy( const TYPE2 *data )
{
if ( std::is_same<TYPE, TYPE2>::value ) {
std::copy( data, data + d_size.length(), d_data );
} else {
for ( size_t i = 0; i < d_size.length(); i++ )
d_data[i] = static_cast<TYPE>( data[i] );
}
}
template<class TYPE, class FUN, class Allocator>
template<class TYPE2>
inline void Array<TYPE, FUN, Allocator>::copyTo( TYPE2 *data ) const
{
if ( std::is_same<TYPE, TYPE2>::value ) {
std::copy( d_data, d_data + d_size.length(), data );
} else {
for ( size_t i = 0; i < d_size.length(); i++ )
data[i] = static_cast<TYPE2>( d_data[i] );
}
return Array<TYPE, FUN, Allocator>::multiply( a, b2 );
}
/********************************************************
* Convience typedefs *
* Copy array *
********************************************************/
typedef Array<double> DoubleArray;
typedef Array<int> IntArray;
#endif

View File

@@ -1,6 +1,5 @@
/*
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
@@ -16,7 +15,6 @@
*/
/*
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
@@ -49,46 +47,65 @@
/********************************************************
* External instantiations *
********************************************************/
extern template class Array<char>;
extern template class Array<uint8_t>;
extern template class Array<uint16_t>;
extern template class Array<uint32_t>;
extern template class Array<uint64_t>;
extern template class Array<int8_t>;
extern template class Array<int16_t>;
extern template class Array<int32_t>;
extern template class Array<int64_t>;
extern template class Array<double>;
extern template class Array<float>;
extern template class Array<char, FunctionTable>;
extern template class Array<uint8_t, FunctionTable>;
extern template class Array<uint16_t, FunctionTable>;
extern template class Array<uint32_t, FunctionTable>;
extern template class Array<uint64_t, FunctionTable>;
extern template class Array<int8_t, FunctionTable>;
extern template class Array<int16_t, FunctionTable>;
extern template class Array<int32_t, FunctionTable>;
extern template class Array<int64_t, FunctionTable>;
extern template class Array<double, FunctionTable>;
extern template class Array<float, FunctionTable>;
/********************************************************
* Macros to help instantiate functions *
* Helper functions *
********************************************************/
// clang-format off
#define instantiateArrayConstructors( TYPE ) \
template Array<TYPE>::Array(); \
template Array<TYPE>::~Array(); \
template Array<TYPE>::Array( const ArraySize & ); \
template Array<TYPE>::Array( size_t ); \
template Array<TYPE>::Array( size_t, size_t ); \
template Array<TYPE>::Array( size_t, size_t, size_t ); \
template Array<TYPE>::Array( size_t, size_t, size_t, size_t ); \
template Array<TYPE>::Array( size_t, size_t, size_t, size_t, size_t ); \
template Array<TYPE>::Array( const std::vector<size_t> &, const TYPE * ); \
template Array<TYPE>::Array( std::initializer_list<TYPE> ); \
template Array<TYPE>::Array( std::initializer_list<std::initializer_list<TYPE>> ); \
template Array<TYPE>::Array( const Array<TYPE> & ); \
template Array<TYPE>::Array( Array<TYPE> && ); \
template void Array<TYPE>::reshape( ArraySize const& ); \
template void Array<TYPE>::squeeze(); \
template std::unique_ptr<const Array<TYPE>> \
Array<TYPE>::constView(ArraySize const&, std::shared_ptr<TYPE const> const&); \
template void Array<TYPE>::viewRaw( ArraySize const&, TYPE*, bool, bool ); \
template void Array<TYPE>::view2(ArraySize const&, std::shared_ptr<TYPE> ); \
template Array<TYPE> &Array<TYPE>::operator=( const Array<TYPE> & ); \
template Array<TYPE> &Array<TYPE>::operator=( Array<TYPE> && );
// clang-format on
template<class TYPE>
inline typename std::enable_if<std::is_integral<TYPE>::value, size_t>::type getRangeSize(
const Range<TYPE> &range )
{
return ( static_cast<int64_t>( range.j ) - static_cast<int64_t>( range.i ) ) /
static_cast<int64_t>( range.k );
}
template<class TYPE>
inline typename std::enable_if<std::is_floating_point<TYPE>::value, size_t>::type getRangeSize(
const Range<TYPE> &range )
{
double tmp = static_cast<double>( ( range.j - range.i ) ) / static_cast<double>( range.k );
return static_cast<size_t>( floor( tmp + 1e-12 ) + 1 );
}
template<class TYPE>
inline typename std::enable_if<std::is_same<TYPE, std::complex<float>>::value ||
std::is_same<TYPE, std::complex<double>>::value,
size_t>::type
getRangeSize( const Range<TYPE> &range )
{
double tmp = std::real( ( range.j - range.i ) / ( range.k ) );
return static_cast<size_t>( floor( tmp + 1e-12 ) + 1 );
}
template<class TYPE>
inline typename std::enable_if<std::is_integral<TYPE>::value, TYPE>::type getRangeValue(
const Range<TYPE> &range, size_t index )
{
return range.i + index * range.k;
}
template<class TYPE>
inline typename std::enable_if<std::is_floating_point<TYPE>::value, TYPE>::type getRangeValue(
const Range<TYPE> &range, size_t index )
{
return range.k * ( range.i / range.k + index );
}
template<class TYPE>
inline typename std::enable_if<std::is_same<TYPE, std::complex<float>>::value ||
std::is_same<TYPE, std::complex<double>>::value,
TYPE>::type
getRangeValue( const Range<TYPE> &range, size_t index )
{
return range.k * ( range.i / range.k + static_cast<TYPE>( index ) );
}
/********************************************************
@@ -139,8 +156,19 @@ Array<TYPE, FUN, Allocator>::Array( const std::vector<size_t> &N, const TYPE *da
: d_isCopyable( true ), d_isFixedSize( false )
{
allocate( N );
if ( data )
copy( data );
if ( data ) {
for ( size_t i = 0; i < d_size.length(); i++ )
d_data[i] = data[i];
}
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator>::Array( const Range<TYPE> &range )
: d_isCopyable( true ), d_isFixedSize( false )
{
size_t N = getRangeSize( range );
allocate( { N } );
for ( size_t i = 0; i < N; i++ )
d_data[i] = getRangeValue( range, i );
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator>::Array( std::string str ) : d_isCopyable( true ), d_isFixedSize( false )
@@ -218,12 +246,8 @@ Array<TYPE, FUN, Allocator>::Array( std::string str ) : d_isCopyable( true ), d_
i2 = str.length();
}
allocate( data.size() );
if ( std::is_same<TYPE, bool>::value ) {
for ( size_t i = 0; i < data.size(); i++ )
d_data[i] = data[i];
} else {
copy( data.data() );
}
for ( size_t i = 0; i < data.size(); i++ )
d_data[i] = data[i];
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator>::Array( std::initializer_list<TYPE> x )
@@ -235,38 +259,19 @@ Array<TYPE, FUN, Allocator>::Array( std::initializer_list<TYPE> x )
d_data[i] = *it;
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator>::Array( std::initializer_list<std::initializer_list<TYPE>> x )
: d_isCopyable( true ), d_isFixedSize( false )
{
size_t Nx = x.size();
size_t Ny = 0;
for ( const auto y : x )
Ny = std::max<size_t>( Ny, y.size() );
allocate( { Nx, Ny } );
auto itx = x.begin();
for ( size_t i = 0; i < x.size(); ++i, ++itx ) {
auto ity = itx->begin();
for ( size_t j = 0; j < itx->size(); ++j, ++ity ) {
d_data[i + j * Nx] = *ity;
}
}
}
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::allocate( const ArraySize &N )
{
if ( d_isFixedSize )
throw std::logic_error( "Array cannot be resized" );
d_size = N;
auto length = d_size.length();
d_data = nullptr;
if ( length > 0 ) {
try {
d_data = new TYPE[length];
} catch ( ... ) {
throw std::logic_error( "Failed to allocate array" );
}
}
d_ptr.reset( d_data, []( TYPE *p ) { delete[] p; } );
if ( length == 0 )
d_ptr.reset();
else
d_ptr.reset( new ( std::nothrow ) TYPE[length], []( TYPE *p ) { delete[] p; } );
d_data = d_ptr.get();
if ( length > 0 && d_data == nullptr )
throw std::logic_error( "Failed to allocate array" );
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator>::Array( const Array &rhs )
@@ -275,19 +280,18 @@ Array<TYPE, FUN, Allocator>::Array( const Array &rhs )
if ( !rhs.d_isCopyable )
throw std::logic_error( "Array cannot be copied" );
allocate( rhs.size() );
copy( rhs.d_data );
for ( size_t i = 0; i < d_size.length(); i++ )
d_data[i] = rhs.d_data[i];
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator>::Array( Array &&rhs )
: d_isCopyable( rhs.d_isCopyable ),
d_isFixedSize( rhs.d_isFixedSize ),
d_size( rhs.d_size ),
d_data( rhs.d_data ),
d_ptr( std::move( rhs.d_ptr ) )
d_data( rhs.d_data )
{
rhs.d_size = ArraySize();
rhs.d_data = nullptr;
rhs.d_ptr = nullptr;
d_ptr = std::move( rhs.d_ptr );
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator> &Array<TYPE, FUN, Allocator>::operator=( const Array &rhs )
@@ -296,8 +300,9 @@ Array<TYPE, FUN, Allocator> &Array<TYPE, FUN, Allocator>::operator=( const Array
return *this;
if ( !rhs.d_isCopyable )
throw std::logic_error( "Array cannot be copied" );
allocate( rhs.size() );
copy( rhs.d_data );
this->allocate( rhs.size() );
for ( size_t i = 0; i < d_size.length(); i++ )
this->d_data[i] = rhs.d_data[i];
return *this;
}
template<class TYPE, class FUN, class Allocator>
@@ -310,17 +315,15 @@ Array<TYPE, FUN, Allocator> &Array<TYPE, FUN, Allocator>::operator=( Array &&rhs
d_size = rhs.d_size;
d_data = rhs.d_data;
d_ptr = std::move( rhs.d_ptr );
rhs.d_size = ArraySize();
rhs.d_data = nullptr;
rhs.d_ptr = nullptr;
return *this;
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator> &Array<TYPE, FUN, Allocator>::operator=( const std::vector<TYPE> &rhs )
{
allocate( ArraySize( rhs.size() ) );
this->allocate( ArraySize( rhs.size() ) );
for ( size_t i = 0; i < rhs.size(); i++ )
d_data[i] = rhs[i];
this->d_data[i] = rhs[i];
return *this;
}
template<class TYPE, class FUN, class Allocator>
@@ -358,9 +361,9 @@ static inline void moveValues( const ArraySize &N1, const ArraySize &N2, TYPE *d
}
}
}
template<class TYPE>
static inline void
copyValues( const ArraySize &N1, const ArraySize &N2, const TYPE *data1, TYPE *data2 )
template<bool test, class TYPE>
static inline typename std::enable_if<test, void>::type copyValues(
const ArraySize &N1, const ArraySize &N2, const TYPE *data1, TYPE *data2 )
{
for ( size_t i5 = 0; i5 < std::min( N1[4], N2[4] ); i5++ ) {
for ( size_t i4 = 0; i4 < std::min( N1[3], N2[3] ); i4++ ) {
@@ -376,6 +379,12 @@ copyValues( const ArraySize &N1, const ArraySize &N2, const TYPE *data1, TYPE *d
}
}
}
template<bool test, class TYPE>
static inline typename std::enable_if<!test, void>::type copyValues(
const ArraySize &, const ArraySize &, const TYPE *, TYPE * )
{
throw std::logic_error( "No copy constructor" );
}
/********************************************************
@@ -402,11 +411,9 @@ void Array<TYPE, FUN, Allocator>::resize( const ArraySize &N )
if ( data0.use_count() <= 1 ) {
// We own the data, use std:move
moveValues( N0, N, data0.get(), d_data );
} else if ( std::is_copy_constructible<TYPE>::value ) {
// We do not own the data, copy
copyValues( N0, N, data0.get(), d_data );
} else {
throw std::logic_error( "No copy constructor" );
// We do not own the data, copy
copyValues<std::is_copy_constructible<TYPE>::value, TYPE>( N0, N, data0.get(), d_data );
}
}
}
@@ -435,7 +442,7 @@ void Array<TYPE, FUN, Allocator>::resizeDim( int dim, size_t N, const TYPE &valu
/********************************************************
* Reshape/squeeze the array *
* Reshape the array *
********************************************************/
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::reshape( const ArraySize &N )
@@ -444,85 +451,6 @@ void Array<TYPE, FUN, Allocator>::reshape( const ArraySize &N )
throw std::logic_error( "reshape is not allowed to change the array size" );
d_size = N;
}
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::squeeze()
{
d_size.squeeze();
}
/********************************************************
* Shift/permute the array *
********************************************************/
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::shiftDim( int N ) const
{
if ( N > 0 )
N = N % d_size.ndim();
if ( N == 0 ) {
// No shift required
return *this;
} else if ( N > 0 ) {
// Shift to the left and wrap
std::vector<uint8_t> index( d_size.ndim() );
size_t i = 0;
for ( size_t j=N; j<index.size(); j++, i++)
index[i] = j;
for ( size_t j=0; i<index.size(); j++, i++)
index[i] = j;
return permute( index );
} else {
// Shift to the right (padding with singletons)
N = -N;
ASSERT( d_size.ndim() + N < (int) ArraySize::maxDim() );
size_t dims[10] = { 1 };
for ( int i = 0; i < ndim(); i++ )
dims[N+i] = d_size[i];
auto y = *this;
y.reshape( ArraySize( ndim() + N, dims ) );
return y;
}
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::permute( const std::vector<uint8_t> &index ) const
{
// Check the permutation
ASSERT( (int) index.size() == ndim() );
for ( int i=0; i < ndim(); i++) {
ASSERT( index[i] < ndim() );
for ( int j=0; j < i; j++)
ASSERT( index[i] != index[j] );
}
// Create the new Array
size_t dims[5] = { 1u, 1u, 1u, 1u, 1u };
for ( size_t i=0; i<index.size(); i++)
dims[i] = d_size[index[i]];
Array y( ArraySize( ndim(), dims ) );
y.fill( -1 );
ASSERT( y.length() == this->length() );
// Fill the data
size_t N[5] = { 1u, 1u, 1u, 1u, 1u };
for ( int i=0; i < ndim(); i++) {
std::array<size_t, 5> ijk = { 0, 0, 0, 0, 0 };
ijk[index[i]] = 1;
N[i] = d_size.index( ijk );
}
size_t tmp = ( dims[0] - 1 ) * N[0] + ( dims[1] - 1 ) * N[1] + ( dims[2] - 1 ) * N[2] + ( dims[3] - 1 ) * N[3] + ( dims[4] - 1 ) * N[4] + 1;
ASSERT( tmp == length() );
for ( size_t i4 = 0; i4 < dims[4]; i4++ ) {
for ( size_t i3 = 0; i3 < dims[3]; i3++ ) {
for ( size_t i2 = 0; i2 < dims[2]; i2++ ) {
for ( size_t i1 = 0; i1 < dims[1]; i1++ ) {
for ( size_t i0 = 0; i0 < dims[0]; i0++ ) {
size_t index2 = i0 * N[0] + i1 * N[1] + i2 * N[2] + i3 * N[3] + i4 * N[4];
y( i0, i1, i2, i3, i4 ) = d_data[index2];
}
}
}
}
}
return y;
}
/********************************************************
@@ -530,8 +458,8 @@ Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::permute( const std::vec
********************************************************/
// Helper function to check subset indices
template<class TYPE, class FUN, class Allocator>
inline void
Array<TYPE, FUN, Allocator>::checkSubsetIndex( const std::vector<Range<size_t>> &range ) const
inline void Array<TYPE, FUN, Allocator>::checkSubsetIndex(
const std::vector<Range<size_t>> &range ) const
{
bool test = (int) range.size() == d_size.ndim();
for ( size_t d = 0; d < range.size(); d++ )
@@ -540,8 +468,8 @@ Array<TYPE, FUN, Allocator>::checkSubsetIndex( const std::vector<Range<size_t>>
throw std::logic_error( "indices for subset are invalid" );
}
template<class TYPE, class FUN, class Allocator>
std::vector<Range<size_t>>
Array<TYPE, FUN, Allocator>::convert( const std::vector<size_t> &index ) const
std::vector<Range<size_t>> Array<TYPE, FUN, Allocator>::convert(
const std::vector<size_t> &index ) const
{
std::vector<Range<size_t>> range( d_size.ndim() );
if ( index.size() % 2 != 0 || static_cast<int>( index.size() / 2 ) < d_size.ndim() )
@@ -553,10 +481,8 @@ Array<TYPE, FUN, Allocator>::convert( const std::vector<size_t> &index ) const
// Helper function to return dimensions for the subset array
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::getSubsetArrays( const std::vector<Range<size_t>> &index,
std::array<size_t, 5> &first,
std::array<size_t, 5> &last,
std::array<size_t, 5> &inc,
std::array<size_t, 5> &N )
std::array<size_t, 5> &first, std::array<size_t, 5> &last, std::array<size_t, 5> &inc,
std::array<size_t, 5> &N )
{
first.fill( 0 );
last.fill( 0 );
@@ -571,8 +497,8 @@ void Array<TYPE, FUN, Allocator>::getSubsetArrays( const std::vector<Range<size_
}
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator>
Array<TYPE, FUN, Allocator>::subset( const std::vector<Range<size_t>> &index ) const
Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::subset(
const std::vector<Range<size_t>> &index ) const
{
// Get the subset indicies
checkSubsetIndex( index );
@@ -580,8 +506,9 @@ Array<TYPE, FUN, Allocator>::subset( const std::vector<Range<size_t>> &index ) c
getSubsetArrays( index, first, last, inc, N1 );
ArraySize S1( d_size.ndim(), N1.data() );
// Create the new array
Array<TYPE, FUN, Allocator> subset_array( S1 );
Array<TYPE> subset_array( S1 );
// Fill the new array
static_assert( ArraySize::maxDim() == 5, "Not programmed for more than 5 dimensions" );
TYPE *subset_data = subset_array.data();
for ( size_t i4 = first[4], k1 = 0; i4 <= last[4]; i4 += inc[4] ) {
for ( size_t i3 = first[3]; i3 <= last[3]; i3 += inc[3] ) {
@@ -598,21 +525,22 @@ Array<TYPE, FUN, Allocator>::subset( const std::vector<Range<size_t>> &index ) c
return subset_array;
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator>
Array<TYPE, FUN, Allocator>::subset( const std::vector<size_t> &index ) const
Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::subset(
const std::vector<size_t> &index ) const
{
auto range = convert( index );
return subset( range );
}
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::copySubset( const std::vector<Range<size_t>> &index,
const Array<TYPE, FUN, Allocator> &subset )
void Array<TYPE, FUN, Allocator>::copySubset(
const std::vector<Range<size_t>> &index, const Array<TYPE, FUN, Allocator> &subset )
{
// Get the subset indices
checkSubsetIndex( index );
std::array<size_t, 5> first, last, inc, N1;
getSubsetArrays( index, first, last, inc, N1 );
// Copy the sub-array
static_assert( ArraySize::maxDim() == 5, "Not programmed for more than 5 dimensions" );
const TYPE *src_data = subset.data();
for ( size_t i4 = first[4], k1 = 0; i4 <= last[4]; i4 += inc[4] ) {
for ( size_t i3 = first[3]; i3 <= last[3]; i3 += inc[3] ) {
@@ -628,14 +556,15 @@ void Array<TYPE, FUN, Allocator>::copySubset( const std::vector<Range<size_t>> &
}
}
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::addSubset( const std::vector<Range<size_t>> &index,
const Array<TYPE, FUN, Allocator> &subset )
void Array<TYPE, FUN, Allocator>::addSubset(
const std::vector<Range<size_t>> &index, const Array<TYPE, FUN, Allocator> &subset )
{
// Get the subset indices
checkSubsetIndex( index );
std::array<size_t, 5> first, last, inc, N1;
getSubsetArrays( index, first, last, inc, N1 );
// add the sub-array
static_assert( ArraySize::maxDim() == 5, "Not programmed for more than 5 dimensions" );
for ( size_t i4 = first[4], k1 = 0; i4 <= last[4]; i4 += inc[4] ) {
for ( size_t i3 = first[3]; i3 <= last[3]; i3 += inc[3] ) {
for ( size_t i2 = first[2]; i2 <= last[2]; i2 += inc[2] ) {
@@ -650,16 +579,16 @@ void Array<TYPE, FUN, Allocator>::addSubset( const std::vector<Range<size_t>> &i
}
}
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::copySubset( const std::vector<size_t> &index,
const Array<TYPE, FUN, Allocator> &subset )
void Array<TYPE, FUN, Allocator>::copySubset(
const std::vector<size_t> &index, const Array<TYPE, FUN, Allocator> &subset )
{
auto range = convert( index );
copySubset( range, subset );
}
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::addSubset( const std::vector<size_t> &index,
const Array<TYPE, FUN, Allocator> &subset )
void Array<TYPE, FUN, Allocator>::addSubset(
const std::vector<size_t> &index, const Array<TYPE, FUN, Allocator> &subset )
{
auto range = convert( index );
addSubset( range, subset );
@@ -687,8 +616,8 @@ bool Array<TYPE, FUN, Allocator>::operator==( const Array &rhs ) const
* Get a view of an C array *
********************************************************/
template<class TYPE, class FUN, class Allocator>
std::unique_ptr<Array<TYPE, FUN, Allocator>>
Array<TYPE, FUN, Allocator>::view( const ArraySize &N, std::shared_ptr<TYPE> data )
std::unique_ptr<Array<TYPE, FUN, Allocator>> Array<TYPE, FUN, Allocator>::view(
const ArraySize &N, std::shared_ptr<TYPE> &data )
{
auto array = std::make_unique<Array<TYPE, FUN, Allocator>>();
array->d_size = N;
@@ -697,9 +626,8 @@ Array<TYPE, FUN, Allocator>::view( const ArraySize &N, std::shared_ptr<TYPE> dat
return array;
}
template<class TYPE, class FUN, class Allocator>
std::unique_ptr<const Array<TYPE, FUN, Allocator>>
Array<TYPE, FUN, Allocator>::constView( const ArraySize &N,
std::shared_ptr<const TYPE> const &data )
std::unique_ptr<const Array<TYPE, FUN, Allocator>> Array<TYPE, FUN, Allocator>::constView(
const ArraySize &N, std::shared_ptr<const TYPE> const &data )
{
auto array = std::make_unique<Array<TYPE, FUN, Allocator>>();
array->d_size = N;
@@ -714,17 +642,15 @@ void Array<TYPE, FUN, Allocator>::view2( Array<TYPE, FUN, Allocator> &src )
d_data = src.d_data;
}
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::view2( const ArraySize &N, std::shared_ptr<TYPE> data )
void Array<TYPE, FUN, Allocator>::view2( const ArraySize &N, std::shared_ptr<TYPE> const &data )
{
d_size = N;
d_ptr = data;
d_data = d_ptr.get();
}
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::viewRaw( const ArraySize &N,
TYPE *data,
bool isCopyable,
bool isFixedSize )
void Array<TYPE, FUN, Allocator>::viewRaw(
const ArraySize &N, TYPE *data, bool isCopyable, bool isFixedSize )
{
d_isCopyable = isCopyable;
d_isFixedSize = isFixedSize;
@@ -748,8 +674,20 @@ void Array<TYPE, FUN, Allocator>::swap( Array &other )
std::swap( d_ptr, other.d_ptr );
}
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::pow( const Array<TYPE, FUN, Allocator> &baseArray,
const TYPE &exp )
void Array<TYPE, FUN, Allocator>::fill( const TYPE &value )
{
for ( size_t i = 0; i < d_size.length(); i++ )
d_data[i] = value;
}
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::scale( const TYPE &value )
{
for ( size_t i = 0; i < d_size.length(); i++ )
d_data[i] *= value;
}
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::pow(
const Array<TYPE, FUN, Allocator> &baseArray, const TYPE &exp )
{
// not insisting on the shapes being the same
// but insisting on the total size being the same
@@ -766,8 +704,8 @@ void Array<TYPE, FUN, Allocator>::pow( const Array<TYPE, FUN, Allocator> &baseAr
* Replicate the array *
********************************************************/
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator>
Array<TYPE, FUN, Allocator>::repmat( const std::vector<size_t> &N_rep ) const
Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::repmat(
const std::vector<size_t> &N_rep ) const
{
std::vector<size_t> N2( d_size.begin(), d_size.end() );
if ( N2.size() < N_rep.size() )
@@ -781,6 +719,7 @@ Array<TYPE, FUN, Allocator>::repmat( const std::vector<size_t> &N_rep ) const
N2[d] *= N_rep[d];
}
Array<TYPE, FUN, Allocator> y( N2 );
static_assert( ArraySize::maxDim() <= 5, "Not programmed for dimensions > 5" );
TYPE *y2 = y.data();
for ( size_t i4 = 0, index = 0; i4 < N1[4]; i4++ ) {
for ( size_t j4 = 0; j4 < Nr[4]; j4++ ) {
@@ -822,7 +761,7 @@ bool Array<TYPE, FUN, Allocator>::NaNs() const
template<class TYPE, class FUN, class Allocator>
TYPE Array<TYPE, FUN, Allocator>::mean( void ) const
{
TYPE x = sum() / d_size.length();
TYPE x = this->sum() / d_size.length();
return x;
}
template<class TYPE, class FUN, class Allocator>
@@ -904,6 +843,7 @@ TYPE Array<TYPE, FUN, Allocator>::min( const std::vector<Range<size_t>> &range )
checkSubsetIndex( range );
std::array<size_t, 5> first, last, inc, N1;
getSubsetArrays( range, first, last, inc, N1 );
static_assert( ArraySize::maxDim() <= 5, "Function programmed for more than 5 dimensions" );
TYPE x = std::numeric_limits<TYPE>::max();
for ( size_t i4 = first[4]; i4 <= last[4]; i4 += inc[4] ) {
for ( size_t i3 = first[3]; i3 <= last[3]; i3 += inc[3] ) {
@@ -926,6 +866,7 @@ TYPE Array<TYPE, FUN, Allocator>::max( const std::vector<Range<size_t>> &range )
checkSubsetIndex( range );
std::array<size_t, 5> first, last, inc, N1;
getSubsetArrays( range, first, last, inc, N1 );
static_assert( ArraySize::maxDim() <= 5, "Function programmed for more than 5 dimensions" );
TYPE x = std::numeric_limits<TYPE>::min();
for ( size_t i4 = first[4]; i4 <= last[4]; i4 += inc[4] ) {
for ( size_t i3 = first[3]; i3 <= last[3]; i3 += inc[3] ) {
@@ -948,6 +889,7 @@ TYPE Array<TYPE, FUN, Allocator>::sum( const std::vector<Range<size_t>> &range )
checkSubsetIndex( range );
std::array<size_t, 5> first, last, inc, N1;
getSubsetArrays( range, first, last, inc, N1 );
static_assert( ArraySize::maxDim() <= 5, "Function programmed for more than 5 dimensions" );
TYPE x = 0;
for ( size_t i4 = first[4]; i4 <= last[4]; i4 += inc[4] ) {
for ( size_t i3 = first[3]; i3 <= last[3]; i3 += inc[3] ) {
@@ -970,6 +912,7 @@ TYPE Array<TYPE, FUN, Allocator>::mean( const std::vector<Range<size_t>> &range
checkSubsetIndex( range );
std::array<size_t, 5> first, last, inc, N1;
getSubsetArrays( range, first, last, inc, N1 );
static_assert( ArraySize::maxDim() <= 5, "Function programmed for more than 5 dimensions" );
size_t n = 1;
for ( auto &d : N1 )
n *= d;
@@ -1006,9 +949,8 @@ TYPE Array<TYPE, FUN, Allocator>::mean( const std::vector<size_t> &index ) const
* Find all elements that match the given operation *
********************************************************/
template<class TYPE, class FUN, class Allocator>
std::vector<size_t>
Array<TYPE, FUN, Allocator>::find( const TYPE &value,
std::function<bool( const TYPE &, const TYPE & )> compare ) const
std::vector<size_t> Array<TYPE, FUN, Allocator>::find(
const TYPE &value, std::function<bool( const TYPE &, const TYPE & )> compare ) const
{
std::vector<size_t> result;
result.reserve( d_size.length() );
@@ -1024,9 +966,8 @@ Array<TYPE, FUN, Allocator>::find( const TYPE &value,
* Print an array to an output stream *
********************************************************/
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::print( std::ostream &os,
const std::string &name,
const std::string &prefix ) const
void Array<TYPE, FUN, Allocator>::print(
std::ostream &os, const std::string &name, const std::string &prefix ) const
{
if ( d_size.ndim() == 1 ) {
for ( size_t i = 0; i < d_size[0]; i++ )
@@ -1050,11 +991,12 @@ void Array<TYPE, FUN, Allocator>::print( std::ostream &os,
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::reverseDim() const
{
size_t N2[5];
size_t N2[ArraySize::maxDim()];
for ( int d = 0; d < ArraySize::maxDim(); d++ )
N2[d] = d_size[ArraySize::maxDim() - d - 1];
ArraySize S2( ArraySize::maxDim(), N2 );
Array<TYPE, FUN, Allocator> y( S2 );
static_assert( ArraySize::maxDim() == 5, "Not programmed for dimensions other than 5" );
TYPE *y2 = y.data();
for ( size_t i0 = 0; i0 < d_size[0]; i0++ ) {
for ( size_t i1 = 0; i1 < d_size[1]; i1++ ) {
@@ -1079,8 +1021,8 @@ Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::reverseDim() const
* Coarsen the array *
********************************************************/
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator>
Array<TYPE, FUN, Allocator>::coarsen( const Array<TYPE, FUN, Allocator> &filter ) const
Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::coarsen(
const Array<TYPE, FUN, Allocator> &filter ) const
{
auto S2 = size();
for ( size_t i = 0; i < S2.size(); i++ ) {
@@ -1100,9 +1042,8 @@ Array<TYPE, FUN, Allocator>::coarsen( const Array<TYPE, FUN, Allocator> &filter
for ( size_t k2 = 0; k2 < Nh[2]; k2++ ) {
for ( size_t j2 = 0; j2 < Nh[1]; j2++ ) {
for ( size_t i2 = 0; i2 < Nh[0]; i2++ ) {
tmp += filter( i2, j2, k2 ) * operator()( i1 *Nh[0] + i2,
j1 * Nh[1] + j2,
k1 * Nh[2] + k2 );
tmp += filter( i2, j2, k2 ) * this->operator()( i1 *Nh[0] + i2,
j1 * Nh[1] + j2, k1 * Nh[2] + k2 );
}
}
}
@@ -1113,8 +1054,7 @@ Array<TYPE, FUN, Allocator>::coarsen( const Array<TYPE, FUN, Allocator> &filter
return y;
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::coarsen(
const std::vector<size_t> &ratio,
Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::coarsen( const std::vector<size_t> &ratio,
std::function<TYPE( const Array<TYPE, FUN, Allocator> & )> filter ) const
{
if ( ratio.size() != d_size.ndim() )
@@ -1135,7 +1075,7 @@ Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::coarsen(
for ( size_t k2 = 0; k2 < ratio[2]; k2++ ) {
for ( size_t j2 = 0; j2 < ratio[1]; j2++ ) {
for ( size_t i2 = 0; i2 < ratio[0]; i2++ ) {
tmp( i2, j2, k2 ) = operator()(
tmp( i2, j2, k2 ) = this->operator()(
i1 *ratio[0] + i2, j1 * ratio[1] + j2, k1 * ratio[2] + k2 );
}
}
@@ -1160,25 +1100,13 @@ void Array<TYPE, FUN, Allocator>::cat( const Array<TYPE, FUN, Allocator> &x, int
*this = cat( tmp, dim );
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::cat( const std::initializer_list<Array> &x,
int dim )
{
return cat( x.size(), x.begin(), dim );
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::cat( const std::vector<Array> &x, int dim )
{
return cat( x.size(), x.data(), dim );
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator>
Array<TYPE, FUN, Allocator>::cat( size_t N_array, const Array *x, int dim )
{
if ( N_array == 0 )
if ( x.empty() )
return Array<TYPE, FUN, Allocator>();
// Check that the dimensions match
bool check = true;
for ( size_t i = 1; i < N_array; i++ ) {
for ( size_t i = 1; i < x.size(); i++ ) {
check = check && x[i].ndim() == x[0].ndim();
for ( int d = 0; d < x[0].ndim(); d++ )
if ( d != dim )
@@ -1188,7 +1116,7 @@ Array<TYPE, FUN, Allocator>::cat( size_t N_array, const Array *x, int dim )
throw std::logic_error( "Array dimensions do not match for concatenation" );
// Create the output array
auto size = x[0].d_size;
for ( size_t i = 1; i < N_array; i++ )
for ( size_t i = 1; i < x.size(); i++ )
size.resize( dim, size[dim] + x[i].size( dim ) );
Array<TYPE, FUN, Allocator> out( size );
size_t N1 = 1;
@@ -1199,7 +1127,7 @@ Array<TYPE, FUN, Allocator>::cat( size_t N_array, const Array *x, int dim )
for ( size_t d = dim + 1; d < size.ndim(); d++ )
N3 *= size[d];
TYPE *data = out.data();
for ( size_t i = 0, i0 = 0; i < N_array; i++ ) {
for ( size_t i = 0, i0 = 0; i < x.size(); i++ ) {
const TYPE *src = x[i].data();
size_t N22 = x[i].size( dim );
for ( size_t j2 = 0; j2 < N3; j2++ ) {
@@ -1219,82 +1147,87 @@ Array<TYPE, FUN, Allocator>::cat( size_t N_array, const Array *x, int dim )
* Interpolate *
********************************************************/
template<class T>
constexpr bool is_compatible_double()
struct is_compatible_double
: std::integral_constant<bool, std::is_floating_point<T>::value || std::is_integral<T>::value> {
};
template<class TYPE>
inline typename std::enable_if<is_compatible_double<TYPE>::value, TYPE>::type Array_interp_1D(
double x, int N, const TYPE *data )
{
return std::is_floating_point<T>::value || std::is_integral<T>::value;
int i = floor( x );
i = std::max( i, 0 );
i = std::min( i, N - 2 );
return ( i + 1 - x ) * data[i] + ( x - i ) * data[i + 1];
}
template<class TYPE>
inline TYPE Array_interp_1D( double x, int N, const TYPE *data )
inline typename std::enable_if<is_compatible_double<TYPE>::value, TYPE>::type Array_interp_2D(
double x, double y, int Nx, int Ny, const TYPE *data )
{
if ( is_compatible_double<TYPE>() ) {
int i = floor( x );
i = std::max( i, 0 );
i = std::min( i, N - 2 );
return ( i + 1 - x ) * data[i] + ( x - i ) * data[i + 1];
} else {
throw std::logic_error( "Invalid conversion" );
}
int i = floor( x );
i = std::max( i, 0 );
i = std::min( i, Nx - 2 );
double dx = x - i;
double dx2 = 1.0 - dx;
int j = floor( y );
j = std::max( j, 0 );
j = std::min( j, Ny - 2 );
double dy = y - j;
double dy2 = 1.0 - dy;
double f[4] = { (double) data[i + j * Nx], (double) data[i + 1 + j * Nx],
(double) data[i + ( j + 1 ) * Nx], (double) data[i + 1 + ( j + 1 ) * Nx] };
return ( dx * f[1] + dx2 * f[0] ) * dy2 + ( dx * f[3] + dx2 * f[2] ) * dy;
}
template<class TYPE>
inline TYPE Array_interp_2D( double x, double y, int Nx, int Ny, const TYPE *data )
inline typename std::enable_if<is_compatible_double<TYPE>::value, TYPE>::type Array_interp_3D(
double x, double y, double z, int Nx, int Ny, int Nz, const TYPE *data )
{
if ( is_compatible_double<TYPE>() ) {
int i = floor( x );
i = std::max( i, 0 );
i = std::min( i, Nx - 2 );
double dx = x - i;
double dx2 = 1.0 - dx;
int j = floor( y );
j = std::max( j, 0 );
j = std::min( j, Ny - 2 );
double dy = y - j;
double dy2 = 1.0 - dy;
double f[4] = { (double) data[i + j * Nx],
(double) data[i + 1 + j * Nx],
(double) data[i + ( j + 1 ) * Nx],
(double) data[i + 1 + ( j + 1 ) * Nx] };
return ( dx * f[1] + dx2 * f[0] ) * dy2 + ( dx * f[3] + dx2 * f[2] ) * dy;
} else {
throw std::logic_error( "Invalid conversion" );
}
int i = floor( x );
i = std::max( i, 0 );
i = std::min( i, Nx - 2 );
double dx = x - i;
double dx2 = 1.0 - dx;
int j = floor( y );
j = std::max( j, 0 );
j = std::min( j, Ny - 2 );
double dy = y - j;
double dy2 = 1.0 - dy;
int k = floor( z );
k = std::max( k, 0 );
k = std::min( k, Nz - 2 );
double dz = z - k;
double dz2 = 1.0 - dz;
double f[8] = { (double) data[i + j * Nx + k * Nx * Ny],
(double) data[i + 1 + j * Nx + k * Nx * Ny],
(double) data[i + ( j + 1 ) * Nx + k * Nx * Ny],
(double) data[i + 1 + ( j + 1 ) * Nx + k * Nx * Ny],
(double) data[i + j * Nx + ( k + 1 ) * Nx * Ny],
(double) data[i + 1 + j * Nx + ( k + 1 ) * Nx * Ny],
(double) data[i + ( j + 1 ) * Nx + ( k + 1 ) * Nx * Ny],
(double) data[i + 1 + ( j + 1 ) * Nx + ( k + 1 ) * Nx * Ny] };
double h0 = ( dx * f[1] + dx2 * f[0] ) * dy2 + ( dx * f[3] + dx2 * f[2] ) * dy;
double h1 = ( dx * f[5] + dx2 * f[4] ) * dy2 + ( dx * f[7] + dx2 * f[6] ) * dy;
return h0 * dz2 + h1 * dz;
}
template<class TYPE>
inline TYPE
Array_interp_3D( double x, double y, double z, int Nx, int Ny, int Nz, const TYPE *data )
inline typename std::enable_if<!is_compatible_double<TYPE>::value, TYPE>::type Array_interp_1D(
double, int, const TYPE * )
{
if ( is_compatible_double<TYPE>() ) {
int i = floor( x );
i = std::max( i, 0 );
i = std::min( i, Nx - 2 );
double dx = x - i;
double dx2 = 1.0 - dx;
int j = floor( y );
j = std::max( j, 0 );
j = std::min( j, Ny - 2 );
double dy = y - j;
double dy2 = 1.0 - dy;
int k = floor( z );
k = std::max( k, 0 );
k = std::min( k, Nz - 2 );
double dz = z - k;
double dz2 = 1.0 - dz;
double f[8] = { (double) data[i + j * Nx + k * Nx * Ny],
(double) data[i + 1 + j * Nx + k * Nx * Ny],
(double) data[i + ( j + 1 ) * Nx + k * Nx * Ny],
(double) data[i + 1 + ( j + 1 ) * Nx + k * Nx * Ny],
(double) data[i + j * Nx + ( k + 1 ) * Nx * Ny],
(double) data[i + 1 + j * Nx + ( k + 1 ) * Nx * Ny],
(double) data[i + ( j + 1 ) * Nx + ( k + 1 ) * Nx * Ny],
(double) data[i + 1 + ( j + 1 ) * Nx + ( k + 1 ) * Nx * Ny] };
double h0 = ( dx * f[1] + dx2 * f[0] ) * dy2 + ( dx * f[3] + dx2 * f[2] ) * dy;
double h1 = ( dx * f[5] + dx2 * f[4] ) * dy2 + ( dx * f[7] + dx2 * f[6] ) * dy;
return h0 * dz2 + h1 * dz;
} else {
throw std::logic_error( "Invalid conversion" );
}
throw std::logic_error( "Invalid conversion" );
}
template<class TYPE>
inline typename std::enable_if<!is_compatible_double<TYPE>::value, TYPE>::type Array_interp_2D(
double, double, int, int, const TYPE * )
{
throw std::logic_error( "Invalid conversion" );
}
template<class TYPE>
inline typename std::enable_if<!is_compatible_double<TYPE>::value, TYPE>::type Array_interp_3D(
double, double, double, int, int, int, const TYPE * )
{
throw std::logic_error( "Invalid conversion" );
}
template<class TYPE, class FUN, class Allocator>
TYPE Array<TYPE, FUN, Allocator>::interp( const double *x ) const
TYPE Array<TYPE, FUN, Allocator>::interp( const std::vector<double> &x ) const
{
int ndim = 0, dim[5];
double x2[5];
@@ -1324,82 +1257,87 @@ TYPE Array<TYPE, FUN, Allocator>::interp( const double *x ) const
/********************************************************
* Math operations (should call the Math class) *
********************************************************/
/*template<class TYPE, class FUN, class Allocator>
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::rand()
{
FUN::rand( *this );
}
*/
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator> &
Array<TYPE, FUN, Allocator>::operator+=( const Array<TYPE, FUN, Allocator> &rhs )
Array<TYPE, FUN, Allocator> &Array<TYPE, FUN, Allocator>::operator+=(
const Array<TYPE, FUN, Allocator> &rhs )
{
auto op = []( const TYPE &a, const TYPE &b ) { return a + b; };
FUN::transform( op, *this, rhs, *this );
const auto &fun = []( const TYPE &a, const TYPE &b ) { return a + b; };
FUN::transform( fun, *this, rhs, *this );
return *this;
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator> &
Array<TYPE, FUN, Allocator>::operator-=( const Array<TYPE, FUN, Allocator> &rhs )
Array<TYPE, FUN, Allocator> &Array<TYPE, FUN, Allocator>::operator-=(
const Array<TYPE, FUN, Allocator> &rhs )
{
auto op = []( const TYPE &a, const TYPE &b ) { return a - b; };
FUN::transform( op, *this, rhs, *this );
const auto &fun = []( const TYPE &a, const TYPE &b ) { return a - b; };
FUN::transform( fun, *this, rhs, *this );
return *this;
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator> &Array<TYPE, FUN, Allocator>::operator+=( const TYPE &rhs )
{
auto op = [rhs]( const TYPE &x ) { return x + rhs; };
FUN::transform( op, *this, *this );
const auto &fun = [rhs]( const TYPE &x ) { return x + rhs; };
FUN::transform( fun, *this, *this );
return *this;
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator> &Array<TYPE, FUN, Allocator>::operator-=( const TYPE &rhs )
{
auto op = [rhs]( const TYPE &x ) { return x - rhs; };
FUN::transform( op, *this, *this );
const auto &fun = [rhs]( const TYPE &x ) { return x - rhs; };
FUN::transform( fun, *this, *this );
return *this;
}
template<class TYPE, class FUN, class Allocator>
TYPE Array<TYPE, FUN, Allocator>::min() const
{
const auto &op = []( const TYPE &a, const TYPE &b ) { return a < b ? a : b; };
return FUN::reduce( op, *this, d_data[0] );
const auto &fun = []( const TYPE &a, const TYPE &b ) { return a < b ? a : b; };
return FUN::reduce( fun, *this );
}
template<class TYPE, class FUN, class Allocator>
TYPE Array<TYPE, FUN, Allocator>::max() const
{
const auto &op = []( const TYPE &a, const TYPE &b ) { return a > b ? a : b; };
return FUN::reduce( op, *this, d_data[0] );
const auto &fun = []( const TYPE &a, const TYPE &b ) { return a > b ? a : b; };
return FUN::reduce( fun, *this );
}
template<class TYPE, class FUN, class Allocator>
TYPE Array<TYPE, FUN, Allocator>::sum() const
{
const auto &op = []( const TYPE &a, const TYPE &b ) { return a + b; };
return FUN::reduce( op, *this, static_cast<TYPE>( 0 ) );
const auto &fun = []( const TYPE &a, const TYPE &b ) { return a + b; };
return FUN::reduce( fun, *this );
}
template<class TYPE, class FUN, class Allocator>
void Array<TYPE, FUN, Allocator>::axpby( const TYPE &alpha,
const Array<TYPE, FUN, Allocator> &x,
const TYPE &beta )
Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::multiply(
const Array<TYPE, FUN, Allocator> &a, const Array<TYPE, FUN, Allocator> &b )
{
const auto &op = [alpha, beta]( const TYPE &x, const TYPE &y ) { return alpha * x + beta * y; };
return FUN::transform( op, x, *this, *this );
Array<TYPE, FUN, Allocator> c;
FUN::multiply( a, b, c );
return c;
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator>
Array<TYPE, FUN, Allocator>::transform( std::function<TYPE( const TYPE & )> fun,
const Array<TYPE, FUN, Allocator> &x )
void Array<TYPE, FUN, Allocator>::axpby(
const TYPE &alpha, const Array<TYPE, FUN, Allocator> &x, const TYPE &beta )
{
const auto &fun = [alpha, beta](
const TYPE &x, const TYPE &y ) { return alpha * x + beta * y; };
return FUN::transform( fun, x, *this, *this );
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::transform(
std::function<TYPE( const TYPE & )> fun, const Array<TYPE, FUN, Allocator> &x )
{
Array<TYPE, FUN, Allocator> y;
FUN::transform( fun, x, y );
return y;
}
template<class TYPE, class FUN, class Allocator>
Array<TYPE, FUN, Allocator>
Array<TYPE, FUN, Allocator>::transform( std::function<TYPE( const TYPE &, const TYPE & )> fun,
const Array<TYPE, FUN, Allocator> &x,
const Array<TYPE, FUN, Allocator> &y )
Array<TYPE, FUN, Allocator> Array<TYPE, FUN, Allocator>::transform(
std::function<TYPE( const TYPE &, const TYPE & )> fun, const Array<TYPE, FUN, Allocator> &x,
const Array<TYPE, FUN, Allocator> &y )
{
Array<TYPE, FUN, Allocator> z;
FUN::transform( fun, x, y, z );
@@ -1411,5 +1349,4 @@ bool Array<TYPE, FUN, Allocator>::equals( const Array &rhs, TYPE tol ) const
return FUN::equals( *this, rhs, tol );
}
#endif

View File

@@ -1,12 +1,8 @@
#ifndef included_ArraySizeClass
#define included_ArraySizeClass
#include "common/Utilities.h"
#include <array>
#include <cmath>
#include <complex>
#include <cstdlib>
#include <cstring>
#include <initializer_list>
#include <vector>
@@ -26,22 +22,21 @@
#if ( defined( DEBUG ) || defined( _DEBUG ) ) && !defined( NDEBUG )
#define CHECK_ARRAY_LENGTH( i, length ) \
#define CHECK_ARRAY_LENGTH( i ) \
do { \
if ( i >= length ) \
if ( i >= d_length ) \
throw std::out_of_range( "Index exceeds array bounds" ); \
} while ( 0 )
#else
#define CHECK_ARRAY_LENGTH( i, length ) \
do { \
#define CHECK_ARRAY_LENGTH( i ) \
do { \
} while ( 0 )
#endif
// Forward declerations
class FunctionTable;
template<class TYPE, class FUN = FunctionTable, class Allocator = std::allocator<TYPE>>
template<class TYPE, class FUN = FunctionTable, class Allocator = std::nullptr_t>
class Array;
@@ -51,7 +46,7 @@ class Range final
{
public:
//! Empty constructor
Range() : i( 0 ), j( -1 ), k( 1 ) {}
constexpr Range() : i( 0 ), j( -1 ), k( 1 ) {}
/*!
* Create a range i:k:j (or i:j)
@@ -59,30 +54,8 @@ public:
* @param j_ Ending value
* @param k_ Increment value
*/
Range( const TYPE &i_, const TYPE &j_, const TYPE &k_ = 1 )
: i( i_ ), j( j_ ), k( k_ )
{
}
constexpr Range( TYPE i_, TYPE j_, 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;
};
@@ -92,20 +65,20 @@ class ArraySize final
{
public:
//! Empty constructor
ArraySize() : d_ndim( 1 ), d_length( 0 ), d_N{ 0, 1, 1, 1, 1 } {}
constexpr 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
*/
ArraySize( size_t N1 ) : d_ndim( 1 ), d_length( N1 ), d_N{ N1, 1, 1, 1, 1 } {}
constexpr 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
*/
ArraySize( size_t N1, size_t N2 )
constexpr ArraySize( size_t N1, size_t N2 )
: d_ndim( 2 ), d_length( N1 * N2 ), d_N{ N1, N2, 1, 1, 1 }
{
}
@@ -116,7 +89,7 @@ public:
* @param N2 Number of elements in the second dimension
* @param N3 Number of elements in the third dimension
*/
ArraySize( size_t N1, size_t N2, size_t N3 )
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 }
{
}
@@ -128,7 +101,7 @@ public:
* @param N3 Number of elements in the third dimension
* @param N4 Number of elements in the fourth dimension
*/
ArraySize( size_t N1, size_t N2, size_t N3, size_t N4 )
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 }
{
}
@@ -141,7 +114,7 @@ public:
* @param N4 Number of elements in the fourth dimension
* @param N5 Number of elements in the fifth dimension
*/
ArraySize( size_t N1, size_t N2, size_t N3, size_t N4, size_t N5 )
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 }
{
}
@@ -149,14 +122,11 @@ public:
/*!
* Create from initializer list
* @param N Size of the array
* @param ndim Number of dimensions
*/
ArraySize( std::initializer_list<size_t> N, int ndim = -1 )
constexpr ArraySize( std::initializer_list<size_t> N )
: d_ndim( N.size() ), d_length( 0 ), d_N{ 0, 1, 1, 1, 1 }
{
if ( ndim >= 0 )
d_ndim = ndim;
if ( d_ndim > 5 )
if ( d_ndim > maxDim() )
throw std::out_of_range( "Maximum number of dimensions exceeded" );
auto it = N.begin();
for ( size_t i = 0; i < d_ndim; i++, ++it )
@@ -174,10 +144,10 @@ public:
* @param ndim Number of dimensions
* @param dims Dimensions
*/
ArraySize( size_t ndim, const size_t *dims )
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 > 5 )
if ( d_ndim > maxDim() )
throw std::out_of_range( "Maximum number of dimensions exceeded" );
for ( size_t i = 0; i < ndim; i++ )
d_N[i] = dims[i];
@@ -188,44 +158,35 @@ public:
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
*/
inline ArraySize( const std::vector<size_t> &N ) : ArraySize( N.size(), N.data() ) {}
ArraySize( const std::vector<size_t> &N );
// Copy/assignment constructors
ArraySize( ArraySize &&rhs ) = default;
ArraySize( const ArraySize &rhs ) = default;
ArraySize &operator=( ArraySize &&rhs ) = default;
ArraySize &operator=( const ArraySize &rhs ) = default;
constexpr ArraySize( ArraySize &&rhs ) = default;
constexpr ArraySize( const ArraySize &rhs ) = default;
constexpr ArraySize &operator=( ArraySize &&rhs ) = default;
constexpr ArraySize &operator=( const ArraySize &rhs ) = default;
/*!
* Access the ith dimension
* @param i Index to access
*/
ARRAY_ATTRIBUTE size_t operator[]( size_t i ) const { return d_N[i]; }
constexpr ARRAY_ATTRIBUTE size_t operator[]( size_t i ) const { return d_N[i]; }
//! Return the number of dimensions
ARRAY_ATTRIBUTE uint8_t ndim() const { return d_ndim; }
constexpr ARRAY_ATTRIBUTE uint8_t ndim() const { return d_ndim; }
//! Return the number of dimensions
ARRAY_ATTRIBUTE size_t size() const { return d_ndim; }
constexpr ARRAY_ATTRIBUTE size_t size() const { return d_ndim; }
//! Return the total number of elements in the array
ARRAY_ATTRIBUTE size_t length() const { return d_length; }
constexpr ARRAY_ATTRIBUTE size_t length() const { return d_length; }
//! Resize the dimension
void resize( uint8_t dim, size_t N )
constexpr void resize( uint8_t dim, size_t N )
{
if ( dim >= d_ndim )
throw std::out_of_range( "Invalid dimension" );
@@ -240,141 +201,75 @@ public:
* max of ndim and the largest dim>1.
* @param ndim Desired number of dimensions
*/
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];
}
}
constexpr void setNdim( uint8_t ndim ) { d_ndim = std::max( ndim, d_ndim ); }
//! Returns an iterator to the beginning
const size_t *begin() const { return d_N; }
constexpr const size_t *begin() const { return d_N; }
//! Returns an iterator to the end
const size_t *end() const { return d_N + d_ndim; }
constexpr const size_t *end() const { return d_N + d_ndim; }
// Check if two array sizes are equal
ARRAY_ATTRIBUTE bool operator==( const ArraySize &rhs ) const
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;
}
// Check if two array sizes are equal (ignoring the dimension)
ARRAY_ATTRIBUTE bool approxEqual( const ArraySize &rhs ) const
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;
}
//! Check if two matrices are not equal
ARRAY_ATTRIBUTE bool operator!=( const ArraySize &rhs ) const
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;
}
//! Maximum supported dimension
ARRAY_ATTRIBUTE static uint8_t maxDim() { return 5; }
constexpr ARRAY_ATTRIBUTE static uint8_t maxDim() { return 5u; }
//! Get the index
ARRAY_ATTRIBUTE size_t index( size_t i ) const
constexpr ARRAY_ATTRIBUTE size_t index( size_t i ) const
{
CHECK_ARRAY_LENGTH( i, d_length );
CHECK_ARRAY_LENGTH( i );
return i;
}
//! Get the index
ARRAY_ATTRIBUTE size_t index( size_t i1, size_t i2 ) const
constexpr ARRAY_ATTRIBUTE size_t index( size_t i1, size_t i2 ) const
{
size_t index = i1 + i2 * d_N[0];
CHECK_ARRAY_LENGTH( index, d_length );
CHECK_ARRAY_LENGTH( index );
return index;
}
//! Get the index
ARRAY_ATTRIBUTE size_t index( size_t i1, size_t i2, size_t i3 ) const
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, d_length );
CHECK_ARRAY_LENGTH( index );
return index;
}
//! Get the index
ARRAY_ATTRIBUTE size_t index( size_t i1, size_t i2, size_t i3, size_t i4 ) const
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, d_length );
CHECK_ARRAY_LENGTH( index );
return index;
}
//! Get the index
ARRAY_ATTRIBUTE size_t
index( size_t i1, size_t i2, size_t i3, size_t i4, size_t i5 ) const
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, d_length );
CHECK_ARRAY_LENGTH( index );
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;
@@ -383,11 +278,11 @@ private:
// Function to concatenate dimensions of two array sizes
inline ArraySize cat( const ArraySize &x, const ArraySize &y )
constexpr ArraySize cat( const ArraySize &x, const ArraySize &y )
{
if ( x.ndim() + y.ndim() > 5 )
if ( x.ndim() + y.ndim() > ArraySize::maxDim() )
throw std::out_of_range( "Maximum number of dimensions exceeded" );
size_t N[5] = { 0 };
size_t N[ArraySize::maxDim()] = { 0 };
for ( int i = 0; i < x.ndim(); i++ )
N[i] = x[i];
for ( int i = 0; i < y.ndim(); i++ )
@@ -396,36 +291,4 @@ inline ArraySize cat( const ArraySize &x, const ArraySize &y )
}
// 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

View File

@@ -1,6 +1,5 @@
/*
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

View File

@@ -1,6 +1,5 @@
/*
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
@@ -17,7 +16,7 @@
#ifndef COMMUNICATION_H_INC
#define COMMUNICATION_H_INC
#include "common/MPI.h"
#include "common/MPI_Helpers.h"
#include "common/Utilities.h"
#include "common/Array.h"
@@ -54,7 +53,7 @@ struct RankInfoStruct {
//! 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 );
const RankInfoStruct& dst_rank, std::array<int,3> dst_size, MPI_Comm comm );
/*!
@@ -67,7 +66,6 @@ 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
@@ -76,7 +74,7 @@ public:
* @param[in] fill Fill {faces,edges,corners}
* @param[in] periodic Periodic dimensions
*/
fillHalo( const Utilities::MPI& comm, const RankInfoStruct& info,
fillHalo( MPI_Comm 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} );
@@ -84,10 +82,6 @@ public:
//! Destructor
~fillHalo( );
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
@@ -104,7 +98,7 @@ public:
private:
Utilities::MPI comm;
MPI_Comm comm;
RankInfoStruct info;
std::array<int,3> n, ng;
int depth;
@@ -114,13 +108,18 @@ private:
TYPE *mem;
TYPE *send[3][3][3], *recv[3][3][3];
MPI_Request send_req[3][3][3], recv_req[3][3][3];
size_t N_type;
MPI_Datatype datatype;
fillHalo(); // Private empty constructor
fillHalo(const fillHalo&); // Private copy constructor
fillHalo& operator=(const fillHalo&); // Private assignment operator
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){
inline void PackMeshData(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;
@@ -129,7 +128,7 @@ inline void PackMeshData(const int *list, int count, double *sendbuf, double *da
sendbuf[idx] = data[n];
}
}
inline void UnpackMeshData(const int *list, int count, double *recvbuf, double *data){
inline void UnpackMeshData(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;
@@ -152,7 +151,7 @@ void InitializeRanks( const int rank, const int nprocx, const int nprocy, const
//***************************************************************************************
inline void CommunicateSendRecvCounts( const Utilities::MPI& comm, int sendtag, int recvtag,
inline void CommunicateSendRecvCounts( MPI_Comm Communicator, 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,
@@ -170,53 +169,54 @@ inline void CommunicateSendRecvCounts( const Utilities::MPI& comm, int sendtag,
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);
MPI_Status stat1[18],stat2[18];
MPI_Isend(&sendCount_x, 1,MPI_INT,rank_x,sendtag+0,Communicator,&req1[0]);
MPI_Irecv(&recvCount_X, 1,MPI_INT,rank_X,recvtag+0,Communicator,&req2[0]);
MPI_Isend(&sendCount_X, 1,MPI_INT,rank_X,sendtag+1,Communicator,&req1[1]);
MPI_Irecv(&recvCount_x, 1,MPI_INT,rank_x,recvtag+1,Communicator,&req2[1]);
MPI_Isend(&sendCount_y, 1,MPI_INT,rank_y,sendtag+2,Communicator,&req1[2]);
MPI_Irecv(&recvCount_Y, 1,MPI_INT,rank_Y,recvtag+2,Communicator,&req2[2]);
MPI_Isend(&sendCount_Y, 1,MPI_INT,rank_Y,sendtag+3,Communicator,&req1[3]);
MPI_Irecv(&recvCount_y, 1,MPI_INT,rank_y,recvtag+3,Communicator,&req2[3]);
MPI_Isend(&sendCount_z, 1,MPI_INT,rank_z,sendtag+4,Communicator,&req1[4]);
MPI_Irecv(&recvCount_Z, 1,MPI_INT,rank_Z,recvtag+4,Communicator,&req2[4]);
MPI_Isend(&sendCount_Z, 1,MPI_INT,rank_Z,sendtag+5,Communicator,&req1[5]);
MPI_Irecv(&recvCount_z, 1,MPI_INT,rank_z,recvtag+5,Communicator,&req2[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);
MPI_Isend(&sendCount_xy, 1,MPI_INT,rank_xy,sendtag+6,Communicator,&req1[6]);
MPI_Irecv(&recvCount_XY, 1,MPI_INT,rank_XY,recvtag+6,Communicator,&req2[6]);
MPI_Isend(&sendCount_XY, 1,MPI_INT,rank_XY,sendtag+7,Communicator,&req1[7]);
MPI_Irecv(&recvCount_xy, 1,MPI_INT,rank_xy,recvtag+7,Communicator,&req2[7]);
MPI_Isend(&sendCount_Xy, 1,MPI_INT,rank_Xy,sendtag+8,Communicator,&req1[8]);
MPI_Irecv(&recvCount_xY, 1,MPI_INT,rank_xY,recvtag+8,Communicator,&req2[8]);
MPI_Isend(&sendCount_xY, 1,MPI_INT,rank_xY,sendtag+9,Communicator,&req1[9]);
MPI_Irecv(&recvCount_Xy, 1,MPI_INT,rank_Xy,recvtag+9,Communicator,&req2[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);
MPI_Isend(&sendCount_xz, 1,MPI_INT,rank_xz,sendtag+10,Communicator,&req1[10]);
MPI_Irecv(&recvCount_XZ, 1,MPI_INT,rank_XZ,recvtag+10,Communicator,&req2[10]);
MPI_Isend(&sendCount_XZ, 1,MPI_INT,rank_XZ,sendtag+11,Communicator,&req1[11]);
MPI_Irecv(&recvCount_xz, 1,MPI_INT,rank_xz,recvtag+11,Communicator,&req2[11]);
MPI_Isend(&sendCount_Xz, 1,MPI_INT,rank_Xz,sendtag+12,Communicator,&req1[12]);
MPI_Irecv(&recvCount_xZ, 1,MPI_INT,rank_xZ,recvtag+12,Communicator,&req2[12]);
MPI_Isend(&sendCount_xZ, 1,MPI_INT,rank_xZ,sendtag+13,Communicator,&req1[13]);
MPI_Irecv(&recvCount_Xz, 1,MPI_INT,rank_Xz,recvtag+13,Communicator,&req2[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();
MPI_Isend(&sendCount_yz, 1,MPI_INT,rank_yz,sendtag+14,Communicator,&req1[14]);
MPI_Irecv(&recvCount_YZ, 1,MPI_INT,rank_YZ,recvtag+14,Communicator,&req2[14]);
MPI_Isend(&sendCount_YZ, 1,MPI_INT,rank_YZ,sendtag+15,Communicator,&req1[15]);
MPI_Irecv(&recvCount_yz, 1,MPI_INT,rank_yz,recvtag+15,Communicator,&req2[15]);
MPI_Isend(&sendCount_Yz, 1,MPI_INT,rank_Yz,sendtag+16,Communicator,&req1[16]);
MPI_Irecv(&recvCount_yZ, 1,MPI_INT,rank_yZ,recvtag+16,Communicator,&req2[16]);
MPI_Isend(&sendCount_yZ, 1,MPI_INT,rank_yZ,sendtag+17,Communicator,&req1[17]);
MPI_Irecv(&recvCount_Yz, 1,MPI_INT,rank_Yz,recvtag+17,Communicator,&req2[17]);
MPI_Waitall(18,req1,stat1);
MPI_Waitall(18,req2,stat2);
MPI_Barrier(Communicator);
}
//***************************************************************************************
inline void CommunicateRecvLists( const Utilities::MPI& comm, int sendtag, int recvtag,
inline void CommunicateRecvLists( MPI_Comm Communicator, int sendtag, int recvtag,
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,
@@ -237,52 +237,53 @@ inline void CommunicateRecvLists( const Utilities::MPI& comm, int sendtag, int r
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)
{
MPI_Request req1[18], req2[18];
req1[0] = comm.Isend(sendList_x,sendCount_x,rank_x,sendtag);
req2[0] = comm.Irecv(recvList_X,recvCount_X,rank_X,recvtag);
req1[1] = comm.Isend(sendList_X,sendCount_X,rank_X,sendtag);
req2[1] = comm.Irecv(recvList_x,recvCount_x,rank_x,recvtag);
req1[2] = comm.Isend(sendList_y,sendCount_y,rank_y,sendtag);
req2[2] = comm.Irecv(recvList_Y,recvCount_Y,rank_Y,recvtag);
req1[3] = comm.Isend(sendList_Y,sendCount_Y,rank_Y,sendtag);
req2[3] = comm.Irecv(recvList_y,recvCount_y,rank_y,recvtag);
req1[4] = comm.Isend(sendList_z,sendCount_z,rank_z,sendtag);
req2[4] = comm.Irecv(recvList_Z,recvCount_Z,rank_Z,recvtag);
req1[5] = comm.Isend(sendList_Z,sendCount_Z,rank_Z,sendtag);
req2[5] = comm.Irecv(recvList_z,recvCount_z,rank_z,recvtag);
MPI_Status stat1[18],stat2[18];
MPI_Isend(sendList_x, sendCount_x,MPI_INT,rank_x,sendtag,Communicator,&req1[0]);
MPI_Irecv(recvList_X, recvCount_X,MPI_INT,rank_X,recvtag,Communicator,&req2[0]);
MPI_Isend(sendList_X, sendCount_X,MPI_INT,rank_X,sendtag,Communicator,&req1[1]);
MPI_Irecv(recvList_x, recvCount_x,MPI_INT,rank_x,recvtag,Communicator,&req2[1]);
MPI_Isend(sendList_y, sendCount_y,MPI_INT,rank_y,sendtag,Communicator,&req1[2]);
MPI_Irecv(recvList_Y, recvCount_Y,MPI_INT,rank_Y,recvtag,Communicator,&req2[2]);
MPI_Isend(sendList_Y, sendCount_Y,MPI_INT,rank_Y,sendtag,Communicator,&req1[3]);
MPI_Irecv(recvList_y, recvCount_y,MPI_INT,rank_y,recvtag,Communicator,&req2[3]);
MPI_Isend(sendList_z, sendCount_z,MPI_INT,rank_z,sendtag,Communicator,&req1[4]);
MPI_Irecv(recvList_Z, recvCount_Z,MPI_INT,rank_Z,recvtag,Communicator,&req2[4]);
MPI_Isend(sendList_Z, sendCount_Z,MPI_INT,rank_Z,sendtag,Communicator,&req1[5]);
MPI_Irecv(recvList_z, recvCount_z,MPI_INT,rank_z,recvtag,Communicator,&req2[5]);
req1[6] = comm.Isend(sendList_xy,sendCount_xy,rank_xy,sendtag);
req2[6] = comm.Irecv(recvList_XY,recvCount_XY,rank_XY,recvtag);
req1[7] = comm.Isend(sendList_XY,sendCount_XY,rank_XY,sendtag);
req2[7] = comm.Irecv(recvList_xy,recvCount_xy,rank_xy,recvtag);
req1[8] = comm.Isend(sendList_Xy,sendCount_Xy,rank_Xy,sendtag);
req2[8] = comm.Irecv(recvList_xY,recvCount_xY,rank_xY,recvtag);
req1[9] = comm.Isend(sendList_xY,sendCount_xY,rank_xY,sendtag);
req2[9] = comm.Irecv(recvList_Xy,recvCount_Xy,rank_Xy,recvtag);
MPI_Isend(sendList_xy, sendCount_xy,MPI_INT,rank_xy,sendtag,Communicator,&req1[6]);
MPI_Irecv(recvList_XY, recvCount_XY,MPI_INT,rank_XY,recvtag,Communicator,&req2[6]);
MPI_Isend(sendList_XY, sendCount_XY,MPI_INT,rank_XY,sendtag,Communicator,&req1[7]);
MPI_Irecv(recvList_xy, recvCount_xy,MPI_INT,rank_xy,recvtag,Communicator,&req2[7]);
MPI_Isend(sendList_Xy, sendCount_Xy,MPI_INT,rank_Xy,sendtag,Communicator,&req1[8]);
MPI_Irecv(recvList_xY, recvCount_xY,MPI_INT,rank_xY,recvtag,Communicator,&req2[8]);
MPI_Isend(sendList_xY, sendCount_xY,MPI_INT,rank_xY,sendtag,Communicator,&req1[9]);
MPI_Irecv(recvList_Xy, recvCount_Xy,MPI_INT,rank_Xy,recvtag,Communicator,&req2[9]);
req1[10] = comm.Isend(sendList_xz,sendCount_xz,rank_xz,sendtag);
req2[10] = comm.Irecv(recvList_XZ,recvCount_XZ,rank_XZ,recvtag);
req1[11] = comm.Isend(sendList_XZ,sendCount_XZ,rank_XZ,sendtag);
req2[11] = comm.Irecv(recvList_xz,recvCount_xz,rank_xz,recvtag);
req1[12] = comm.Isend(sendList_Xz,sendCount_Xz,rank_Xz,sendtag);
req2[12] = comm.Irecv(recvList_xZ,recvCount_xZ,rank_xZ,recvtag);
req1[13] = comm.Isend(sendList_xZ,sendCount_xZ,rank_xZ,sendtag);
req2[13] = comm.Irecv(recvList_Xz,recvCount_Xz,rank_Xz,recvtag);
MPI_Isend(sendList_xz, sendCount_xz,MPI_INT,rank_xz,sendtag,Communicator,&req1[10]);
MPI_Irecv(recvList_XZ, recvCount_XZ,MPI_INT,rank_XZ,recvtag,Communicator,&req2[10]);
MPI_Isend(sendList_XZ, sendCount_XZ,MPI_INT,rank_XZ,sendtag,Communicator,&req1[11]);
MPI_Irecv(recvList_xz, recvCount_xz,MPI_INT,rank_xz,recvtag,Communicator,&req2[11]);
MPI_Isend(sendList_Xz, sendCount_Xz,MPI_INT,rank_Xz,sendtag,Communicator,&req1[12]);
MPI_Irecv(recvList_xZ, recvCount_xZ,MPI_INT,rank_xZ,recvtag,Communicator,&req2[12]);
MPI_Isend(sendList_xZ, sendCount_xZ,MPI_INT,rank_xZ,sendtag,Communicator,&req1[13]);
MPI_Irecv(recvList_Xz, recvCount_Xz,MPI_INT,rank_Xz,recvtag,Communicator,&req2[13]);
req1[14] = comm.Isend(sendList_yz,sendCount_yz,rank_yz,sendtag);
req2[14] = comm.Irecv(recvList_YZ,recvCount_YZ,rank_YZ,recvtag);
req1[15] = comm.Isend(sendList_YZ,sendCount_YZ,rank_YZ,sendtag);
req2[15] = comm.Irecv(recvList_yz,recvCount_yz,rank_yz,recvtag);
req1[16] = comm.Isend(sendList_Yz,sendCount_Yz,rank_Yz,sendtag);
req2[16] = comm.Irecv(recvList_yZ,recvCount_yZ,rank_yZ,recvtag);
req1[17] = comm.Isend(sendList_yZ,sendCount_yZ,rank_yZ,sendtag);
req2[17] = comm.Irecv(recvList_Yz,recvCount_Yz,rank_Yz,recvtag);
comm.waitAll( 18, req1 );
comm.waitAll( 18, req2 );
MPI_Isend(sendList_yz, sendCount_yz,MPI_INT,rank_yz,sendtag,Communicator,&req1[14]);
MPI_Irecv(recvList_YZ, recvCount_YZ,MPI_INT,rank_YZ,recvtag,Communicator,&req2[14]);
MPI_Isend(sendList_YZ, sendCount_YZ,MPI_INT,rank_YZ,sendtag,Communicator,&req1[15]);
MPI_Irecv(recvList_yz, recvCount_yz,MPI_INT,rank_yz,recvtag,Communicator,&req2[15]);
MPI_Isend(sendList_Yz, sendCount_Yz,MPI_INT,rank_Yz,sendtag,Communicator,&req1[16]);
MPI_Irecv(recvList_yZ, recvCount_yZ,MPI_INT,rank_yZ,recvtag,Communicator,&req2[16]);
MPI_Isend(sendList_yZ, sendCount_yZ,MPI_INT,rank_yZ,sendtag,Communicator,&req1[17]);
MPI_Irecv(recvList_Yz, recvCount_Yz,MPI_INT,rank_Yz,recvtag,Communicator,&req2[17]);
MPI_Waitall(18,req1,stat1);
MPI_Waitall(18,req2,stat2);
}
//***************************************************************************************
inline void CommunicateMeshHalo(DoubleArray &Mesh, const Utilities::MPI& comm,
inline void CommunicateMeshHalo(DoubleArray &Mesh, MPI_Comm Communicator,
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,
@@ -332,24 +333,42 @@ inline void CommunicateMeshHalo(DoubleArray &Mesh, const Utilities::MPI& comm,
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);
MPI_Sendrecv(sendbuf_x,sendCount_x,MPI_DOUBLE,rank_x,sendtag,
recvbuf_X,recvCount_X,MPI_DOUBLE,rank_X,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_X,sendCount_X,MPI_DOUBLE,rank_X,sendtag,
recvbuf_x,recvCount_x,MPI_DOUBLE,rank_x,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_y,sendCount_y,MPI_DOUBLE,rank_y,sendtag,
recvbuf_Y,recvCount_Y,MPI_DOUBLE,rank_Y,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_Y,sendCount_Y,MPI_DOUBLE,rank_Y,sendtag,
recvbuf_y,recvCount_y,MPI_DOUBLE,rank_y,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_z,sendCount_z,MPI_DOUBLE,rank_z,sendtag,
recvbuf_Z,recvCount_Z,MPI_DOUBLE,rank_Z,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_Z,sendCount_Z,MPI_DOUBLE,rank_Z,sendtag,
recvbuf_z,recvCount_z,MPI_DOUBLE,rank_z,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_xy,sendCount_xy,MPI_DOUBLE,rank_xy,sendtag,
recvbuf_XY,recvCount_XY,MPI_DOUBLE,rank_XY,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_XY,sendCount_XY,MPI_DOUBLE,rank_XY,sendtag,
recvbuf_xy,recvCount_xy,MPI_DOUBLE,rank_xy,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_Xy,sendCount_Xy,MPI_DOUBLE,rank_Xy,sendtag,
recvbuf_xY,recvCount_xY,MPI_DOUBLE,rank_xY,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_xY,sendCount_xY,MPI_DOUBLE,rank_xY,sendtag,
recvbuf_Xy,recvCount_Xy,MPI_DOUBLE,rank_Xy,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_xz,sendCount_xz,MPI_DOUBLE,rank_xz,sendtag,
recvbuf_XZ,recvCount_XZ,MPI_DOUBLE,rank_XZ,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_XZ,sendCount_XZ,MPI_DOUBLE,rank_XZ,sendtag,
recvbuf_xz,recvCount_xz,MPI_DOUBLE,rank_xz,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_Xz,sendCount_Xz,MPI_DOUBLE,rank_Xz,sendtag,
recvbuf_xZ,recvCount_xZ,MPI_DOUBLE,rank_xZ,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_xZ,sendCount_xZ,MPI_DOUBLE,rank_xZ,sendtag,
recvbuf_Xz,recvCount_Xz,MPI_DOUBLE,rank_Xz,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_yz,sendCount_yz,MPI_DOUBLE,rank_yz,sendtag,
recvbuf_YZ,recvCount_YZ,MPI_DOUBLE,rank_YZ,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_YZ,sendCount_YZ,MPI_DOUBLE,rank_YZ,sendtag,
recvbuf_yz,recvCount_yz,MPI_DOUBLE,rank_yz,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_Yz,sendCount_Yz,MPI_DOUBLE,rank_Yz,sendtag,
recvbuf_yZ,recvCount_yZ,MPI_DOUBLE,rank_yZ,recvtag,Communicator,MPI_STATUS_IGNORE);
MPI_Sendrecv(sendbuf_yZ,sendCount_yZ,MPI_DOUBLE,rank_yZ,sendtag,
recvbuf_Yz,recvCount_Yz,MPI_DOUBLE,rank_Yz,recvtag,Communicator,MPI_STATUS_IGNORE);
//........................................................................................
UnpackMeshData(recvList_x, recvCount_x ,recvbuf_x, MeshData);
UnpackMeshData(recvList_X, recvCount_X ,recvbuf_X, MeshData);

View File

@@ -1,6 +1,5 @@
/*
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
@@ -16,7 +15,6 @@
*/
/*
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
@@ -34,8 +32,9 @@
#define COMMUNICATION_HPP_INC
#include "common/Communication.h"
#include "common/MPI.h"
#include "common/MPI_Helpers.h"
#include "common/Utilities.h"
//#include "ProfilerApp.h"
/********************************************************
@@ -43,19 +42,17 @@
********************************************************/
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 )
const RankInfoStruct& dst_rank, std::array<int,3> dst_size, MPI_Comm 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 } );
}
#ifdef USE_MPI
// 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 );
MPI_Allreduce( size0, src_size.data(), 3, MPI_INT, MPI_MAX, comm );
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 );
MPI_Allreduce( dst_size.data(), size0, 3, MPI_INT, MPI_MAX, comm );
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] ) {
@@ -77,9 +74,9 @@ Array<TYPE> redistribute( const RankInfoStruct& src_rank, const Array<TYPE>& src
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++ ) {
for ( size_t i=0; i<dst_rank.nx; i++ ) {
for ( size_t j=0; j<dst_rank.ny; j++ ) {
for ( size_t 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 );
@@ -93,14 +90,14 @@ Array<TYPE> redistribute( const RankInfoStruct& src_rank, const Array<TYPE>& src
}
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 );
MPI_Isend( send_data[i].data(), sizeof(TYPE)*send_data[i].length(), MPI_BYTE, send_rank[i], 5462, comm, &send_request[i]);
// 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++ ) {
for ( size_t i=0; i<src_rank.nx; i++ ) {
for ( size_t j=0; j<src_rank.ny; j++ ) {
for ( size_t 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 );
@@ -108,14 +105,17 @@ Array<TYPE> redistribute( const RankInfoStruct& src_rank, const Array<TYPE>& src
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 );
MPI_Recv( data.data(), sizeof(TYPE)*data.length(), MPI_BYTE, rank, 5462, comm, MPI_STATUS_IGNORE );
dst_data.copySubset( index, data );
}
}
}
// Free data
comm.waitAll( send_request.size(), send_request.data() );
MPI_Waitall( send_request.size(), send_request.data(), MPI_STATUSES_IGNORE );
return dst_data;
#else
return src_data.subset( { 0, dst_size[0]-1, 0, dst_size[1]-1, 0, dst_size[2]-1 );
#endif
}
@@ -124,11 +124,27 @@ Array<TYPE> redistribute( const RankInfoStruct& src_rank, const Array<TYPE>& src
* Structure to fill halo cells *
********************************************************/
template<class TYPE>
fillHalo<TYPE>::fillHalo( const Utilities::MPI& comm_, const RankInfoStruct& info_,
fillHalo<TYPE>::fillHalo( MPI_Comm 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_)
{
if ( std::is_same<TYPE,double>() ) {
N_type = 1;
datatype = MPI_DOUBLE;
} else if ( std::is_same<TYPE,float>() ) {
N_type = 1;
datatype = MPI_FLOAT;
} else if ( sizeof(TYPE)%sizeof(double)==0 ) {
N_type = sizeof(TYPE) / sizeof(double);
datatype = MPI_DOUBLE;
} else if ( sizeof(TYPE)%sizeof(float)==0 ) {
N_type = sizeof(TYPE) / sizeof(float);
datatype = MPI_FLOAT;
} else {
N_type = sizeof(TYPE);
datatype = MPI_BYTE;
}
// Set the fill pattern
memset(fill_pattern,0,sizeof(fill_pattern));
if ( fill[0] ) {
@@ -265,8 +281,8 @@ void fillHalo<TYPE>::fill( Array<TYPE>& data )
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] );
MPI_Irecv( recv[i][j][k], N_type*depth2*N_send_recv[i][j][k], datatype,
info.rank[i][j][k], tag[2-i][2-j][2-k], comm, &recv_req[i][j][k] );
}
}
}
@@ -277,18 +293,19 @@ void fillHalo<TYPE>::fill( Array<TYPE>& data )
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] );
MPI_Isend( send[i][j][k], N_type*depth2*N_send_recv[i][j][k], datatype,
info.rank[i][j][k], tag[i][j][k], comm, &send_req[i][j][k] );
}
}
}
// Recv the dst data and unpack (we recive in reverse order to match the sends)
MPI_Status status;
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] );
MPI_Wait(&recv_req[i][j][k],&status);
unpack( data, i-1, j-1, k-1, recv[i][j][k] );
}
}
@@ -299,7 +316,7 @@ void fillHalo<TYPE>::fill( Array<TYPE>& data )
for (int k=0; k<3; k++) {
if ( !fill_pattern[i][j][k] )
continue;
comm.wait( send_req[i][j][k] );
MPI_Wait(&send_req[i][j][k],&status);
}
}
}

View File

@@ -1,6 +1,5 @@
/*
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

View File

@@ -1,6 +1,5 @@
/*
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

View File

@@ -1,6 +1,5 @@
/*
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
@@ -16,7 +15,6 @@
*/
/*
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

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,5 @@
/*
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
@@ -21,7 +20,6 @@
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <math.h>
#include <time.h>
#include <exception>
@@ -29,101 +27,90 @@
#include "common/Array.h"
#include "common/Utilities.h"
#include "common/MPI.h"
#include "common/MPI_Helpers.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 Box
*
* @details
* information about a box
*/
//! Class to hold information about a box
class Box {
public:
int ifirst[3];
int ilast[3];
};
class Patch;
/**
* \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.
*/
enum class DataLocation { CPU, DEVICE };
//! Class to hold information about a patch
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 domain info
class Domain{
public:
/**
* \brief Constructor
* @param db input database
* @param Communicator MPI communicator
*/
Domain( std::shared_ptr<Database> db, const Utilities::MPI& Communicator);
//! Default constructor
Domain( std::shared_ptr<Database> db, MPI_Comm Communicator);
/**
* \brief Obsolete constructor
*/
//! 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);
/**
* \brief Empty constructor
*/
//! Empty constructor
Domain() = delete;
/**
* \brief Copy constructor
*/
//! Copy constructor
Domain( const Domain& ) = delete;
/**
* \brief Assignment operator
*/
//! Assignment operator
Domain& operator=( const Domain& ) = delete;
/**
* \brief Destructor
*/
//! Destructor
~Domain();
/**
* \brief Get the database
*/
//! Get the database
inline std::shared_ptr<const Database> getDatabase() const { return d_db; }
/**
* \brief Get the domain box
*/
//! Get the domain box
inline const Box& getBox() const { return d_box; }
/**
* \brief Get local patch
*/
//! Get local patch
inline const Patch& getLocalPatch() const { return *d_localPatch; }
/**
* \brief Get all patches
*/
//! Get all patches
inline const std::vector<Patch>& getAllPatch() const { return d_patches; }
private:
/**
* \brief initialize from database
*/
void initialize( std::shared_ptr<Database> db );
std::shared_ptr<Database> d_db;
@@ -144,16 +131,15 @@ public: // Public variables (need to create accessors instead)
double porosity;
RankInfoStruct rank_info;
Utilities::MPI Comm; // MPI Communicator for this domain
MPI_Comm Comm; // MPI Communicator for this domain
int BoundaryCondition;
MPI_Group Group; // Group of processors associated with this domain
//**********************************
// 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; }
@@ -186,140 +172,56 @@ 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(); }
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 *sendList_x, *sendList_y, *sendList_z, *sendList_X, *sendList_Y, *sendList_Z;
int *sendList_xy, *sendList_yz, *sendList_xz, *sendList_Xy, *sendList_Yz, *sendList_xZ;
int *sendList_xY, *sendList_yZ, *sendList_Xz, *sendList_XY, *sendList_YZ, *sendList_XZ;
//......................................................................................
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 *recvList_x, *recvList_y, *recvList_z, *recvList_X, *recvList_Y, *recvList_Z;
int *recvList_xy, *recvList_yz, *recvList_xz, *recvList_Xy, *recvList_Yz, *recvList_xZ;
int *recvList_xY, *recvList_yZ, *recvList_Xz, *recvList_XY, *recvList_YZ, *recvList_XZ;
//......................................................................................
// Solid indicator function
std::vector<signed char> id;
signed char *id;
/**
* \brief Read domain IDs from file
*/
void ReadIDs();
/**
* \brief Compute the porosity
*/
void ComputePorosity();
/**
* \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 Decomp(std::string Filename);
void CommunicateMeshHalo(DoubleArray &Mesh);
/**
* \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();
/**
* \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 );
void AggregateLabels(char *FILENAME);
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);
/**
* \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);
void CommHaloIDs();
//......................................................................................
MPI_Request req1[18], req2[18];
MPI_Status stat1[18],stat2[18];
int *sendBuf_x, *sendBuf_y, *sendBuf_z, *sendBuf_X, *sendBuf_Y, *sendBuf_Z;
int *sendBuf_xy, *sendBuf_yz, *sendBuf_xz, *sendBuf_Xy, *sendBuf_Yz, *sendBuf_xZ;
int *sendBuf_xY, *sendBuf_yZ, *sendBuf_Xz, *sendBuf_XY, *sendBuf_YZ, *sendBuf_XZ;
//......................................................................................
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;
int *recvBuf_x, *recvBuf_y, *recvBuf_z, *recvBuf_X, *recvBuf_Y, *recvBuf_Z;
int *recvBuf_xy, *recvBuf_yz, *recvBuf_xz, *recvBuf_Xy, *recvBuf_Yz, *recvBuf_xZ;
int *recvBuf_xY, *recvBuf_yZ, *recvBuf_Xz, *recvBuf_XY, *recvBuf_YZ, *recvBuf_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;
double *sendData_x, *sendData_y, *sendData_z, *sendData_X, *sendData_Y, *sendData_Z;
double *sendData_xy, *sendData_yz, *sendData_xz, *sendData_Xy, *sendData_Yz, *sendData_xZ;
double *sendData_xY, *sendData_yZ, *sendData_Xz, *sendData_XY, *sendData_YZ, *sendData_XZ;
double *recvData_x, *recvData_y, *recvData_z, *recvData_X, *recvData_Y, *recvData_Z;
double *recvData_xy, *recvData_yz, *recvData_xz, *recvData_Xy, *recvData_Yz, *recvData_xZ;
double *recvData_xY, *recvData_yZ, *recvData_Xz, *recvData_XY, *recvData_YZ, *recvData_XZ;
};
@@ -357,10 +259,10 @@ private:
};
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, int Np);
void ReadCheckpoint(char *FILENAME, double *cDen, double *cfq, size_t Np);
void ReadCheckpoint(char *FILENAME, double *cDen, double *cfq, int Np);
void ReadBinaryFile(char *FILENAME, double *Data, size_t N);
void ReadBinaryFile(char *FILENAME, double *Data, int N);
#endif

View File

@@ -1,147 +0,0 @@
#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");
}

View File

@@ -1,6 +1,5 @@
/*
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
@@ -23,7 +22,6 @@
#include <functional>
/*!
* Class FunctionTable is a serial function table class that defines
* a series of operations that can be performed on the Array class.
@@ -42,55 +40,38 @@ public:
/*!
* Perform a reduce operator y = f(x)
* @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
* @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
*/
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 );
static inline TYPE reduce( LAMBDA &op, const Array<TYPE, FUN> &A );
/*!
* Perform a element-wise operation y = f(x)
* @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
* @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
*/
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 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
* @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
*/
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 );
static inline void transform(
LAMBDA &fun, const Array<TYPE, FUN> &x, const Array<TYPE, FUN> &y, Array<TYPE, FUN> &z );
/*!
* Multiply two arrays
@@ -99,8 +80,8 @@ public:
* @param[out] c The output array
*/
template<class TYPE, class FUN>
static void
multiply( const Array<TYPE, FUN> &a, const Array<TYPE, FUN> &b, Array<TYPE, FUN> &c );
static inline 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 )
@@ -108,14 +89,11 @@ 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 );
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 )
@@ -135,84 +113,9 @@ public:
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 );
};

View File

@@ -1,6 +1,5 @@
/*
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
@@ -16,7 +15,6 @@
*/
/*
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
@@ -34,63 +32,66 @@
#define included_FunctionTable_hpp
#include "common/FunctionTable.h"
#include "common/UtilityMacros.h"
#include "common/Utilities.h"
#include <algorithm>
#include <cstring>
#include <limits>
//#include <random>
#include <random>
/********************************************************
* Random number initialization *
********************************************************/
/*template<class TYPE> TYPE genRand();
template<class TYPE, class FUN>
inline void FunctionTable::rand( Array<TYPE, FUN> &x )
template<class TYPE>
static inline typename std::enable_if<std::is_integral<TYPE>::value>::type genRand(
size_t N, TYPE* x )
{
for ( size_t i = 0; i < x.length(); i++ )
x( i ) = genRand<TYPE>();
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, class FUN>
inline void FunctionTable::rand( Array<TYPE, FUN>& x )
{
genRand<TYPE>( x.length(), x.data() );
}
/********************************************************
* Reduction *
********************************************************/
template<class TYPE, class FUN, typename LAMBDA>
inline TYPE FunctionTable::reduce( LAMBDA &op, const Array<TYPE, FUN> &A, const TYPE &initialValue )
inline TYPE FunctionTable::reduce( LAMBDA& op, const Array<TYPE, FUN>& A )
{
if ( A.length() == 0 )
return TYPE();
const TYPE *x = A.data();
TYPE y = initialValue;
for ( size_t i = 0; i < A.length(); i++ )
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 );
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 )
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();
@@ -98,10 +99,8 @@ inline void FunctionTable::transform( LAMBDA &fun, const Array<TYPE, FUN> &x, Ar
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 )
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" );
@@ -116,19 +115,25 @@ inline void FunctionTable::transform( LAMBDA &fun,
* axpy *
********************************************************/
template<class TYPE>
void call_axpy( size_t N, const TYPE alpha, const TYPE *x, TYPE *y );
inline 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 );
inline void call_axpy<float>( size_t, const float, const float*, float* )
{
throw std::logic_error( "LapackWrappers not configured" );
}
template<>
void call_axpy<double>( size_t N, const double alpha, const double *x, double *y );
inline void call_axpy<double>( size_t, const double, const double*, double* )
{
throw std::logic_error( "LapackWrappers not configured" );
}
template<class TYPE>
void call_axpy( size_t N, const TYPE alpha, const TYPE *x, TYPE *y )
inline 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 )
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" );
@@ -140,15 +145,21 @@ void FunctionTable::axpy( const TYPE alpha, const Array<TYPE, FUN> &x, Array<TYP
* Multiply two arrays *
********************************************************/
template<class TYPE>
void call_gemv( size_t M, size_t N, TYPE alpha, TYPE beta, const TYPE *A, const TYPE *x, TYPE *y );
inline 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 );
inline void call_gemv<double>(
size_t, size_t, double, double, const double*, const double*, double* )
{
throw std::logic_error( "LapackWrappers not configured" );
}
template<>
void call_gemv<float>(
size_t M, size_t N, float alpha, float beta, const float *A, const float *x, float *y );
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>
void call_gemv( size_t M, size_t N, TYPE alpha, TYPE beta, const TYPE *A, const TYPE *x, TYPE *y )
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++ )
y[i] = beta * y[i];
@@ -158,29 +169,21 @@ void call_gemv( size_t M, size_t N, TYPE alpha, TYPE beta, const TYPE *A, const
}
}
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 );
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<>
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 );
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<>
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 );
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>
void call_gemm(
size_t M, size_t N, size_t K, TYPE alpha, TYPE beta, const TYPE *A, const TYPE *B, TYPE *C )
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++ )
C[i] = beta * C[i];
@@ -192,17 +195,16 @@ void call_gemm(
}
}
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 )
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 ) {
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() );
} else {
@@ -210,16 +212,17 @@ void FunctionTable::gemm( const TYPE alpha,
}
}
template<class TYPE, class FUN>
void FunctionTable::multiply( const Array<TYPE, FUN> &a,
const Array<TYPE, FUN> &b,
Array<TYPE, FUN> &c )
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 ) {
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() );
@@ -233,8 +236,8 @@ void FunctionTable::multiply( const Array<TYPE, FUN> &a,
* Check if two arrays are equal *
********************************************************/
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 )
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 )
{
bool pass = true;
if ( a.size() != b.size() )
@@ -245,7 +248,7 @@ FunctionTableCompare( const Array<TYPE, FUN> &a, const Array<TYPE, FUN> &b, TYPE
}
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() )
@@ -255,89 +258,10 @@ FunctionTableCompare( const Array<TYPE, FUN> &a, const Array<TYPE, FUN> &b, TYPE
return pass;
}
template<class TYPE, class FUN>
bool FunctionTable::equals( const Array<TYPE, FUN> &a, const Array<TYPE, FUN> &b, TYPE tol )
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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

281
common/MPI_Helpers.cpp Normal file
View File

@@ -0,0 +1,281 @@
/*
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 "common/MPI_Helpers.h"
#include "common/Utilities.h"
/********************************************************
* Return the MPI data type *
********************************************************/
template<> MPI_Datatype getMPItype<char>() {
return MPI_CHAR;
}
template<> MPI_Datatype getMPItype<unsigned char>() {
return MPI_UNSIGNED_CHAR;
}
template<> MPI_Datatype getMPItype<int>() {
return MPI_INT;
}
template<> MPI_Datatype getMPItype<long>() {
return MPI_LONG;
}
template<> MPI_Datatype getMPItype<unsigned long>() {
return MPI_UNSIGNED_LONG;
}
template<> MPI_Datatype getMPItype<long long>() {
return MPI_LONG_LONG;
}
template<> MPI_Datatype getMPItype<float>() {
return MPI_FLOAT;
}
template<> MPI_Datatype getMPItype<double>() {
return MPI_DOUBLE;
}
/********************************************************
* Concrete implimentations for packing/unpacking *
********************************************************/
// unsigned char
template<>
size_t packsize<unsigned char>( const unsigned char& )
{
return sizeof(unsigned char);
}
template<>
void pack<unsigned char>( const unsigned char& rhs, char *buffer )
{
memcpy(buffer,&rhs,sizeof(unsigned char));
}
template<>
void unpack<unsigned char>( unsigned char& data, const char *buffer )
{
memcpy(&data,buffer,sizeof(unsigned char));
}
// char
template<>
size_t packsize<char>( const char& )
{
return sizeof(char);
}
template<>
void pack<char>( const char& rhs, char *buffer )
{
memcpy(buffer,&rhs,sizeof(char));
}
template<>
void unpack<char>( char& data, const char *buffer )
{
memcpy(&data,buffer,sizeof(char));
}
// int
template<>
size_t packsize<int>( const int& )
{
return sizeof(int);
}
template<>
void pack<int>( const int& rhs, char *buffer )
{
memcpy(buffer,&rhs,sizeof(int));
}
template<>
void unpack<int>( int& data, const char *buffer )
{
memcpy(&data,buffer,sizeof(int));
}
// unsigned int
template<>
size_t packsize<unsigned int>( const unsigned int& )
{
return sizeof(unsigned int);
}
template<>
void pack<unsigned int>( const unsigned int& rhs, char *buffer )
{
memcpy(buffer,&rhs,sizeof(int));
}
template<>
void unpack<unsigned int>( unsigned int& data, const char *buffer )
{
memcpy(&data,buffer,sizeof(int));
}
// size_t
template<>
size_t packsize<size_t>( const size_t& )
{
return sizeof(size_t);
}
template<>
void pack<size_t>( const size_t& rhs, char *buffer )
{
memcpy(buffer,&rhs,sizeof(size_t));
}
template<>
void unpack<size_t>( size_t& data, const char *buffer )
{
memcpy(&data,buffer,sizeof(size_t));
}
// std::string
template<>
size_t packsize<std::string>( const std::string& rhs )
{
return rhs.size()+1;
}
template<>
void pack<std::string>( const std::string& rhs, char *buffer )
{
memcpy(buffer,rhs.c_str(),rhs.size()+1);
}
template<>
void unpack<std::string>( std::string& data, const char *buffer )
{
data = std::string(buffer);
}
/********************************************************
* Fake MPI routines *
********************************************************/
#ifndef USE_MPI
int MPI_Init(int*,char***)
{
return 0;
}
int MPI_Init_thread(int*,char***, int required, int *provided )
{
*provided = required;
return 0;
}
int MPI_Finalize()
{
return 0;
}
int MPI_Comm_size( MPI_Comm, int *size )
{
*size = 1;
return 0;
}
int MPI_Comm_rank( MPI_Comm, int *rank )
{
*rank = 0;
return 0;
}
int MPI_Barrier( MPI_Comm )
{
return 0;
}
int MPI_Waitall( int, MPI_Request[], MPI_Status[] )
{
return 0;
}
int MPI_Wait( MPI_Request*, MPI_Status* )
{
return 0;
}
int MPI_Bcast( void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm )
{
return 0;
}
int MPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest, int tag,
MPI_Comm comm)
{
ERROR("Not implimented yet");
return 0;
}
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag,
MPI_Comm comm, MPI_Status *status)
{
ERROR("Not implimented yet");
return 0;
}
int MPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag,
MPI_Comm comm, MPI_Request *request)
{
ERROR("Not implimented yet");
return 0;
}
int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source,
int tag, MPI_Comm comm, MPI_Request *request)
{
ERROR("Not implimented yet");
return 0;
}
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count,
MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
{
ERROR("Not implimented yet");
return 0;
}
int MPI_Allgather(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
void *recvbuf, int recvcount, MPI_Datatype recvtype,
MPI_Comm comm)
{
ERROR("Not implimented yet");
return 0;
}
int MPI_Allgatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
void *recvbuf, const int *recvcounts, const int *displs,
MPI_Datatype recvtype, MPI_Comm comm)
{
ERROR("Not implimented yet");
return 0;
}
int MPI_Sendrecv(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
int dest, int sendtag,
void *recvbuf, int recvcount, MPI_Datatype recvtype,
int source, int recvtag,
MPI_Comm comm, MPI_Status *status)
{
ERROR("Not implimented yet");
return 0;
}
int MPI_Reduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype,
MPI_Op op, int root, MPI_Comm comm)
{
ERROR("Not implimented yet");
return 0;
}
int MPI_Comm_group(MPI_Comm comm, MPI_Group *group)
{
ERROR("Not implimented yet");
return 0;
}
int MPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm *newcomm)
{
ERROR("Not implimented yet");
return 0;
}
int MPI_Comm_dup(MPI_Comm comm, MPI_Comm *newcomm)
{
*newcomm = comm;
return 0;
}
double MPI_Wtime( void )
{
return 0.0;
}
int MPI_Comm_free(MPI_Comm *group)
{
return 0;
}
int MPI_Group_free(MPI_Group *group)
{
return 0;
}
#endif

248
common/MPI_Helpers.h Normal file
View File

@@ -0,0 +1,248 @@
/*
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/>.
*/
// This file contains wrappers for MPI routines and functions to pack/unpack data structures
#ifndef MPI_WRAPPERS_INC
#define MPI_WRAPPERS_INC
#include <string.h>
#include <vector>
#include <set>
#include <map>
#ifdef USE_MPI
// Inlcude MPI
#include "mpi.h"
#else
// Create fake MPI types
typedef int MPI_Comm;
typedef int MPI_Request;
typedef int MPI_Status;
#define MPI_COMM_WORLD 0
#define MPI_COMM_SELF 0
#define MPI_COMM_NULL -1
#define MPI_GROUP_NULL -2
#define MPI_STATUS_IGNORE NULL
enum MPI_Datatype { MPI_LOGICAL, MPI_CHAR, MPI_UNSIGNED_CHAR, MPI_INT,
MPI_UNSIGNED, MPI_LONG, MPI_UNSIGNED_LONG, MPI_LONG_LONG, MPI_FLOAT, MPI_DOUBLE };
enum MPI_Op { MPI_MIN, MPI_MAX, MPI_SUM };
typedef int MPI_Group;
#define MPI_THREAD_SINGLE 0
#define MPI_THREAD_FUNNELED 1
#define MPI_THREAD_SERIALIZED 2
#define MPI_THREAD_MULTIPLE 3
// Fake MPI functions
int MPI_Init(int*,char***);
int MPI_Init_thread( int *argc, char ***argv, int required, int *provided );
int MPI_Finalize();
int MPI_Comm_size( MPI_Comm, int *size );
int MPI_Comm_rank( MPI_Comm, int *rank );
int MPI_Barrier(MPI_Comm);
int MPI_Wait(MPI_Request*,MPI_Status*);
int MPI_Waitall(int,MPI_Request[],MPI_Status[]);
int MPI_Bcast(void*,int,MPI_Datatype,int,MPI_Comm);
int MPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest, int tag,
MPI_Comm comm);
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag,
MPI_Comm comm, MPI_Status *status);
int MPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag,
MPI_Comm comm, MPI_Request *request);
int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source,
int tag, MPI_Comm comm, MPI_Request *request);
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count,
MPI_Datatype datatype, MPI_Op op, MPI_Comm comm);
int MPI_Allgather(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
void *recvbuf, int recvcount, MPI_Datatype recvtype,
MPI_Comm comm);
int MPI_Allgatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
void *recvbuf, const int *recvcounts, const int *displs,
MPI_Datatype recvtype, MPI_Comm comm);
int MPI_Sendrecv(const void *sendbuf, int sendcount, MPI_Datatype sendtype,
int dest, int sendtag,
void *recvbuf, int recvcount, MPI_Datatype recvtype,
int source, int recvtag,
MPI_Comm comm, MPI_Status *status);
int MPI_Reduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype,
MPI_Op op, int root, MPI_Comm comm);
double MPI_Wtime( void );
int MPI_Comm_group(MPI_Comm comm, MPI_Group *group);
int MPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm *newcomm);
int MPI_Comm_free(MPI_Comm *group);
int MPI_Group_free(MPI_Group *group);
int MPI_Comm_dup(MPI_Comm comm, MPI_Comm *newcomm);
#endif
//! Get the size of the MPI_Comm
// Note: this is a thread and interrupt safe function
inline int comm_size( MPI_Comm comm ) {
int size = 1;
MPI_Comm_size( comm, &size );
return size;
}
//! Get the rank of the MPI_Comm
// Note: this is a thread and interrupt safe function
inline int comm_rank( MPI_Comm comm ) {
int rank = 1;
MPI_Comm_rank( comm, &rank );
return rank;
}
//! Get the size of MPI_COMM_WORLD
inline int MPI_WORLD_SIZE( ) {
return comm_size( MPI_COMM_WORLD );
}
//! Get the size of MPI_COMM_WORLD
inline int MPI_WORLD_RANK( ) {
return comm_rank( MPI_COMM_WORLD );
}
//! Return the appropriate MPI datatype for a class
template<class TYPE>
MPI_Datatype getMPItype();
//! Template function to return the buffer size required to pack a class
template<class TYPE>
size_t packsize( const TYPE& rhs );
//! Template function to pack a class to a buffer
template<class TYPE>
void pack( const TYPE& rhs, char *buffer );
//! Template function to unpack a class from a buffer
template<class TYPE>
void unpack( TYPE& data, const char *buffer );
//! Template function to return the buffer size required to pack a std::vector
template<class TYPE>
size_t packsize( const std::vector<TYPE>& rhs );
//! Template function to pack a class to a buffer
template<class TYPE>
void pack( const std::vector<TYPE>& rhs, char *buffer );
//! Template function to pack a class to a buffer
template<class TYPE>
void unpack( std::vector<TYPE>& data, const char *buffer );
//! Template function to return the buffer size required to pack a std::pair
template<class TYPE1, class TYPE2>
size_t packsize( const std::pair<TYPE1,TYPE2>& rhs );
//! Template function to pack a class to a buffer
template<class TYPE1, class TYPE2>
void pack( const std::pair<TYPE1,TYPE2>& rhs, char *buffer );
//! Template function to pack a class to a buffer
template<class TYPE1, class TYPE2>
void unpack( std::pair<TYPE1,TYPE2>& data, const char *buffer );
//! Template function to return the buffer size required to pack a std::map
template<class TYPE1, class TYPE2>
size_t packsize( const std::map<TYPE1,TYPE2>& rhs );
//! Template function to pack a class to a buffer
template<class TYPE1, class TYPE2>
void pack( const std::map<TYPE1,TYPE2>& rhs, char *buffer );
//! Template function to pack a class to a buffer
template<class TYPE1, class TYPE2>
void unpack( std::map<TYPE1,TYPE2>& data, const char *buffer );
//! Template function to return the buffer size required to pack a std::set
template<class TYPE>
size_t packsize( const std::set<TYPE>& rhs );
//! Template function to pack a class to a buffer
template<class TYPE>
void pack( const std::set<TYPE>& rhs, char *buffer );
//! Template function to pack a class to a buffer
template<class TYPE>
void unpack( std::set<TYPE>& data, const char *buffer );
// Helper functions
inline double sumReduce( MPI_Comm comm, double x )
{
double y = 0;
MPI_Allreduce(&x,&y,1,MPI_DOUBLE,MPI_SUM,comm);
return y;
}
inline float sumReduce( MPI_Comm comm, float x )
{
float y = 0;
MPI_Allreduce(&x,&y,1,MPI_FLOAT,MPI_SUM,comm);
return y;
}
inline int sumReduce( MPI_Comm comm, int x )
{
int y = 0;
MPI_Allreduce(&x,&y,1,MPI_INT,MPI_SUM,comm);
return y;
}
inline bool sumReduce( MPI_Comm comm, bool x )
{
int y = sumReduce( comm, x?1:0 );
return y>0;
}
inline std::vector<float> sumReduce( MPI_Comm comm, const std::vector<float>& x )
{
auto y = x;
MPI_Allreduce(x.data(),y.data(),x.size(),MPI_FLOAT,MPI_SUM,comm);
return y;
}
inline std::vector<int> sumReduce( MPI_Comm comm, const std::vector<int>& x )
{
auto y = x;
MPI_Allreduce(x.data(),y.data(),x.size(),MPI_INT,MPI_SUM,comm);
return y;
}
inline double maxReduce( MPI_Comm comm, double x )
{
double y = 0;
MPI_Allreduce(&x,&y,1,MPI_DOUBLE,MPI_MAX,comm);
return y;
}
inline float maxReduce( MPI_Comm comm, float x )
{
float y = 0;
MPI_Allreduce(&x,&y,1,MPI_FLOAT,MPI_MAX,comm);
return y;
}
inline int maxReduce( MPI_Comm comm, int x )
{
int y = 0;
MPI_Allreduce(&x,&y,1,MPI_INT,MPI_MAX,comm);
return y;
}
#endif
#include "common/MPI_Helpers.hpp"

184
common/MPI_Helpers.hpp Normal file
View File

@@ -0,0 +1,184 @@
/*
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/>.
*/
// This file contains wrappers for MPI routines and functions to pack/unpack data structures
#ifndef MPI_WRAPPERS_HPP
#define MPI_WRAPPERS_HPP
#include "common/MPI_Helpers.h"
#include <string.h>
#include <vector>
#include <set>
#include <map>
/********************************************************
* Default instantiations for std::vector *
********************************************************/
template<class TYPE>
size_t packsize( const std::vector<TYPE>& rhs )
{
size_t bytes = sizeof(size_t);
for (size_t i=0; i<rhs.size(); i++)
bytes += packsize(rhs[i]);
return bytes;
}
template<class TYPE>
void pack( const std::vector<TYPE>& rhs, char *buffer )
{
size_t size = rhs.size();
memcpy(buffer,&size,sizeof(size_t));
size_t pos = sizeof(size_t);
for (size_t i=0; i<rhs.size(); i++) {
pack(rhs[i],&buffer[pos]);
pos += packsize(rhs[i]);
}
}
template<class TYPE>
void unpack( std::vector<TYPE>& data, const char *buffer )
{
size_t size;
memcpy(&size,buffer,sizeof(size_t));
data.clear();
data.resize(size);
size_t pos = sizeof(size_t);
for (size_t i=0; i<data.size(); i++) {
unpack(data[i],&buffer[pos]);
pos += packsize(data[i]);
}
}
/********************************************************
* Default instantiations for std::pair *
********************************************************/
template<class TYPE1, class TYPE2>
size_t packsize( const std::pair<TYPE1,TYPE2>& rhs )
{
return packsize(rhs.first)+packsize(rhs.second);
}
template<class TYPE1, class TYPE2>
void pack( const std::pair<TYPE1,TYPE2>& rhs, char *buffer )
{
pack(rhs.first,buffer);
pack(rhs.second,&buffer[packsize(rhs.first)]);
}
template<class TYPE1, class TYPE2>
void unpack( std::pair<TYPE1,TYPE2>& data, const char *buffer )
{
unpack(data.first,buffer);
unpack(data.second,&buffer[packsize(data.first)]);
}
/********************************************************
* Default instantiations for std::map *
********************************************************/
template<class TYPE1, class TYPE2>
size_t packsize( const std::map<TYPE1,TYPE2>& rhs )
{
size_t bytes = sizeof(size_t);
typename std::map<TYPE1,TYPE2>::const_iterator it;
for (it=rhs.begin(); it!=rhs.end(); ++it) {
bytes += packsize(it->first);
bytes += packsize(it->second);
}
return bytes;
}
template<class TYPE1, class TYPE2>
void pack( const std::map<TYPE1,TYPE2>& rhs, char *buffer )
{
size_t N = rhs.size();
pack(N,buffer);
size_t pos = sizeof(size_t);
typename std::map<TYPE1,TYPE2>::const_iterator it;
for (it=rhs.begin(); it!=rhs.end(); ++it) {
pack(it->first,&buffer[pos]); pos+=packsize(it->first);
pack(it->second,&buffer[pos]); pos+=packsize(it->second);
}
}
template<class TYPE1, class TYPE2>
void unpack( std::map<TYPE1,TYPE2>& data, const char *buffer )
{
size_t N = 0;
unpack(N,buffer);
size_t pos = sizeof(size_t);
data.clear();
for (size_t i=0; i<N; i++) {
std::pair<TYPE1,TYPE2> tmp;
unpack(tmp.first,&buffer[pos]); pos+=packsize(tmp.first);
unpack(tmp.second,&buffer[pos]); pos+=packsize(tmp.second);
data.insert(tmp);
}
}
/********************************************************
* Default instantiations for std::set *
********************************************************/
template<class TYPE>
size_t packsize( const std::set<TYPE>& rhs )
{
size_t bytes = sizeof(size_t);
typename std::set<TYPE>::const_iterator it;
for (it=rhs.begin(); it!=rhs.end(); ++it) {
bytes += packsize(*it);
}
return bytes;
}
template<class TYPE>
void pack( const std::set<TYPE>& rhs, char *buffer )
{
size_t N = rhs.size();
pack(N,buffer);
size_t pos = sizeof(size_t);
typename std::set<TYPE>::const_iterator it;
for (it=rhs.begin(); it!=rhs.end(); ++it) {
pack(*it); pos+=packsize(*it);
}
}
template<class TYPE>
void unpack( std::set<TYPE>& data, const char *buffer )
{
size_t N = 0;
unpack(N,buffer);
size_t pos = sizeof(size_t);
data.clear();
for (size_t i=0; i<N; i++) {
TYPE tmp;
unpack(tmp,&buffer[pos]); pos+=packsize(tmp);
data.insert(tmp);
}
}
#endif

Some files were not shown because too many files have changed in this diff Show More