Skip to content

Commit 3e0399f

Browse files
authored
Merge pull request #83 from SLongshaw/master
Completed Fortran wrapper and CMake build system
2 parents 47703ba + 8019c4b commit 3e0399f

51 files changed

Lines changed: 33835 additions & 756 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CMakeLists.txt‎

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
cmake_minimum_required(VERSION 3.0)
2-
project(MUI VERSION 1.1.3 DESCRIPTION "Multiscale Universal Interface" LANGUAGES CXX C Fortran)
2+
project(MUI VERSION 1.2 DESCRIPTION "Multiscale Universal Interface" LANGUAGES CXX C Fortran)
33

44
set(CMAKE_CXX_STANDARD 11)
55
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@@ -9,19 +9,19 @@ set(CMAKE_CXX_EXTENSIONS OFF)
99
option(USE_RBF "Include RBF support" OFF)
1010
# Wrapper options
1111
option(C_WRAPPER "Compile C wrapper" OFF)
12-
option(FORTRAN_WRAPPER "Compile Fortran wrapper" OFF) #ToDo: Add Fortran wrapper compilation
12+
option(FORTRAN_WRAPPER "Compile Fortran wrapper" OFF)
1313
option(PYTHON_WRAPPER "Compile Python wrapper" OFF)
1414
option(PIP_INSTALL "Install compiled Python wrapper using pip" OFF)
1515

1616
include(CMakePackageConfigHelpers)
1717
include(CMake/sourcelist.cmake)
1818

1919
find_package(MPI REQUIRED)
20-
if (MPI_FOUND)
20+
if(MPI_FOUND)
2121
include_directories(SYSTEM ${MPI_INCLUDE_PATH})
22-
else (MPI_FOUND)
22+
elseif(NOT MPI_FOUND)
2323
message(SEND_ERROR "MPI not found")
24-
endif (MPI_FOUND)
24+
endif(MPI_FOUND)
2525

2626
if(USE_RBF)
2727
find_package(Eigen3 REQUIRED)
@@ -47,7 +47,9 @@ target_compile_definitions(MUI INTERFACE LIBRARY_HEADER_ONLY)
4747
install(TARGETS MUI EXPORT muiTargets INCLUDES DESTINATION include LIBRARY DESTINATION lib)
4848
install(DIRECTORY ${CMAKE_SOURCE_DIR}/
4949
DESTINATION ${CMAKE_INSTALL_PREFIX}/MUI-${PROJECT_VERSION}/include
50-
FILES_MATCHING PATTERN "*.h"
50+
FILES_MATCHING
51+
PATTERN "*.h"
52+
PATTERN "*.f90"
5153
PATTERN ".git" EXCLUDE
5254
PATTERN "build" EXCLUDE
5355
PATTERN "wrappers/Python" EXCLUDE
@@ -83,6 +85,29 @@ if(C_WRAPPER)
8385
endif(C_WRAPPER)
8486

8587
if(FORTRAN_WRAPPER)
88+
message("-- MUI Fortran wrapper: Selected")
89+
90+
add_library(MUI_Fortran_wrapper SHARED
91+
./wrappers/Fortran/mui_f_wrapper_general.cpp
92+
./wrappers/Fortran/mui_f_wrapper_1d.cpp
93+
./wrappers/Fortran/mui_f_wrapper_2d.cpp
94+
./wrappers/Fortran/mui_f_wrapper_3d.cpp)
95+
set_target_properties(MUI_Fortran_wrapper PROPERTIES PUBLIC_HEADER ./wrappers/Fortran/mui_f_wrapper_general.f90)
96+
set_target_properties(MUI_Fortran_wrapper PROPERTIES PUBLIC_HEADER ./wrappers/Fortran/mui_f_wrapper_1d.f90)
97+
set_target_properties(MUI_Fortran_wrapper PROPERTIES PUBLIC_HEADER ./wrappers/Fortran/mui_f_wrapper_2d.f90)
98+
set_target_properties(MUI_Fortran_wrapper PROPERTIES PUBLIC_HEADER ./wrappers/Fortran/mui_f_wrapper_3d.f90)
99+
set_target_properties(MUI_Fortran_wrapper PROPERTIES PUBLIC_HEADER ./wrappers/Fortran/config_f_wrapper.h)
100+
target_include_directories(MUI_Fortran_wrapper PRIVATE .)
101+
102+
if(USE_RBF)
103+
target_link_libraries(MUI_Fortran_wrapper Eigen3::Eigen ${MPI_CXX_LIBRARIES})
104+
else()
105+
target_link_libraries(MUI_Fortran_wrapper ${MPI_CXX_LIBRARIES})
106+
endif(USE_RBF)
107+
108+
install(TARGETS MUI_Fortran_wrapper
109+
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/MUI-${PROJECT_VERSION}/lib/
110+
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_PREFIX}/MUI-${PROJECT_VERSION}/include/wrappers/Fortran/)
86111
endif(FORTRAN_WRAPPER)
87112

88113
if(PYTHON_WRAPPER)
@@ -97,10 +122,10 @@ if(PYTHON_WRAPPER)
97122
endif()
98123

99124
if(USE_RBF)
100-
add_custom_target(mui4py ALL COMMAND $(MAKE) COMPILER=${COMPILER_TYPE} package USE_RBF=1 INC_EIGEN="${EIGEN3_INCLUDE_DIR}"
125+
add_custom_target(mui4py ALL COMMAND $(MAKE) COMPILER=${COMPILER_TYPE} CXX=${MPI_CXX_COMPILER} USE_RBF=1 INC_EIGEN="${EIGEN3_INCLUDE_DIR}" package
101126
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wrappers/Python)
102127
else()
103-
add_custom_target(mui4py ALL COMMAND $(MAKE) COMPILER=${COMPILER_TYPE} package
128+
add_custom_target(mui4py ALL COMMAND $(MAKE) COMPILER=${COMPILER_TYPE} CXX=${MPI_CXX_COMPILER} package
104129
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wrappers/Python)
105130
endif(USE_RBF)
106131

@@ -113,6 +138,8 @@ if(PYTHON_WRAPPER)
113138
${CMAKE_CURRENT_SOURCE_DIR}/wrappers/Python/mui4py/mui4py_mod.so)
114139

115140
if(PIP_INSTALL)
141+
message("-- MUI Python wrapper installation: Selected")
142+
116143
add_custom_target(mui4py_pip ALL COMMAND pip3 install dist/mui4py*.tar.gz
117144
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wrappers/Python)
118145
add_dependencies(mui4py_pip mui4py)

‎README.md‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
# MUI - Multiscale Universal Interface
2-
Concurrently coupled numerical simulations using heterogeneous solvers are powerful tools for modeling multiscale phenomena. However, major modifications to existing codes are often required to enable such simulations, posing significant difficulties in practice. Here we present Multiscale Universal Interface (MUI), which is capable of facilitating the coupling effort for a wide range of multiscale simulations. The library adopts a header-only form with minimal external dependency and hence can be easily dropped into existing codes. A data samplerconcept is introduced, combined with a hybrid dynamic/static typing mechanism, to create an easily customizable framework for solver-independent data interpretation.
2+
Concurrently coupled numerical simulations using heterogeneous solvers are powerful tools for modeling both multiscale and multiphysics phenomena. However, major modifications to existing codes are often required to enable such simulations, posing significant difficulties in practice. Here we present the Multiscale Universal Interface (MUI), which is capable of facilitating the coupling effort for a wide range of simulation types.
3+
4+
The library adopts a header-only form with minimal external dependency and hence can be easily dropped into existing codes. A data sampler concept is introduced, combined with a hybrid dynamic/static typing mechanism, to create an easily customizable framework for solver-independent data interpretation.
35

46
The library integrates MPI MPMD support and an asynchronous communication protocol to handle inter-solver information exchange irrespective of the solvers’ own MPI awareness. Template metaprogramming is heavily employed to simultaneously improve runtime performance and code flexibility.
57

6-
In the publication referenced below, the library is validated by solving three different multiscale problems, which also serve to demonstrate the flexibility of the framework in handling heterogeneous models and solvers associated with multiphysics problems. In the first example, a Couette flow was simulated using two concurrently coupled Smoothed Particle Hydrodynamics (SPH) simulations of different spatial resolutions. In the second example, we coupled the deterministic SPH method with the stochastic Dissipative Particle Dynamics (DPD) method to study the effect of surface grafting on the hydrodynamics properties on the surface. In the third example, we consider conjugate heat transfer between a solid domain and a fluid domain by coupling the particle-based energy-conserving DPD (eDPD) method with the Finite Element Method (FEM).
8+
In the publication referenced below, the library is validated by solving three different multiscale type problems, which also serve to demonstrate the flexibility of the framework in handling heterogeneous models and solvers associated with multiphysics problems. In the first example, a Couette flow was simulated using two concurrently coupled Smoothed Particle Hydrodynamics (SPH) simulations of different spatial resolutions. In the second example, we coupled the deterministic SPH method with the stochastic Dissipative Particle Dynamics (DPD) method to study the effect of surface grafting on the hydrodynamics properties on the surface. In the third example, we consider conjugate heat transfer between a solid domain and a fluid domain by coupling the particle-based energy-conserving DPD (eDPD) method with the Finite Element Method (FEM).
79

810
## Licensing
911

@@ -29,6 +31,8 @@ As a header-only library using MUI in your own source code is straight forward,
2931

3032
<sup>1</sup> Only true if the Radial Basis Function (RBF) spatial interpolation scheme is included at compile-time.
3133

34+
<b>Note:</b> if you are using MUI with a toolchain other than GNU, you may need to manually specify the endianness you wish the library to assume, this is done using a number of compile-time parameters: -DMUI_IGNORE_ENDIAN (never reorders); -DMUI_INT_LITTLE_ENDIAN combined with -DMUI_FLOAT_LITTLE_ENDIAN (assumed little endian reordering); -DMUI_INT_BIG_ENDIAN combined with -DMUI_FLOAT_BIG_ENDIAN (assumes big endian reordering). It is recommended you start by allowing the library to try and determine your endianness options, however if you receive many compilation erorrs relating to the stream parts of the library then you will need to manually define your choices.
35+
3236
## Publication
3337

3438
**Tang** Y.-H., **Kudo**, S., **Bian**, X., **Li**, Z., & **Karniadakis**, G. E. Multiscale Universal Interface: A Concurrent Framework for Coupling Heterogeneous Solvers, *Journal of Computational Physics*, **2015**, 297.15, 13-31.

‎bin.h‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ struct bin_t {
250250
}
251251

252252
size_t zero_count=0;
253-
REAL vol = abs(max[0]-min[0]);
253+
REAL vol = std::abs(max[0]-min[0]);
254254
if(almost_equal(vol, static_cast<REAL>(0))) { // check if first dimension is zero size, if so set to 1
255255
vol = 1.0;
256256
zero_count++;
@@ -307,7 +307,6 @@ struct bin_t {
307307
if( initialize_query_(bx,lda,lh) ) return map;
308308
map.reserve(lda[D-1]*12);
309309
set_map_<D-1>::apply( 0, lda, lh, displs, map );
310-
map.shrink_to_fit();
311310
return map;
312311
}
313312

@@ -322,8 +321,7 @@ struct bin_t {
322321
REAL domain_size() {
323322
REAL dim_size = norm(max-min);
324323
// Special case if domain only contains a single point
325-
if(almost_equal(dim_size, static_cast<REAL>(0)))
326-
dim_size = 1.0;
324+
if(dim_size == 0) dim_size = 1.0;
327325
return dim_size;
328326
}
329327

‎comm_mpi_smart.h‎

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -65,30 +65,36 @@ class comm_mpi_smart : public comm_mpi {
6565
public:
6666
comm_mpi_smart( const char URI[], MPI_Comm world = MPI_COMM_WORLD ) : comm_mpi(URI, world) {}
6767
virtual ~comm_mpi_smart() {
68-
// Call MPI_Test in blocking loop on any remaining MPI_Isend messages in buffer and if complete, pop before destruction
68+
// Call blocking MPI_Test on any remaining MPI_Isend messages in buffer and if complete, pop before destruction or warn
6969
test_completion_blocking();
7070
}
7171

7272
private:
7373
void send_impl_( message msg, const std::vector<bool> &is_sending ) {
74-
// Call non-blocking MPI_Test on MPI_Isend messages in buffer and if complete, pop
74+
// Call non-blocking MPI_Test on outstanding MPI_Isend messages in buffer and if complete, pop
7575
test_completion();
7676
auto bytes = std::make_shared<std::vector<char> >(msg.detach());
77-
for( int i = 0 ; i < remote_size_ ; i++ ){
78-
if( is_sending[i] ){
79-
if(bytes->size() > INT_MAX){
80-
std::cerr << "MUI Error [comm_mpi_smart.h]: Trying to send more data than is possible with MPI_Isend." << std::endl
81-
<< "This is likely because there is too much data per MPI rank." << std::endl
82-
<< "The program will now abort. Try increasing the number of MPI ranks." << std::endl;
83-
std::abort();
84-
}
77+
78+
if(bytes->size() > INT_MAX){
79+
std::cerr << "MUI Error [comm_mpi_smart.h]: Trying to send more data than is possible with MPI_Isend." << std::endl
80+
<< "This is likely because there is too much data per MPI rank." << std::endl
81+
<< "The program will now abort. Try increasing the number of MPI ranks." << std::endl;
82+
std::abort();
83+
}
84+
85+
int test;
86+
87+
for( int i = 0; i < remote_size_; i++ ) {
88+
if( is_sending[i] ) {
8589
send_buf.emplace_back(MPI_Request(), bytes);
86-
MPI_Isend(bytes->data(), bytes->size(), MPI_BYTE, i, 0,
90+
MPI_Isend(bytes->data(), bytes->size(), MPI_BYTE, i, 0,
8791
domain_remote_, &(send_buf.back().first));
92+
93+
// Add immediate MPI_Test to ensure buffer cleared as quickly as possible
94+
MPI_Test(&(send_buf.back().first),&test,MPI_STATUS_IGNORE);
95+
if( test ) send_buf.pop_back();
8896
}
8997
}
90-
// Call non-blocking MPI_Test on MPI_Isend messages in buffer and if complete, pop
91-
test_completion();
9298
}
9399

94100
message recv_impl_() {
@@ -118,21 +124,11 @@ class comm_mpi_smart : public comm_mpi {
118124
/** \brief Time-limited blocking check for complete MPI_Isend calls
119125
*/
120126
void test_completion_blocking() {
121-
int timeout = 0;
122-
auto start = std::chrono::system_clock::now();
123-
while (send_buf.size() > 0) {
127+
while (send_buf.size() > 0) {
124128
for( auto itr=send_buf.begin(), end=send_buf.end(); itr != end; ){
125-
int test = false;
126-
MPI_Test(&(itr->first),&test,MPI_STATUS_IGNORE);
127-
if( test ) itr = send_buf.erase(itr);
128-
else ++itr;
129-
}
130-
if( (std::chrono::system_clock::now() - start) > std::chrono::seconds(5) ) {
131-
timeout++;
132-
int time_left = 60 - (timeout*5);
133-
if( time_left == 0) break;
134-
std::cout << "MUI Warning [comm_mpi_smart.h]: MPI_Isend calls spent over 5 seconds completing, all operations will timeout in "
135-
<< time_left << "s" << std::endl;
129+
//int test = false;
130+
MPI_Wait(&(itr->first), MPI_STATUS_IGNORE);
131+
itr = send_buf.erase(itr);
136132
}
137133
}
138134
}

‎doc/.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
documentation/

‎doc/Doxyfile‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ PROJECT_NAME = "Multiscale Universal Interface"
3838
# could be handy for archiving the generated documentation or if some version
3939
# control system is used.
4040

41-
PROJECT_NUMBER =
41+
PROJECT_NUMBER = 1.2
4242

4343
# Using the PROJECT_BRIEF tag one can provide an optional one line description
4444
# for a project that appears at the top of each page and should give viewer a
@@ -150,7 +150,7 @@ INLINE_INHERITED_MEMB = NO
150150
# shortest path that makes the file name unique will be used
151151
# The default value is: YES.
152152

153-
FULL_PATH_NAMES = YES
153+
FULL_PATH_NAMES = NO
154154

155155
# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
156156
# Stripping is only done if one of the specified strings matches the left-hand
@@ -790,7 +790,7 @@ WARN_LOGFILE =
790790
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
791791
# Note: If this tag is empty the current directory is searched.
792792

793-
INPUT =
793+
INPUT = ../
794794

795795
# This tag can be used to specify the character encoding of the source files
796796
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -873,8 +873,10 @@ RECURSIVE = YES
873873
# Note that relative paths are relative to the directory from which doxygen is
874874
# run.
875875

876-
EXCLUDE = /wrappers \
877-
/documentation
876+
EXCLUDE = ../build \
877+
../doc \
878+
../CMake \
879+
../wrappers
878880

879881
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
880882
# directories that are symbolic links (a Unix file system feature) are excluded

‎doc/resources/MUI_logo.png‎

12.4 KB
Loading

‎mui.h‎

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -189,21 +189,6 @@ SPECIALIZE(2fx,float,int64_t,2);
189189
SPECIALIZE(3fx,float,int64_t,3);
190190
#undef SPECIALIZE
191191
#endif
192-
// sample configuration class
193-
// modify to adapt to specific simulation scenario
194-
/******************************************************************************
195-
struct config_custom {
196-
static const int D = 3;
197-
using REAL = double;
198-
using INT = int;
199-
using point_type = point<REAL,D>;
200-
using time_type = REAL;
201-
static const bool DEBUG = false;
202-
using data_types = type_list<int,double,float>;
203-
using EXCEPTION = exception_segv;
204-
static const bool FIXEDPOINTS = false;
205-
};
206-
******************************************************************************/
207192

208193
// usage: SPECIALIZE( _your_custom_suffix, your_custom_config_structure )
209194
// uniface_your_custom_suffix interface; ...

‎spatial_samplers/sampler_exact.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class sampler_exact {
7575

7676
template<template<typename,typename> class CONTAINER>
7777
inline OTYPE filter( point_type focus, const CONTAINER<ITYPE,CONFIG> &data_points ) const {
78-
for( size_t i = 0 ; i < data_points.size() ; i++ ) {
78+
for( size_t i = 0 ; i < data_points.size() ; i++ ) {
7979
if ( norm( focus - data_points[i].first ) < point_tolerance ) {
8080
return data_points[i].second;
8181
}

‎spatial_samplers/sampler_gauss.h‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,14 @@ class sampler_gauss {
6767

6868
template<template<typename,typename> class CONTAINER>
6969
inline OTYPE filter( point_type focus, const CONTAINER<ITYPE,CONFIG> &data_points ) const {
70-
REAL wsum = 0;
70+
REAL exp_val = -0.5/h;
71+
REAL r2 = r*r;
72+
REAL wsum = 0;
7173
OTYPE vsum = 0;
7274
for( size_t i = 0 ; i < data_points.size() ; i++ ) {
73-
auto d = normsq( focus - data_points[i].first );
74-
if ( d < r*r ) {
75-
REAL w = nh * std::exp( (REAL(-0.5)/h) * d );
75+
REAL d = normsq( focus - data_points[i].first );
76+
if ( d < r2 ) {
77+
REAL w = nh * std::exp( exp_val * d );
7678
vsum += data_points[i].second * w;
7779
wsum += w;
7880
}

0 commit comments

Comments
 (0)