1
/* Copyright (C) 2006 Imperial College London and others.
3
Please see the AUTHORS file in the main source directory for a full list
7
Applied Modelling and Computation Group
8
Department of Earth Science and Engineering
9
Imperial College London
11
g.gorman@imperial.ac.uk
13
This library is free software; you can redistribute it and/or
14
modify it under the terms of the GNU Lesser General Public
15
License as published by the Free Software Foundation; either
16
version 2.1 of the License.
18
This library is distributed in the hope that it will be useful,
19
but WITHOUT ANY WARRANTY; without even the implied warranty of
20
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21
Lesser General Public License for more details.
23
You should have received a copy of the GNU Lesser General Public
24
License along with this library; if not, write to the Free Software
25
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
43
//#define CREATE_VELOCITY_HALO2 1
45
void Mesh::formHalo2(){
47
unsigned len45 = element_list.size();
48
for(unsigned i=0; i<len45; i++)
49
for(unsigned j=0; j<len45; j++)
51
assert(element_list[i] != element_list[j]);
54
// This is what we are looking for.
55
vector< deque<unsigned> > halo2Elements(NProcs);
56
set<unsigned> dangerElements;
58
// Wizz through all elements.
60
for(deque<Element>::const_iterator elm = element_list.begin(); elm != element_list.end(); ++elm, ++pos){
62
const vector<unn_t>& nodes = (*elm).get_enlist();
63
vector<bool> halo1(NProcs, false);
64
bool interesting=false;
66
for(int p=0; p<NProcs; p++){
67
if(p==MyRank) continue;
69
// Record if elm has a halo node with p.
70
for( vector<unn_t>::const_iterator jt = nodes.begin(); jt!=nodes.end(); ++jt){
71
halo1[p] = (halo_nodes[p].find(*jt)!= halo_nodes[p].end());
79
// Record if elm shares a node with p, but is not itself a halo1 element for p.
80
for(vector<unn_t>::const_iterator jt=nodes.begin(); jt!=nodes.end(); ++jt){
81
if(shared_nodes[p].find(*jt)!=shared_nodes[p].end()){
83
halo2Elements[p].push_back(pos);
92
// A halo2 element may be multiably sent if it contains halo1
93
// nodes for any domain.
94
for(unsigned p=0;p<(unsigned)NProcs;p++){
96
dangerElements.insert( pos );
102
} // Have halo2 elements and a set of dangerElements.
106
// Identify all the nodes that must be sent.
108
vector< set<unsigned> > sendhalo2nodes(NProcs);
109
vector< set<unsigned> > sendhalo2pnodes(NProcs);
110
for(unsigned p=0; p<(unsigned)NProcs; p++){
112
for(deque<unsigned>::const_iterator elm=halo2Elements[p].begin(); elm!=halo2Elements[p].end(); ++elm){
113
// It's enough to just check the volume elements
114
if(element_list[*elm].get_flags() & ELM_SURFACE)
118
const vector<unn_t>& nodes = element_list[*elm].get_enlist();
119
for(vector<unn_t>::const_iterator nod=nodes.begin(); nod!=nodes.end(); ++nod){
120
sendhalo2nodes[p].insert( *nod );
124
const vector<unn_t>& nodes = element_list[*elm].get_MFenlist();
125
for(vector<unn_t>::const_iterator nod=nodes.begin(); nod!=nodes.end(); ++nod){
126
sendhalo2pnodes[p].insert( *nod );
131
{// Remove nodes that p should already know through halo1.
133
for(set<unsigned>::const_iterator it=sendhalo2nodes[p].begin(); it != sendhalo2nodes[p].end(); ++it){
134
if(shared_nodes[p].find( *it ) != shared_nodes[p].end()){
138
for(set<unsigned>::const_iterator it=toDel.begin(); it != toDel.end(); ++it){
139
sendhalo2nodes[p].erase( *it );
143
{// Remove pressure nodes that p should already know through halo1.
145
for(set<unsigned>::const_iterator it=sendhalo2pnodes[p].begin(); it != sendhalo2pnodes[p].end(); ++it){
146
if( shared_pnodes[p].find( *it ) != shared_pnodes[p].end() ){
150
for(set<unsigned>::const_iterator it=toDel.begin(); it != toDel.end(); ++it){
151
sendhalo2pnodes[p].erase( *it );
157
// At this point we have identified all the information which we
158
// want to communicate:
159
// vector< deque<unsigned> > elems2send( NProcs );
160
// vector< set<unsigned> > nodes2send( NProcs );
163
// Make the send-packs
164
vector< vector<char> > SendRecvBuffer(NProcs);
166
{ // Allocate space for buffers
167
unsigned max_node_size = max_nodepack_size();
168
unsigned max_pnode_size = max_pressurepack_size();
169
unsigned max_element_size = max_elementpack_size();
170
unsigned space_for_unsigned = MPI::UNSIGNED.Pack_size(1, MPI::COMM_WORLD);
172
for(int i=0; i<NProcs; i++){
173
unsigned nbytes = space_for_unsigned +
174
space_for_unsigned*halo2Elements[i].size() +
176
max_element_size*halo2Elements[i].size() +
178
max_node_size*sendhalo2nodes[i].size() +
180
max_pnode_size*sendhalo2pnodes[i].size();
182
SendRecvBuffer[i].resize( (unsigned)(1.1*nbytes) );
186
vector<int> offsets(NProcs, 0); // int because of mpi calls
189
for(int i=0; i<NProcs; i++){
190
int len = SendRecvBuffer[i].size();
192
if( (i == MyRank)||(len == 0) )
195
char *buff = &(SendRecvBuffer[i][0]);
198
unsigned cnt = halo2Elements[i].size();
199
MPI::UNSIGNED.Pack(&cnt, 1, buff, len, offsets[i], MPI::COMM_WORLD);
201
ECHO("Packing "<<cnt<<" halo2 elements for "<<i<<".");
202
for(unsigned j=0; j<cnt; j++){
206
if( dangerElements.find( halo2Elements[i][j] ) != dangerElements.end() )
208
MPI::UNSIGNED.Pack(&danger, 1, buff, len, offsets[i], MPI::COMM_WORLD);
211
element_list[ halo2Elements[i][j] ].pack(buff, len, offsets[i]);
214
cnt = sendhalo2nodes[i].size();
215
MPI::UNSIGNED.Pack(&cnt, 1, buff, len, offsets[i], MPI::COMM_WORLD);
217
ECHO("Packing "<<cnt<<" halo2 nodes for "<<i<<".");
218
for(set<unsigned>::const_iterator it=sendhalo2nodes[i].begin(); it!=sendhalo2nodes[i].end(); ++it){
219
const Node& node = node_list.unn( *it );
220
node.pack(buff, len, offsets[i]);
224
cnt = sendhalo2pnodes[i].size();
225
MPI::UNSIGNED.Pack(&cnt, 1, buff, len, offsets[i], MPI::COMM_WORLD);
226
ECHO("Packing "<<cnt<<" halo2 pressure nodes for "<<i<<".");
228
for(set<unsigned>::const_iterator it=sendhalo2pnodes[i].begin(); it!=sendhalo2pnodes[i].end(); ++it){
229
const PressureNode& node = MFnode_list.unn( *it );
230
node.pack(buff, len, offsets[i]);
233
assert(offsets[i] <= (int)SendRecvBuffer[i].size());
237
dangerElements.clear();
238
halo2Elements.clear();
239
sendhalo2nodes.clear();
240
sendhalo2pnodes.clear();
242
// Send/recieve everything.
243
allSendRecv(SendRecvBuffer);
246
ECHO("Starting unpacking.");
248
for(int p=0; p<NProcs; p++){
252
set<Element> DangerElements;
253
set<unsigned> ReceivedNodes;
254
set<unsigned> ReceivedPressureNodes;
255
vector< set<unsigned> > extraHalo(NProcs);
258
assert(SendRecvBuffer.size() == (unsigned)NProcs);
261
CHECK( element_list.size() );
262
do_element_headcount();
263
CHECK( num_elements("total") );
264
CHECK( num_elements("volume") );
265
CHECK( num_elements("surface") );
268
for(int p=0; p<NProcs; p++){
269
int nbytes = SendRecvBuffer[p].size();
270
if( (p == MyRank)||(nbytes == 0) )
273
char *buffer = &(SendRecvBuffer[p][0]);
276
MPI::UNSIGNED.Unpack(buffer, nbytes, &cnt, 1, offsets[p], MPI::COMM_WORLD);
278
ECHO("Unpacking "<<cnt<<" elements from "<<p<<".");
280
for(unsigned j=0; j<cnt; j++){
283
ECHO("Unpacking "<<j<<"...");
285
// Unpack danger flag.
287
MPI::UNSIGNED.Unpack(buffer, nbytes, &danger, 1, offsets[p], MPI::COMM_WORLD);
291
element.unpack(buffer, nbytes, offsets[p]);
295
ECHO("Danger element...taking evasive action.");
296
DangerElements.insert( element );
298
element_list.push_back(element);
301
} // finished unpacking elements.
305
MPI::UNSIGNED.Unpack(buffer, nbytes, &cnt, 1, offsets[p], MPI::COMM_WORLD);
306
ECHO("Unpacking "<<cnt<<" nodes from "<<p<<".");
308
for(unsigned j=0; j<cnt; j++){
310
node.unpack(buffer, nbytes, offsets[p]);
311
unsigned unn = node.get_unn();
312
unsigned owner = node.get_owner();
314
if(halo_nodes[owner].find( unn ) == halo_nodes[owner].end())
315
if(ReceivedNodes.find( unn ) == ReceivedNodes.end()){
316
assert( !node_list.contains_unn(unn) );
317
node_list.push_back( node );
318
ReceivedNodes.insert( unn );
322
} // finished unpacking nodes
326
MPI::UNSIGNED.Unpack(buffer, nbytes, &cnt, 1, offsets[p], MPI::COMM_WORLD);
327
ECHO("Unpacking "<<cnt<<" pressure nodes from "<<p<<".");
329
for(unsigned j=0; j<cnt; j++){
331
node.unpack(buffer, nbytes, offsets[p]);
332
unsigned unn = node.get_unn();
333
unsigned owner = node.get_owner();
335
if(halo_pnodes[owner].find( unn ) == halo_pnodes[owner].end())
336
if(ReceivedPressureNodes.find( node.get_unn() ) == ReceivedPressureNodes.end()){
337
assert( !MFnode_list.contains_unn(unn) );
338
MFnode_list.push_back( node );
339
ReceivedPressureNodes.insert( node.get_unn() );
341
// This next line is tricky as "node.get_owner()" is used
342
// rather than p. This is because the owner of this node is
343
// not necessarly the same as the processor that sent
345
extraHalo[owner].insert( node.get_unn() );
349
} // finished unpacking pressure nodes
354
// Finally, add in the danger elements
356
if( !DangerElements.empty() ){
357
ECHO("Add in danger elements.");
359
for(set<Element>::const_iterator it=DangerElements.begin(); it!=DangerElements.end(); ++it)
360
element_list.push_back( *it );
361
DangerElements.clear();
365
CHECK( element_list.size() );
366
do_element_headcount();
367
CHECK( num_elements("total") );
368
CHECK( num_elements("volume") );
369
CHECK( num_elements("surface") );
373
// Communicate extra halo stuff.
375
vector< set<unsigned> > extraShared(NProcs);
376
ECHO("Communicating the extended halo...");
377
assert(extraHalo[MyRank].size() == 0);
378
allSendRecv(extraHalo, extraShared);
379
assert(extraShared[MyRank].size() == 0);
383
// Add in extra halo values...
385
for(int p=0; p<NProcs; p++){
389
// add in extra halo values
390
ECHO("Adding halo nodes for "<<p);
391
halo_pnodes[p].insert(extraHalo[p].begin(), extraHalo[p].end());
392
extraHalo[p].clear();
394
ECHO("Adding shared nodes for "<<p);
395
shared_pnodes[p].insert(extraShared[p].begin(), extraShared[p].end());
396
extraShared[p].clear();
402
} // finished unpacking
405
len45 = element_list.size();
406
for(unsigned i=0; i<len45; i++)
407
for(unsigned j=0; j<len45; j++)
409
assert(element_list[i] != element_list[j]);
412
ECHO("Halo2 created.");