source: CIVL/examples/mpi-omp/AMG2013/parcsr_mv/par_csr_assumed_part.c

main
Last change on this file was ea777aa, checked in by Alex Wilton <awilton@…>, 3 years ago

Moved examples, include, build_default.properties, common.xml, and README out from dev.civl.com into the root of the repo.

git-svn-id: svn://vsl.cis.udel.edu/civl/trunk@5704 fb995dde-84ed-4084-dfe6-e5aef3e2452c

  • Property mode set to 100644
File size: 17.6 KB
Line 
1/*BHEADER**********************************************************************
2 * Copyright (c) 2008, Lawrence Livermore National Security, LLC.
3 * Produced at the Lawrence Livermore National Laboratory.
4 * This file is part of HYPRE. See file COPYRIGHT for details.
5 *
6 * HYPRE is free software; you can redistribute it and/or modify it under the
7 * terms of the GNU Lesser General Public License (as published by the Free
8 * Software Foundation) version 2.1 dated February 1999.
9 *
10 * $Revision: 2.4 $
11 ***********************************************************************EHEADER*/
12
13
14
15/*----------------------------------------------------
16 * Functions for the IJ assumed partition
17 * (Some of these were formerly in new_commpkg.c)
18 * AHB 4/06
19 *-----------------------------------------------------*/
20
21#include "headers.h"
22
23/* This is used only in the function below */
24#define CONTACT(a,b) (contact_list[(a)*3+(b)])
25
26/*--------------------------------------------------------------------
27 * hypre_LocateAssummedPartition
28 * Reconcile assumed partition with actual partition. Essentially
29 * each processor ends of with a partition of its assumed partition.
30 *--------------------------------------------------------------------*/
31
32
33int
34hypre_LocateAssummedPartition(MPI_Comm comm, HYPRE_BigInt row_start, HYPRE_BigInt row_end,
35 HYPRE_BigInt global_num_rows,
36 hypre_IJAssumedPart *part, int myid)
37{
38
39 int i;
40
41 HYPRE_BigInt *contact_list;
42 int contact_list_length, contact_list_storage;
43
44 HYPRE_BigInt contact_row_start[2], contact_row_end[2], contact_ranges;
45 int owner_start, owner_end;
46 HYPRE_BigInt tmp_row_start, tmp_row_end;
47
48 HYPRE_BigInt locate_row_start[2];
49 int locate_ranges, complete;
50
51 int locate_row_count, rows_found;
52
53 HYPRE_BigInt tmp_range[2];
54 HYPRE_BigInt *sortme;
55 int *si;
56
57 const int flag1 = 17;
58
59 MPI_Request *requests;
60 MPI_Status status0, *statuses;
61
62
63
64
65 /*-----------------------------------------------------------
66 * Contact ranges -
67 * which rows do I have that others are assumed responsible for?
68 * (at most two ranges - maybe none)
69 *-----------------------------------------------------------*/
70
71
72 contact_row_start[0]=0;
73 contact_row_end[0]=0;
74 contact_row_start[1]=0;
75 contact_row_end[1]=0;
76 contact_ranges = 0;
77
78 if (row_start <= row_end ) { /*must own at least one row*/
79
80 if ( part->row_end < row_start || row_end < part->row_start )
81 { /*no overlap - so all of my rows and only one range*/
82 contact_row_start[0] = row_start;
83 contact_row_end[0] = row_end;
84 contact_ranges++;
85 }
86 else /* the two regions overlap - so one or two ranges */
87 {
88 /* check for contact rows on the low end of the local range */
89 if (row_start < part->row_start)
90 {
91 contact_row_start[0] = row_start;
92 contact_row_end[0] = part->row_start - 1;
93 contact_ranges++;
94 }
95 if (part->row_end < row_end) /* check the high end */
96 {
97 if (contact_ranges) /* already found one range */
98 {
99 contact_row_start[1] = part->row_end +1;
100 contact_row_end[1] = row_end;
101 }
102 else
103 {
104 contact_row_start[0] = part->row_end +1;
105 contact_row_end[0] = row_end;
106 }
107 contact_ranges++;
108 }
109 }
110 }
111
112 /*-----------------------------------------------------------
113 * Contact: find out who is assumed responsible for these
114 * ranges of contact rows and contact them
115 *
116 *-----------------------------------------------------------*/
117
118
119 contact_list_length = 0;
120 contact_list_storage = 5;
121 contact_list = hypre_TAlloc(HYPRE_BigInt, contact_list_storage*3); /*each contact needs 3 ints */
122
123 for (i=0; i<contact_ranges; i++)
124 {
125
126 /*get start and end row owners */
127 hypre_GetAssumedPartitionProcFromRow(comm, contact_row_start[i], global_num_rows,
128 &owner_start);
129 hypre_GetAssumedPartitionProcFromRow(comm, contact_row_end[i], global_num_rows,
130 &owner_end);
131
132 if (owner_start == owner_end) /* same processor owns the whole range */
133 {
134
135 if (contact_list_length == contact_list_storage)
136 {
137 /*allocate more space*/
138 contact_list_storage += 5;
139 contact_list = hypre_TReAlloc(contact_list, HYPRE_BigInt, (contact_list_storage*3));
140 }
141 CONTACT(contact_list_length, 0) = (HYPRE_BigInt) owner_start; /*proc #*/
142 CONTACT(contact_list_length, 1) = contact_row_start[i]; /* start row */
143 CONTACT(contact_list_length, 2) = contact_row_end[i]; /*end row */
144 contact_list_length++;
145 }
146 else
147 {
148 complete = 0;
149 while (!complete)
150 {
151 hypre_GetAssumedPartitionRowRange(comm, owner_start, global_num_rows,
152 &tmp_row_start, &tmp_row_end);
153
154 if (tmp_row_end >= contact_row_end[i])
155 {
156 tmp_row_end = contact_row_end[i];
157 complete = 1;
158 }
159 if (tmp_row_start < contact_row_start[i])
160 {
161 tmp_row_start = contact_row_start[i];
162 }
163
164
165 if (contact_list_length == contact_list_storage)
166 {
167 /*allocate more space*/
168 contact_list_storage += 5;
169 contact_list = hypre_TReAlloc(contact_list, HYPRE_BigInt, (contact_list_storage*3));
170 }
171
172
173 CONTACT(contact_list_length, 0) = (HYPRE_BigInt) owner_start; /*proc #*/
174 CONTACT(contact_list_length, 1) = tmp_row_start; /* start row */
175 CONTACT(contact_list_length, 2) = tmp_row_end; /*end row */
176 contact_list_length++;
177 owner_start++; /*processors are seqential */
178 }
179 }
180 }
181
182 requests = hypre_CTAlloc(MPI_Request, contact_list_length);
183 statuses = hypre_CTAlloc(MPI_Status, contact_list_length);
184
185 /*send out messages */
186 for (i=0; i< contact_list_length; i++)
187 {
188 MPI_Isend(&CONTACT(i,1) ,2, MPI_HYPRE_BIG_INT, CONTACT(i,0), flag1 ,
189 comm, &requests[i]);
190 }
191
192 /*-----------------------------------------------------------
193 * Locate ranges -
194 * which rows in my assumed range do I not own
195 * (at most two ranges - maybe none)
196 * locate_row_count = total number of rows I must locate
197 *-----------------------------------------------------------*/
198
199
200 locate_row_count = 0;
201
202 locate_row_start[0]=0;
203 locate_row_start[1]=0;
204
205 locate_ranges = 0;
206
207 if (part->row_end < row_start || row_end < part->row_start )
208 /*no overlap - so all of my assumed rows */
209 {
210 locate_row_start[0] = part->row_start;
211 locate_ranges++;
212 locate_row_count += part->row_end - part->row_start + 1;
213 }
214 else /* the two regions overlap */
215 {
216 if (part->row_start < row_start)
217 {/* check for locate rows on the low end of the local range */
218 locate_row_start[0] = part->row_start;
219 locate_ranges++;
220 locate_row_count += (row_start-1) - part->row_start + 1;
221 }
222 if (row_end < part->row_end) /* check the high end */
223 {
224 if (locate_ranges) /* already have one range */
225 {
226 locate_row_start[1] = row_end +1;
227 }
228 else
229 {
230 locate_row_start[0] = row_end +1;
231 }
232 locate_ranges++;
233 locate_row_count += part->row_end - (row_end + 1) + 1;
234 }
235 }
236
237
238 /*-----------------------------------------------------------
239 * Receive messages from other procs telling us where
240 * all our locate rows actually reside
241 *-----------------------------------------------------------*/
242
243
244 /* we will keep a partition of our assumed partition - list ourselves
245 first. We will sort later with an additional index.
246 In practice, this should only contain a few processors */
247
248 /*which part do I own?*/
249 tmp_row_start = hypre_max(part->row_start, row_start);
250 tmp_row_end = hypre_min(row_end, part->row_end);
251
252 if (tmp_row_start <= tmp_row_end)
253 {
254 part->proc_list[0] = myid;
255 part->row_start_list[0] = tmp_row_start;
256 part->row_end_list[0] = tmp_row_end;
257 part->length++;
258 }
259
260 /* now look for messages that tell us which processor has our locate rows */
261 /* these will be blocking receives as we know how many to expect and they should
262 be waiting (and we don't want to continue on without them) */
263
264 rows_found = 0;
265
266 while (rows_found != locate_row_count) {
267
268 MPI_Recv( tmp_range, 2 , MPI_HYPRE_BIG_INT, MPI_ANY_SOURCE,
269 flag1 , comm, &status0);
270
271 if (part->length==part->storage_length)
272 {
273 part->storage_length+=10;
274 part->proc_list = hypre_TReAlloc(part->proc_list, int, part->storage_length);
275 part->row_start_list = hypre_TReAlloc(part->row_start_list, HYPRE_BigInt, part->storage_length);
276 part->row_end_list = hypre_TReAlloc(part->row_end_list, HYPRE_BigInt, part->storage_length);
277
278 }
279 part->row_start_list[part->length] = tmp_range[0];
280 part->row_end_list[part->length] = tmp_range[1];
281
282 part->proc_list[part->length] = status0.MPI_SOURCE;
283 rows_found += (int)(tmp_range[1]- tmp_range[0]) + 1;
284
285 part->length++;
286 }
287
288 /*In case the partition of the assumed partition is longish,
289 we would like to know the sorted order */
290 si= hypre_CTAlloc(int, part->length);
291 sortme = hypre_CTAlloc(HYPRE_BigInt, part->length);
292
293 for (i=0; i<part->length; i++)
294 {
295 si[i] = i;
296 sortme[i] = part->row_start_list[i];
297 }
298 hypre_BigQsortbi( sortme, si, 0, (part->length)-1);
299 part->sort_index = si;
300
301 /*free the requests */
302 MPI_Waitall(contact_list_length, requests,
303 statuses);
304
305
306 hypre_TFree(statuses);
307 hypre_TFree(requests);
308
309
310 hypre_TFree(sortme);
311 hypre_TFree(contact_list);
312
313
314 return hypre_error_flag;
315
316
317}
318
319/*--------------------------------------------------------------------
320 * hypre_ParCSRMatrixCreateAssumedPartition -
321 * Each proc gets it own range. Then
322 * each needs to reconcile its actual range with its assumed
323 * range - the result is essentila a partition of its assumed range -
324 * this is the assumed partition.
325 *--------------------------------------------------------------------*/
326
327
328int
329hypre_ParCSRMatrixCreateAssumedPartition( hypre_ParCSRMatrix *matrix)
330{
331
332
333 HYPRE_BigInt global_num_cols;
334 int myid;
335 HYPRE_BigInt row_start=0, row_end=0, col_start = 0, col_end = 0;
336
337 MPI_Comm comm;
338
339 hypre_IJAssumedPart *apart;
340
341 global_num_cols = hypre_ParCSRMatrixGlobalNumCols(matrix);
342 comm = hypre_ParCSRMatrixComm(matrix);
343
344 /* find out my actualy range of rows and columns */
345 hypre_ParCSRMatrixGetLocalRange( matrix,
346 &row_start, &row_end ,
347 &col_start, &col_end );
348 MPI_Comm_rank(comm, &myid );
349
350 /* allocate space */
351 apart = hypre_CTAlloc(hypre_IJAssumedPart, 1);
352
353 /* get my assumed partitioning - we want partitioning of the vector that the
354 matrix multiplies - so we use the col start and end */
355 hypre_GetAssumedPartitionRowRange( comm, myid, global_num_cols, &(apart->row_start),
356 &(apart->row_end));
357
358 /*allocate some space for the partition of the assumed partition */
359 apart->length = 0;
360 /*room for 10 owners of the assumed partition*/
361 apart->storage_length = 10; /*need to be >=1 */
362 apart->proc_list = hypre_TAlloc(int, apart->storage_length);
363 apart->row_start_list = hypre_TAlloc(HYPRE_BigInt, apart->storage_length);
364 apart->row_end_list = hypre_TAlloc(HYPRE_BigInt, apart->storage_length);
365
366
367 /* now we want to reconcile our actual partition with the assumed partition */
368 hypre_LocateAssummedPartition(comm, col_start, col_end, global_num_cols, apart, myid);
369
370 /* this partition will be saved in the matrix data structure until the matrix is destroyed */
371 hypre_ParCSRMatrixAssumedPartition(matrix) = apart;
372
373 return hypre_error_flag;
374
375
376}
377
378/*--------------------------------------------------------------------
379 * hypre_ParCSRMatrixDestroyAssumedPartition
380 *--------------------------------------------------------------------*/
381int
382hypre_ParCSRMatrixDestroyAssumedPartition(hypre_ParCSRMatrix *matrix )
383{
384
385 hypre_IJAssumedPart *apart;
386
387 apart = hypre_ParCSRMatrixAssumedPartition(matrix);
388
389
390 if(apart->storage_length > 0)
391 {
392 hypre_TFree(apart->proc_list);
393 hypre_TFree(apart->row_start_list);
394 hypre_TFree(apart->row_end_list);
395 hypre_TFree(apart->sort_index);
396 }
397
398 hypre_TFree(apart);
399
400 return hypre_error_flag;
401
402}
403
404/*--------------------------------------------------------------------
405 * hypre_GetAssumedPartitionProcFromRow
406 * Assumed partition for IJ case. Given a particular row j, return
407 * the processor that is assumed to own that row.
408 *--------------------------------------------------------------------*/
409
410
411int
412hypre_GetAssumedPartitionProcFromRow( MPI_Comm comm, HYPRE_BigInt row, HYPRE_BigInt global_num_rows, int *proc_id)
413{
414
415 int num_procs;
416 HYPRE_BigInt size, extra, temp;
417 HYPRE_BigInt switch_row;
418
419
420 MPI_Comm_size(comm, &num_procs );
421
422 /* j = floor[(row*p/N] - this overflows*/
423 /* *proc_id = (row*num_procs)/global_num_rows;*/
424
425 /* this looks a bit odd, but we have to be very careful that
426 this function and the next are inverses - and rounding
427 errors make this difficult!!!!! */
428
429 size = global_num_rows /(HYPRE_BigInt)num_procs;
430 extra = global_num_rows - size*(HYPRE_BigInt)num_procs;
431 switch_row = (size + 1)*extra;
432
433 if (row >= switch_row)
434 {
435 temp = extra + (row - switch_row)/size;
436 *proc_id = (int)temp;
437 }
438 else
439 {
440 temp = row/(size+1);
441 *proc_id = (int)temp;
442 }
443
444
445 return hypre_error_flag;
446
447
448}
449/*--------------------------------------------------------------------
450 * hypre_GetAssumedPartitionRowRange
451 * Assumed partition for IJ case. Given a particular processor id, return
452 * the assumed range of rows ([row_start, row_end]) for that processor.
453 *--------------------------------------------------------------------*/
454
455
456int
457hypre_GetAssumedPartitionRowRange( MPI_Comm comm, int proc_id, HYPRE_BigInt global_num_rows,
458 HYPRE_BigInt *row_start, HYPRE_BigInt* row_end)
459{
460
461 int num_procs;
462 int size, extra;
463
464
465 MPI_Comm_size(comm, &num_procs );
466
467
468 /* this may look non-intuitive, but we have to be very careful that
469 this function and the next are inverses - and avoiding overflow and
470 rounding errors makes this difficult! */
471
472 size = (int)(global_num_rows /num_procs);
473 extra = (int)(global_num_rows - (HYPRE_BigInt)size*(HYPRE_BigInt)num_procs);
474
475 *row_start = (HYPRE_BigInt)size*(HYPRE_BigInt)proc_id;
476 *row_start += (HYPRE_BigInt)hypre_min(proc_id, extra);
477
478
479 *row_end = (HYPRE_BigInt)size*(HYPRE_BigInt)(proc_id+1);
480 *row_end += (HYPRE_BigInt)hypre_min(proc_id+1, extra);
481 *row_end = *row_end - 1;
482
483
484 return hypre_error_flag;
485
486}
487
488
489/*--------------------------------------------------------------------
490 * hypre_ParVectorCreateAssumedPartition -
491
492 * Essentially the same as for a matrix!
493
494 * Each proc gets it own range. Then
495 * each needs to reconcile its actual range with its assumed
496 * range - the result is essentila a partition of its assumed range -
497 * this is the assumed partition.
498 *--------------------------------------------------------------------*/
499
500
501int
502hypre_ParVectorCreateAssumedPartition( hypre_ParVector *vector)
503{
504
505
506 HYPRE_BigInt global_num;
507 int myid;
508 HYPRE_BigInt start=0, end=0;
509
510 MPI_Comm comm;
511
512 hypre_IJAssumedPart *apart;
513
514 global_num = hypre_ParVectorGlobalSize(vector);
515 comm = hypre_ParVectorComm(vector);
516
517 /* find out my actualy range of rows */
518 start = hypre_ParVectorFirstIndex(vector);
519 end = hypre_ParVectorLastIndex(vector);
520
521 MPI_Comm_rank(comm, &myid );
522
523 /* allocate space */
524 apart = hypre_CTAlloc(hypre_IJAssumedPart, 1);
525
526 /* get my assumed partitioning - we want partitioning of the vector that the
527 matrix multiplies - so we use the col start and end */
528 hypre_GetAssumedPartitionRowRange( comm, myid, global_num, &(apart->row_start),
529 &(apart->row_end));
530
531 /*allocate some space for the partition of the assumed partition */
532 apart->length = 0;
533 /*room for 10 owners of the assumed partition*/
534 apart->storage_length = 10; /*need to be >=1 */
535 apart->proc_list = hypre_TAlloc(int, apart->storage_length);
536 apart->row_start_list = hypre_TAlloc(HYPRE_BigInt, apart->storage_length);
537 apart->row_end_list = hypre_TAlloc(HYPRE_BigInt, apart->storage_length);
538
539
540 /* now we want to reconcile our actual partition with the assumed partition */
541 hypre_LocateAssummedPartition(comm, start, end, global_num, apart, myid);
542
543 /* this partition will be saved in the vector data structure until the vector is destroyed */
544 hypre_ParVectorAssumedPartition(vector) = apart;
545
546 return hypre_error_flag;
547
548
549}
550
551/*--------------------------------------------------------------------
552 * hypre_ParVectorDestroyAssumedPartition
553 *--------------------------------------------------------------------*/
554int
555hypre_ParVectorDestroyAssumedPartition(hypre_ParVector *vector )
556{
557
558 hypre_IJAssumedPart *apart;
559
560 apart = hypre_ParVectorAssumedPartition(vector);
561
562
563 if(apart->storage_length > 0)
564 {
565 hypre_TFree(apart->proc_list);
566 hypre_TFree(apart->row_start_list);
567 hypre_TFree(apart->row_end_list);
568 hypre_TFree(apart->sort_index);
569 }
570
571 hypre_TFree(apart);
572
573 return hypre_error_flag;
574
575}
Note: See TracBrowser for help on using the repository browser.