Multiscale Universal Interface  2.0
A Concurrent Framework for Coupling Heterogeneous Solvers
lib_mpi_multidomain.h
Go to the documentation of this file.
1 /*****************************************************************************
2 * Multiscale Universal Interface Code Coupling Library *
3 * *
4 * Copyright (C) 2019 Y. H. Tang, S. Kudo, X. Bian, Z. Li, G. E. Karniadakis *
5 * *
6 * This software is jointly licensed under the Apache License, Version 2.0 *
7 * and the GNU General Public License version 3, you may use it according *
8 * to either. *
9 * *
10 * ** Apache License, version 2.0 ** *
11 * *
12 * Licensed under the Apache License, Version 2.0 (the "License"); *
13 * you may not use this file except in compliance with the License. *
14 * You may obtain a copy of the License at *
15 * *
16 * http://www.apache.org/licenses/LICENSE-2.0 *
17 * *
18 * Unless required by applicable law or agreed to in writing, software *
19 * distributed under the License is distributed on an "AS IS" BASIS, *
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
21 * See the License for the specific language governing permissions and *
22 * limitations under the License. *
23 * *
24 * ** GNU General Public License, version 3 ** *
25 * *
26 * This program is free software: you can redistribute it and/or modify *
27 * it under the terms of the GNU General Public License as published by *
28 * the Free Software Foundation, either version 3 of the License, or *
29 * (at your option) any later version. *
30 * *
31 * This program is distributed in the hope that it will be useful, *
32 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
34 * GNU General Public License for more details. *
35 * *
36 * You should have received a copy of the GNU General Public License *
37 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
38 *****************************************************************************/
39 
48 #ifndef LIB_MPI_MULTIDOMAIN_H_
49 #define LIB_MPI_MULTIDOMAIN_H_
50 
51 #include "lib_uri.h"
52 #include "comm_mpi.h"
53 #include "lib_mpi_helper.h"
54 #include "../uniface.h"
55 
56 namespace mui
57 {
58 
59 using namespace mpi;
60 
61 template<class CONFIG>
62 inline std::vector<std::unique_ptr<uniface<CONFIG>>> create_uniface( std::string domain, std::vector<std::string> interfaces, MPI_Comm world = MPI_COMM_WORLD )
63 {
64  // gather total number of interfaces (edges of the graph)
65  int global_size, global_rank;
66  MPI_Comm_size( world, &global_size );
67  MPI_Comm_rank( world, &global_rank );
68 
69  std::map<int, std::string> map;
70 
71  std::vector<int> my_hashes;
72  for( auto &i : interfaces ) {
73  auto h = std::hash<std::string>()( i );
74  my_hashes.push_back( h );
75  map[h] = i;
76  }
77 
78  // output for debugging
79  if( !CONFIG::QUIET ) {
80  for( auto &e : map ) {
81  std::cout << "MUI [lib_mpi_multidomain]: Rank: " << global_rank << ", \"" << domain
82  << "\" registered interface \"" << e.second
83  << "\" as " << std::hex << e.first << std::dec << std::endl;
84  }
85  }
86  else {
87  if( global_rank == 0 ) {
88  for( auto &e : map ) {
89  std::cout << "MUI [lib_mpi_multidomain]: \"" << domain
90  << "\" registered interface \"" << e.second
91  << "\" as " << std::hex << e.first << std::dec << std::endl;
92  }
93  }
94  }
95  MPI_Barrier( world );
96 
97 
98  int n_unique;
99  std::set<int> unique_ifs;
100  if( global_rank == 0 ) {
101  std::vector<int> nifs = gather( static_cast<int>(interfaces.size()), world );
102  std::vector<int> displs( global_size + 1, 0 );
103  std::partial_sum( nifs.begin(), nifs.end(), displs.begin() + 1 );
104 
105  std::vector<int> all_hashes( displs.back() );
106  MPI_Gatherv( my_hashes.data(), my_hashes.size(), MPI_INT, all_hashes.data(), nifs.data(), displs.data(), MPI_INT, 0, world );
107 
108  for( auto &i : all_hashes ) unique_ifs.insert( i );
109  n_unique = unique_ifs.size();
110  std::cout << "MUI Info [lib_mpi_multidomain]: " << n_unique << " distinct interface(s) found" << std::endl;
111  } else {
112  gather( static_cast<int>(interfaces.size()), world );
113  MPI_Gatherv( my_hashes.data(), my_hashes.size(), MPI_INT, NULL, NULL, NULL, MPI_INT, 0, world );
114  }
115 
116  MPI_Barrier( world );
117  MPI_Bcast( &n_unique, 1, MPI_INT, 0, world );
118  std::vector<int> uniq_hashes( n_unique );
119  if( global_rank == 0 ) uniq_hashes.assign( unique_ifs.begin(), unique_ifs.end() );
120  MPI_Bcast( uniq_hashes.data(), n_unique, MPI_INT, 0, world );
121 
122  std::vector<uniface<CONFIG>*> unifaces;
123  for( auto &i : uniq_hashes ) {
124  MPI_Comm comm_ifs;
125  if( map.find( i ) != map.end() ) {
126  MPI_Comm_split( world, 1, global_rank, &comm_ifs );
127  int comm_rank;
128  MPI_Comm_rank( comm_ifs, &comm_rank );
129  if( comm_rank == 0 ) {
130  std::cout << "MUI [lib_mpi_multidomain]: Setting up interface " << map[i] << " [" << std::hex << i
131  << std::dec << "] (rank ids are local to each interface)" << std::endl;
132  }
133  std::string full_uri( "mpi://" );
134  full_uri = full_uri + domain + "/" + map[i];
135  unifaces.push_back( new uniface<CONFIG>( new comm_mpi_smart( full_uri.c_str(), CONFIG::QUIET, comm_ifs ) ) );
136  } else {
137  MPI_Comm_split( world, 0, global_rank, &comm_ifs );
138  }
139 
140  MPI_Barrier( world );
141  }
142 
143  // Sort return vector into original interface order (order can be mangled due to use of hash values)
144  std::vector<std::unique_ptr<uniface<CONFIG>>> unifaces_sorted;
145 
146  for (const auto &orig_inter : interfaces) {
147  for (auto &uni : unifaces) {
148  if( uni->uri_path().compare(orig_inter) == 0 ) {
149  unifaces_sorted.push_back( std::unique_ptr<uniface<CONFIG>>(uni) );
150  break;
151  }
152  }
153  }
154 
155  return unifaces_sorted;
156 }
157 
158  // Ensure all interfaces in the range of the two iterators have hit sync_all
159  template<typename IteratorT>
160  void sync_all(IteratorT begin, IteratorT end,
161  typename std::decay<decltype(**begin)>::type::time_type t) {
162  for(auto it = begin; it != end; ++it) {
163  auto& unif = *it;
164  // If nothing pushed this just announces the current time
165  unif->commit(t);
166  }
167 
168  for(auto it = begin; it != end; ++it) {
169  auto& unif = *it;
170  // This waits for all the other end of the interface to announce
171  // a time greater than or equal to t
172  unif->barrier(t);
173  }
174  }
175 }
176 
177 #endif /* LIB_MPI_MULTIDOMAIN_H_ */
Definition: comm_mpi_smart.h:62
Definition: uniface.h:80
Class definition of base MPI communicator.
MPI data types used internally by MUI.
Base class to contain and manipulate a unique URI (Uniform Resource Identifier).
e
Definition: dim.h:347
std::vector< T > gather(T t, MPI_Comm comm)
Definition: lib_mpi_helper.h:68
Definition: comm.h:54
void sync_all(IteratorT begin, IteratorT end, typename std::decay< decltype(**begin)>::type::time_type t)
Definition: lib_mpi_multidomain.h:160
std::vector< std::unique_ptr< uniface< CONFIG > > > create_uniface(std::string domain, std::vector< std::string > interfaces, MPI_Comm world=MPI_COMM_WORLD)
Definition: lib_mpi_multidomain.h:62