Compare commits
3 Commits
thomaram-p
...
Greyscale
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0117d25c15 | ||
|
|
dd4a317b13 | ||
|
|
3893fcef30 |
108
.clang-format
108
.clang-format
@@ -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
|
||||
...
|
||||
|
||||
@@ -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
|
||||
...
|
||||
148
.github/workflows/c-cpp.yml
vendored
148
.github/workflows/c-cpp.yml
vendored
@@ -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
|
||||
41
.github/workflows/test_install_openmpi.yml
vendored
41
.github/workflows/test_install_openmpi.yml
vendored
@@ -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
|
||||
|
||||
364
CMakeLists.txt
364
CMakeLists.txt
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
585
IO/HDF5_IO.cpp
585
IO/HDF5_IO.cpp
@@ -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
|
||||
169
IO/HDF5_IO.h
169
IO/HDF5_IO.h
@@ -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
|
||||
348
IO/HDF5_IO.hpp
348
IO/HDF5_IO.hpp
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
719
IO/Mesh.cpp
719
IO/Mesh.cpp
@@ -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
133
IO/Mesh.h
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
131
IO/PIO.cpp
131
IO/PIO.cpp
@@ -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
|
||||
|
||||
|
||||
47
IO/PIO.h
47
IO/PIO.h
@@ -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
|
||||
|
||||
12
IO/PIO.hpp
12
IO/PIO.hpp
@@ -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
|
||||
|
||||
104
IO/PackData.cpp
104
IO/PackData.cpp
@@ -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 );
|
||||
}
|
||||
@@ -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
|
||||
159
IO/PackData.hpp
159
IO/PackData.hpp
@@ -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
|
||||
586
IO/Reader.cpp
586
IO/Reader.cpp
@@ -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 ×tep, 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 ×tep )
|
||||
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 ×tep,
|
||||
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 ×tep,
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
61
IO/Reader.h
61
IO/Reader.h
@@ -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 ×tep, 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 ×tep );
|
||||
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 ×tep,
|
||||
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 ×tep,
|
||||
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
|
||||
|
||||
@@ -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
|
||||
605
IO/Writer.cpp
605
IO/Writer.cpp
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
||||
32
IO/Writer.h
32
IO/Writer.h
@@ -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
|
||||
|
||||
620
IO/Xdmf.cpp
620
IO/Xdmf.cpp
@@ -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 ¢er, ArraySize size,
|
||||
const std::string &location )
|
||||
{
|
||||
fprintf( xmf, "%s<Attribute Name=\"%s\" AttributeType=\"%s\" Center=\"%s\">\n", indent.data(),
|
||||
name.data(), type.data(), center.data() );
|
||||
addDataItem( xmf, indent + " ", size, location );
|
||||
fprintf( xmf, "%s</Attribute>\n", indent.data() );
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Enum functions *
|
||||
****************************************************************/
|
||||
/*template<class TYPE>
|
||||
static Xdmf::DataType getDataType()
|
||||
{
|
||||
if ( std::is_same<TYPE, char>::value )
|
||||
return Xdmf::DataType::Char;
|
||||
else if ( std::is_same<TYPE, int32_t>::value )
|
||||
return Xdmf::DataType::Int32;
|
||||
else if ( std::is_same<TYPE, int64_t>::value )
|
||||
return Xdmf::DataType::Int64;
|
||||
else if ( std::is_same<TYPE, uint32_t>::value )
|
||||
return Xdmf::DataType::Uint32;
|
||||
else if ( std::is_same<TYPE, uint64_t>::value )
|
||||
return Xdmf::DataType::Uint64;
|
||||
else if ( std::is_same<TYPE, float>::value )
|
||||
return Xdmf::DataType::Float;
|
||||
else if ( std::is_same<TYPE, double>::value )
|
||||
return Xdmf::DataType::Double;
|
||||
else
|
||||
ERROR( "Invalid type" );
|
||||
}*/
|
||||
static const char *TopologyTypeNames[] = { "", "Polyvertex", "Polyline", "Polygon", "Triangle",
|
||||
"Quadrilateral", "Tetrahedron", "Pyramid", "Wedge", "Hexahedron", "Edge_3", "Triangle_6",
|
||||
"Quadrilateral_8", "Tetrahedron_10", "Pyramid_13", "Wedge_15", "Hexahedron_20", "Mixed",
|
||||
"CurvilinearMesh2D", "CurvilinearMesh3D", "RectangularMesh2D", "RectangularMesh3D",
|
||||
"UniformMesh2D", "UniformMesh3D" };
|
||||
static const uint8_t TopologyTypeDOFs[] = { 0, 1, 2, 0, 3, 4, 4, 5, 6, 8, 3, 6, 8, 10, 13, 15, 20,
|
||||
0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Create a mesh *
|
||||
****************************************************************/
|
||||
Xdmf::MeshData Xdmf::createPointMesh( const std::string &name, uint8_t NDIM, size_t N,
|
||||
const std::string &x, const std::string &y, const std::string &z )
|
||||
{
|
||||
return createUnstructuredMesh( name, NDIM, TopologyType::Polyvertex, N, "", N, x, y, z );
|
||||
}
|
||||
Xdmf::MeshData Xdmf::createUniformMesh(
|
||||
const std::string &name, const std::vector<double> &range, ArraySize size )
|
||||
{
|
||||
ASSERT( range.size() == 2 * size.ndim() );
|
||||
MeshData data;
|
||||
data.name = name;
|
||||
data.size = size;
|
||||
if ( size.ndim() == 2 )
|
||||
data.type = TopologyType::UniformMesh2D;
|
||||
else if ( size.ndim() == 3 )
|
||||
data.type = TopologyType::UniformMesh3D;
|
||||
else
|
||||
ERROR( "# of dimensions != 2 or 3" );
|
||||
for ( int i = 0; i < 2 * size.ndim(); i++ )
|
||||
data.range[i] = range[i];
|
||||
return data;
|
||||
}
|
||||
Xdmf::MeshData Xdmf::createCurvilinearMesh( const std::string &name, ArraySize size,
|
||||
const std::string &x, const std::string &y, const std::string &z )
|
||||
{
|
||||
MeshData data;
|
||||
data.name = name;
|
||||
if ( size.ndim() == 2 )
|
||||
data.type = TopologyType::CurvilinearMesh2D;
|
||||
else if ( size.ndim() == 3 )
|
||||
data.type = TopologyType::CurvilinearMesh3D;
|
||||
else
|
||||
ERROR( "Invalid size for Curvilinear mesh" );
|
||||
data.size = size;
|
||||
data.x = x;
|
||||
data.y = y;
|
||||
data.z = z;
|
||||
return data;
|
||||
}
|
||||
Xdmf::MeshData Xdmf::createUnstructuredMesh( const std::string &name, uint8_t NDIM,
|
||||
TopologyType type, size_t NumElements, const std::string &dofMap, size_t NumNodes,
|
||||
const std::string &x, const std::string &y, const std::string &z )
|
||||
{
|
||||
ASSERT( type != TopologyType::Null );
|
||||
MeshData data;
|
||||
data.name = name;
|
||||
data.type = type;
|
||||
data.size = { NDIM, NumElements, NumNodes };
|
||||
data.dofMap = dofMap;
|
||||
data.x = x;
|
||||
data.y = y;
|
||||
data.z = z;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Add a variable *
|
||||
****************************************************************/
|
||||
void Xdmf::MeshData::addVariable( const std::string &meshName, const std::string &varName,
|
||||
ArraySize varSize, RankType rank, Center center, const std::string &varData )
|
||||
{
|
||||
VarData var;
|
||||
var.name = varName;
|
||||
var.size = varSize;
|
||||
var.data = varData;
|
||||
var.rankType = rank;
|
||||
var.center = center;
|
||||
vars.push_back( std::move( var ) );
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Add a mesh domain *
|
||||
****************************************************************/
|
||||
void Xdmf::addMesh( const std::string &meshName, const MeshData &domain )
|
||||
{
|
||||
auto &domains = d_meshData[meshName];
|
||||
for ( const auto &domain2 : domains )
|
||||
ASSERT( domain2.name != domain.name );
|
||||
domains.push_back( domain );
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Write a variable *
|
||||
****************************************************************/
|
||||
static void writeVariable( FILE *fid, const Xdmf::VarData &var, const std::string &indent )
|
||||
{
|
||||
// Write the variable name
|
||||
fprintf( fid, "%s<Attribute Name=\"%s\"", indent.data(), var.name.data() );
|
||||
// Write the variable type
|
||||
if ( var.rankType == Xdmf::RankType::Scalar ) {
|
||||
fprintf( fid, " AttributeType=\"Scalar\"" );
|
||||
} else if ( var.rankType == Xdmf::RankType::Vector ) {
|
||||
fprintf( fid, " AttributeType=\"Vector\"" );
|
||||
} else if ( var.rankType == Xdmf::RankType::Tensor ) {
|
||||
fprintf( fid, " AttributeType=\"Tensor\"" );
|
||||
} else if ( var.rankType == Xdmf::RankType::Tensor6 ) {
|
||||
fprintf( fid, " AttributeType=\"Tensor6\"" );
|
||||
} else if ( var.rankType == Xdmf::RankType::Matrix ) {
|
||||
fprintf( fid, " AttributeType=\"Matrix\"" );
|
||||
} else if ( var.rankType == Xdmf::RankType::GlobalID ) {
|
||||
fprintf( fid, " AttributeType=\"GlobalID\"" );
|
||||
} else {
|
||||
ERROR( "Unknown center type" );
|
||||
}
|
||||
// Write the variable centering
|
||||
if ( var.center == Xdmf::Center::Node ) {
|
||||
fprintf( fid, " Center=\"Node\">\n" );
|
||||
} else if ( var.center == Xdmf::Center::Cell ) {
|
||||
fprintf( fid, " Center=\"Cell\">\n" );
|
||||
} else if ( var.center == Xdmf::Center::Grid ) {
|
||||
fprintf( fid, " Center=\"Grid\">\n" );
|
||||
} else if ( var.center == Xdmf::Center::Face ) {
|
||||
fprintf( fid, " Center=\"Face\">\n" );
|
||||
} else if ( var.center == Xdmf::Center::Edge ) {
|
||||
fprintf( fid, " Center=\"Edge\">\n" );
|
||||
} else if ( var.center == Xdmf::Center::Other ) {
|
||||
fprintf( fid, " Center=\"Other\">\n" );
|
||||
} else {
|
||||
ERROR( "Unknown center type" );
|
||||
}
|
||||
// Write the data item
|
||||
addDataItem( fid, indent + " ", var.size, var.data );
|
||||
// Finished
|
||||
fprintf( fid, "%s</Attribute>\n", indent.data() );
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Write the mesh grid *
|
||||
****************************************************************/
|
||||
static void writeMeshGrid( FILE *fid, const Xdmf::MeshData &mesh, const std::string &indent )
|
||||
{
|
||||
const char *s = indent.data();
|
||||
double x0[3] = { mesh.range[0], mesh.range[2], mesh.range[4] };
|
||||
double dx[3] = { ( mesh.range[1] - mesh.range[0] ) / mesh.size[0],
|
||||
( mesh.range[3] - mesh.range[2] ) / mesh.size[1],
|
||||
( mesh.range[5] - mesh.range[4] ) / mesh.size[2] };
|
||||
switch ( mesh.type ) {
|
||||
case Xdmf::TopologyType::UniformMesh2D:
|
||||
// Write a uniform 2d mesh
|
||||
fprintf( fid, "%s<Grid Name=\"%s\" GridType=\"Uniform\">\n", s, mesh.name.data() );
|
||||
fprintf( fid,
|
||||
"%s <Topology TopologyType=\"2DCoRectMesh\" NumberOfElements=\"%lu %lu\"/>\n", s,
|
||||
mesh.size[1] + 1, mesh.size[0] + 1 );
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"ORIGIN_DXDY\">\n", s );
|
||||
fprintf(
|
||||
fid, "%s <DataItem Format=\"XML\" NumberType=\"float\" Dimensions=\"2\">\n", s );
|
||||
fprintf( fid, "%s %0.12e %0.12e\n", s, x0[0], x0[1] );
|
||||
fprintf( fid, "%s </DataItem>\n", s );
|
||||
fprintf(
|
||||
fid, "%s <DataItem Format=\"XML\" NumberType=\"float\" Dimensions=\"2\">\n", s );
|
||||
fprintf( fid, "%s %0.12e %0.12e\n", s, dx[0], dx[1] );
|
||||
fprintf( fid, "%s </DataItem>\n", s );
|
||||
fprintf( fid, "%s </Geometry>\n", s );
|
||||
break;
|
||||
case Xdmf::TopologyType::UniformMesh3D:
|
||||
// Write a uniform 3d mesh
|
||||
fprintf( fid, "%s<Grid Name=\"%s\" GridType=\"Uniform\">\n", s, mesh.name.data() );
|
||||
fprintf( fid,
|
||||
"%s <Topology TopologyType=\"3DCoRectMesh\" NumberOfElements=\"%lu %lu\"/>\n", s,
|
||||
mesh.size[1] + 1, mesh.size[0] + 1 );
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"ORIGIN_DXDYDZ\">\n", s );
|
||||
fprintf(
|
||||
fid, "%s <DataItem Format=\"XML\" NumberType=\"float\" Dimensions=\"3\">\n", s );
|
||||
fprintf( fid, "%s %0.12e %0.12e %0.12e\n", s, x0[0], x0[1], x0[2] );
|
||||
fprintf( fid, "%s </DataItem>\n", s );
|
||||
fprintf(
|
||||
fid, "%s <DataItem Format=\"XML\" NumberType=\"float\" Dimensions=\"3\">\n", s );
|
||||
fprintf( fid, "%s %0.12e %0.12e %0.12e\n", s, dx[0], dx[1], dx[2] );
|
||||
fprintf( fid, "%s </DataItem>\n", s );
|
||||
fprintf( fid, "%s </Geometry>\n", s );
|
||||
break;
|
||||
case Xdmf::TopologyType::CurvilinearMesh2D:
|
||||
// Write a 2D curvillinear mesh
|
||||
fprintf( fid, "%s<Grid Name=\"%s\" GridType=\"Uniform\">\n", s, mesh.name.data() );
|
||||
fprintf( fid, "%s <Topology TopologyType=\"2DSMesh\" NumberOfElements=\"%lu %lu\"/>\n", s,
|
||||
mesh.size[1] + 1, mesh.size[0] + 1 );
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"X_Y\">\n", s );
|
||||
addDataItem( fid, indent + " ", mesh.size + 1, mesh.x );
|
||||
addDataItem( fid, indent + " ", mesh.size + 1, mesh.y );
|
||||
fprintf( fid, "%s </Geometry>\n", s );
|
||||
break;
|
||||
case Xdmf::TopologyType::CurvilinearMesh3D:
|
||||
// Write a 3D curvillinear mesh
|
||||
fprintf( fid, "%s<Grid Name=\"%s\" GridType=\"Uniform\">\n", s, mesh.name.data() );
|
||||
fprintf( fid, "%s <Topology TopologyType=\"3DSMesh\" NumberOfElements=\"%lu %lu %lu\"/>\n",
|
||||
s, mesh.size[2] + 1, mesh.size[1] + 1, mesh.size[0] + 1 );
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"X_Y_Z\">\n", s );
|
||||
addDataItem( fid, indent + " ", mesh.size + 1, mesh.x );
|
||||
addDataItem( fid, indent + " ", mesh.size + 1, mesh.y );
|
||||
addDataItem( fid, indent + " ", mesh.size + 1, mesh.z );
|
||||
fprintf( fid, "%s </Geometry>\n", s );
|
||||
break;
|
||||
case Xdmf::TopologyType::Polyvertex:
|
||||
case Xdmf::TopologyType::Polyline:
|
||||
case Xdmf::TopologyType::Polygon:
|
||||
case Xdmf::TopologyType::Triangle:
|
||||
case Xdmf::TopologyType::Quadrilateral:
|
||||
case Xdmf::TopologyType::Tetrahedron:
|
||||
case Xdmf::TopologyType::Pyramid:
|
||||
case Xdmf::TopologyType::Wedge:
|
||||
case Xdmf::TopologyType::Hexahedron:
|
||||
case Xdmf::TopologyType::Edge_3:
|
||||
case Xdmf::TopologyType::Triangle_6:
|
||||
case Xdmf::TopologyType::Quadrilateral_8:
|
||||
case Xdmf::TopologyType::Tetrahedron_10:
|
||||
case Xdmf::TopologyType::Pyramid_13:
|
||||
case Xdmf::TopologyType::Wedge_15:
|
||||
case Xdmf::TopologyType::Hexahedron_20:
|
||||
// Write an unstructured mesh
|
||||
{
|
||||
int NDIM = mesh.size[0];
|
||||
size_t Nelem = mesh.size[1];
|
||||
size_t Nnode = mesh.size[2];
|
||||
uint8_t Ndofs = TopologyTypeDOFs[static_cast<int>( mesh.type )];
|
||||
auto type = TopologyTypeNames[static_cast<int>( mesh.type )];
|
||||
fprintf( fid, "%s<Grid Name=\"%s\">\n", s, mesh.name.data() );
|
||||
fprintf( fid, "%s <Topology TopologyType=\"%s\"", s, type );
|
||||
fprintf( fid, " NumberOfElements=\"%lu\">\n", Nelem );
|
||||
if ( !mesh.dofMap.empty() )
|
||||
addDataItem( fid, indent + " ", { Ndofs, Nelem }, mesh.dofMap );
|
||||
fprintf( fid, "%s </Topology>\n", s );
|
||||
if ( NDIM == 2 ) {
|
||||
if ( mesh.y.empty() ) {
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"XY\">\n", s );
|
||||
addDataItem( fid, indent + " ", { 2, Nnode }, mesh.x );
|
||||
} else {
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"X_Y\">\n", s );
|
||||
addDataItem( fid, indent + " ", Nnode, mesh.x );
|
||||
addDataItem( fid, indent + " ", Nnode, mesh.y );
|
||||
}
|
||||
} else if ( NDIM == 3 ) {
|
||||
if ( mesh.y.empty() ) {
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"XYZ\">\n", s );
|
||||
addDataItem( fid, indent + " ", { 2, Nnode }, mesh.x );
|
||||
} else {
|
||||
fprintf( fid, "%s <Geometry GeometryType=\"X_Y_Z\">\n", s );
|
||||
addDataItem( fid, indent + " ", Nnode, mesh.x );
|
||||
addDataItem( fid, indent + " ", Nnode, mesh.y );
|
||||
addDataItem( fid, indent + " ", Nnode, mesh.z );
|
||||
}
|
||||
} else {
|
||||
ERROR( "Dimensions other than 2 or 3 are not supported" );
|
||||
}
|
||||
fprintf( fid, "%s </Geometry>\n", s );
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
auto msg = "Invalid mesh type: " + std::to_string( static_cast<int>( mesh.type ) ) + " - " +
|
||||
mesh.name;
|
||||
ERROR( msg );
|
||||
}
|
||||
}
|
||||
// Write the variables
|
||||
for ( const auto &var : mesh.vars )
|
||||
writeVariable( fid, var, indent + " " );
|
||||
fprintf( fid, "%s </Grid>\n", s );
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Write the XDMF xml file *
|
||||
****************************************************************/
|
||||
void Xdmf::write( const std::string &filename ) const
|
||||
{
|
||||
// Create XDMF file
|
||||
auto fid = fopen( filename.data(), "w" );
|
||||
fprintf( fid, "<?xml version=\"1.0\" ?>\n" );
|
||||
fprintf( fid, "<!DOCTYPE Xdmf SYSTEM \"Xdmf.dtd\" []>\n" );
|
||||
fprintf( fid, "<Xdmf Version=\"2.0\">\n" );
|
||||
fprintf( fid, "<Domain>\n" );
|
||||
// Write an empty mesh to enable collections to work properly
|
||||
fprintf( fid, " <Grid Name=\"\" GridType=\"Uniform\"></Grid>\n\n" );
|
||||
// Write each mesh
|
||||
for ( const auto &data : d_meshData ) {
|
||||
auto name = data.first;
|
||||
auto domains = data.second;
|
||||
if ( domains.empty() )
|
||||
continue;
|
||||
if ( domains.size() == 1u && name == domains[0].name ) {
|
||||
writeMeshGrid( fid, domains[0], " " );
|
||||
} else {
|
||||
fprintf( fid, " <Grid Name=\"%s\" GridType=\"Collection\">\n", name.data() );
|
||||
for ( const auto &domain : domains )
|
||||
writeMeshGrid( fid, domain, " " );
|
||||
fprintf( fid, " </Grid>\n\n" );
|
||||
}
|
||||
}
|
||||
fprintf( fid, "</Domain>\n" );
|
||||
fprintf( fid, "</Xdmf>\n" );
|
||||
fclose( fid );
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Pack/Unpack data *
|
||||
****************************************************************/
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_trivially_copyable<T>::value, size_t>::type size( const T & )
|
||||
{
|
||||
return sizeof( T );
|
||||
}
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_trivially_copyable<T>::value, char *>::type pack(
|
||||
char *ptr, const T &x )
|
||||
{
|
||||
memcpy( ptr, &x, sizeof( T ) );
|
||||
return ptr + sizeof( T );
|
||||
}
|
||||
template<class T>
|
||||
typename std::enable_if<std::is_trivially_copyable<T>::value, char *>::type unpack(
|
||||
char *ptr, T &x )
|
||||
{
|
||||
memcpy( &x, ptr, sizeof( T ) );
|
||||
return ptr + sizeof( T );
|
||||
}
|
||||
static size_t size( const std::string &str ) { return sizeof( int ) + str.size(); }
|
||||
static char *pack( char *ptr, const std::string &str )
|
||||
{
|
||||
int N = str.size();
|
||||
memcpy( ptr, &N, sizeof( int ) );
|
||||
ptr += sizeof( int );
|
||||
memcpy( ptr, str.data(), str.size() );
|
||||
ptr += str.size();
|
||||
return ptr;
|
||||
}
|
||||
static char *unpack( char *ptr, std::string &str )
|
||||
{
|
||||
int N = 0;
|
||||
memcpy( &N, ptr, sizeof( int ) );
|
||||
ASSERT( N >= 0 && N < 1000 );
|
||||
ptr += sizeof( int );
|
||||
str = std::string( ptr, N );
|
||||
ptr += N;
|
||||
return ptr;
|
||||
}
|
||||
static size_t size( const Xdmf::VarData &data )
|
||||
{
|
||||
size_t bytes = 0;
|
||||
bytes += size( data.name );
|
||||
bytes += size( data.size );
|
||||
bytes += size( data.rankType );
|
||||
bytes += size( data.center );
|
||||
bytes += size( data.data );
|
||||
return bytes;
|
||||
}
|
||||
static char *pack( char *ptr, const Xdmf::VarData &data )
|
||||
{
|
||||
ptr = pack( ptr, data.name );
|
||||
ptr = pack( ptr, data.size );
|
||||
ptr = pack( ptr, data.rankType );
|
||||
ptr = pack( ptr, data.center );
|
||||
ptr = pack( ptr, data.data );
|
||||
return ptr;
|
||||
}
|
||||
static char *unpack( char *ptr, Xdmf::VarData &data )
|
||||
{
|
||||
int rankType = 0, center = 0;
|
||||
ptr = unpack( ptr, data.name );
|
||||
ptr = unpack( ptr, data.size );
|
||||
ptr = unpack( ptr, rankType );
|
||||
ptr = unpack( ptr, center );
|
||||
ptr = unpack( ptr, data.data );
|
||||
data.rankType = static_cast<Xdmf::RankType>( rankType );
|
||||
data.center = static_cast<Xdmf::Center>( center );
|
||||
return ptr;
|
||||
}
|
||||
static size_t size( const Xdmf::MeshData &data )
|
||||
{
|
||||
int N_vars = data.vars.size();
|
||||
size_t bytes = 0;
|
||||
bytes += size( data.name );
|
||||
bytes += size( data.type );
|
||||
bytes += size( data.size );
|
||||
bytes += size( data.range );
|
||||
bytes += size( data.x );
|
||||
bytes += size( data.y );
|
||||
bytes += size( data.z );
|
||||
bytes += size( N_vars );
|
||||
for ( int i = 0; i < N_vars; i++ )
|
||||
bytes += size( data.vars[i] );
|
||||
return bytes;
|
||||
}
|
||||
static char *pack( char *ptr, const Xdmf::MeshData &data )
|
||||
{
|
||||
int N_vars = data.vars.size();
|
||||
ptr = pack( ptr, data.name );
|
||||
ptr = pack( ptr, data.type );
|
||||
ptr = pack( ptr, data.size );
|
||||
ptr = pack( ptr, data.range );
|
||||
ptr = pack( ptr, data.x );
|
||||
ptr = pack( ptr, data.y );
|
||||
ptr = pack( ptr, data.z );
|
||||
ptr = pack( ptr, N_vars );
|
||||
for ( int i = 0; i < N_vars; i++ )
|
||||
ptr = pack( ptr, data.vars[i] );
|
||||
return ptr;
|
||||
}
|
||||
static char *unpack( char *ptr, Xdmf::MeshData &data )
|
||||
{
|
||||
int N_vars = 0;
|
||||
ptr = unpack( ptr, data.name );
|
||||
ptr = unpack( ptr, data.type );
|
||||
ptr = unpack( ptr, data.size );
|
||||
ptr = unpack( ptr, data.range );
|
||||
ptr = unpack( ptr, data.x );
|
||||
ptr = unpack( ptr, data.y );
|
||||
ptr = unpack( ptr, data.z );
|
||||
ptr = unpack( ptr, N_vars );
|
||||
data.vars.resize( N_vars );
|
||||
for ( int i = 0; i < N_vars; i++ )
|
||||
ptr = unpack( ptr, data.vars[i] );
|
||||
return ptr;
|
||||
}
|
||||
static size_t size( const std::vector<Xdmf::MeshData> &data )
|
||||
{
|
||||
size_t bytes = 0;
|
||||
int N = data.size();
|
||||
bytes += size( N );
|
||||
for ( int i = 0; i < N; i++ )
|
||||
bytes += size( data[i] );
|
||||
return bytes;
|
||||
}
|
||||
static char *pack( char *ptr, const std::vector<Xdmf::MeshData> &data )
|
||||
{
|
||||
int N = data.size();
|
||||
ptr = pack( ptr, N );
|
||||
for ( int i = 0; i < N; i++ )
|
||||
ptr = pack( ptr, data[i] );
|
||||
return ptr;
|
||||
}
|
||||
static char *unpack( char *ptr, std::vector<Xdmf::MeshData> &data )
|
||||
{
|
||||
data.clear();
|
||||
int N = data.size();
|
||||
ptr = unpack( ptr, N );
|
||||
data.resize( N );
|
||||
for ( int i = 0; i < N; i++ )
|
||||
ptr = unpack( ptr, data[i] );
|
||||
return ptr;
|
||||
}
|
||||
static size_t size( const std::map<std::string, std::vector<Xdmf::MeshData>> &data )
|
||||
{
|
||||
size_t bytes = 0;
|
||||
int N_map = data.size();
|
||||
bytes += size( N_map );
|
||||
for ( const auto &tmp : data ) {
|
||||
bytes += size( tmp.first );
|
||||
bytes += size( tmp.second );
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
static char *pack( char *ptr, const std::map<std::string, std::vector<Xdmf::MeshData>> &data )
|
||||
{
|
||||
int N_map = data.size();
|
||||
ptr = pack( ptr, N_map );
|
||||
for ( const auto &tmp : data ) {
|
||||
ptr = pack( ptr, tmp.first );
|
||||
ptr = pack( ptr, tmp.second );
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
static char *unpack( char *ptr, std::map<std::string, std::vector<Xdmf::MeshData>> &data )
|
||||
{
|
||||
data.clear();
|
||||
int N_map = data.size();
|
||||
ptr = unpack( ptr, N_map );
|
||||
for ( int i = 0; i < N_map; i++ ) {
|
||||
std::string name;
|
||||
std::vector<Xdmf::MeshData> data2;
|
||||
ptr = unpack( ptr, name );
|
||||
ptr = unpack( ptr, data2 );
|
||||
data[name] = std::move( data2 );
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* Gather all data to rank 0 *
|
||||
****************************************************************/
|
||||
void Xdmf::gather( const Utilities::MPI &comm )
|
||||
{
|
||||
if ( comm.getRank() == 0 ) {
|
||||
for ( int i = 1; i < comm.getSize(); i++ ) {
|
||||
// Recieve the data
|
||||
size_t N_meshes = 0, N_bytes = 0;
|
||||
comm.recv( &N_meshes, 1, i, 717 );
|
||||
comm.recv( &N_bytes, 1, i, 718 );
|
||||
auto buf = new char[N_bytes];
|
||||
comm.recv( buf, N_bytes, i, 719 );
|
||||
// Unpack the data
|
||||
std::map<std::string, std::vector<MeshData>> data;
|
||||
unpack( buf, data );
|
||||
delete[] buf;
|
||||
// Add the meshes
|
||||
for ( auto tmp : data ) {
|
||||
const auto &name = tmp.first;
|
||||
const auto &domains = tmp.second;
|
||||
if ( domains.size() == 1u && domains[0].name == name ) {
|
||||
// We are dealing with a single mesh
|
||||
ASSERT( d_meshData.find( name ) == d_meshData.end() );
|
||||
d_meshData.insert( tmp );
|
||||
} else {
|
||||
// Add the domains
|
||||
auto &meshes = d_meshData[name];
|
||||
for ( auto domain : domains ) {
|
||||
for ( const auto &tmp : meshes )
|
||||
ASSERT( tmp.name != domain.name );
|
||||
meshes.push_back( domain );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Send the number of meshes
|
||||
size_t N_meshes = d_meshData.size();
|
||||
comm.send( &N_meshes, 1, 0, 717 );
|
||||
// Pack the send data
|
||||
size_t N_bytes = size( d_meshData );
|
||||
comm.send( &N_bytes, 1, 0, 718 );
|
||||
auto buf = new char[N_bytes];
|
||||
pack( buf, d_meshData );
|
||||
// Send the data to rank 0
|
||||
comm.send( buf, N_bytes, 0, 719 );
|
||||
delete[] buf;
|
||||
// Clear the internal data
|
||||
d_meshData.clear();
|
||||
}
|
||||
}
|
||||
131
IO/Xdmf.h
131
IO/Xdmf.h
@@ -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;
|
||||
};
|
||||
388
IO/netcdf.cpp
388
IO/netcdf.cpp
@@ -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
|
||||
|
||||
|
||||
|
||||
83
IO/netcdf.h
83
IO/netcdf.h
@@ -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
|
||||
|
||||
91
IO/silo.cpp
91
IO/silo.cpp
@@ -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
162
IO/silo.h
@@ -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"
|
||||
|
||||
|
||||
379
IO/silo.hpp
379
IO/silo.hpp
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
|
||||
|
||||
#include "StackTrace/StackTrace.h"
|
||||
#include "common/MPI.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "mpi.h"
|
||||
|
||||
|
||||
namespace StackTrace
|
||||
{
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
*/
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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() &&
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
/*!
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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} );
|
||||
|
||||
@@ -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 )
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
362
cmake/FindMPI.cmake
Normal 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)
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 ()
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
143
common/Array.cpp
143
common/Array.cpp
@@ -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
|
||||
|
||||
235
common/Array.h
235
common/Array.h
@@ -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
|
||||
|
||||
605
common/Array.hpp
605
common/Array.hpp
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
1362
common/Domain.cpp
1362
common/Domain.cpp
File diff suppressed because it is too large
Load Diff
270
common/Domain.h
270
common/Domain.h
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
1184
common/MPI.I
1184
common/MPI.I
File diff suppressed because it is too large
Load Diff
3810
common/MPI.cpp
3810
common/MPI.cpp
File diff suppressed because it is too large
Load Diff
1170
common/MPI.h
1170
common/MPI.h
File diff suppressed because it is too large
Load Diff
281
common/MPI_Helpers.cpp
Normal file
281
common/MPI_Helpers.cpp
Normal 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
248
common/MPI_Helpers.h
Normal 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
184
common/MPI_Helpers.hpp
Normal 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
Reference in New Issue
Block a user