Flow123d
distribution.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2007 Technical University of Liberec. All rights reserved.
4  *
5  * Please make a following refer to Flow123d on your project site if you use the program for any purpose,
6  * especially for academic research:
7  * Flow123d, Research Centre: Advanced Remedial Technologies, Technical University of Liberec, Czech Republic
8  *
9  * This program is free software; you can redistribute it and/or modify it under the terms
10  * of the GNU General Public License version 3 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along with this program; if not,
17  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
18  *
19  *
20  * $Id$
21  * $Revision$
22  * $LastChangedBy$
23  * $LastChangedDate$
24  *
25  * @file
26  * @ingroup system
27  * @brief Objects and functions for mesh partitioning.
28  *
29  */
30 
31 #include "system/global_defs.h"
32 #include "system/system.hh"
33 #include "distribution.hh"
34 
35 /**
36  * create a Distribution from local sizes (dim = np )
37  * (collective context)
38  */
39 Distribution::Distribution(const unsigned int size, MPI_Comm comm)
40 :communicator(comm),
41 lsizes(NULL)
42 {
43  F_ENTRY;
44 
45  int ierr;
47  ASSERT( ! ierr , "Can not get MPI rank.\n" );
49  ASSERT( ! ierr , "Can not get MPI size.\n" );
50 // TODO: zavest odchytavani vyjimek a pouzivat new a delete
51 
52  // communicate global sizes array
53  starts=(unsigned int *)xmalloc((np()+1)*sizeof(unsigned int));
54  unsigned int lsize=size; // since size is const
56  // count starts
57  starts[0]=0;
58  for( unsigned int i=1 ; i<=np(); i++) starts[i]+=starts[i-1];
59 }
60 
61 /**
62  * create a Distribution from local sizes (dim = np )
63  * (local context)
64  */
65 Distribution::Distribution(const unsigned int * const sizes, MPI_Comm comm)
66 :communicator(comm),
67  lsizes(NULL)
68 {
69  F_ENTRY;
70 
71  int ierr;
73  ASSERT( ! ierr , "Can not get MPI rank.\n" );
75  ASSERT( ! ierr , "Can not get MPI size.\n" );
76 // TODO: zavest odchytavani vyjimek a pouzivat new a delete
77  starts=(unsigned int *)xmalloc((np()+1)*sizeof(unsigned int));
78  starts[0]=0;
79  for(unsigned int i=0 ; i<np(); i++) starts[i+1]=starts[i]+sizes[i];
80 }
81 
82 /**
83  * constructor from existing PETSC vector
84  * (collective context)
85  */
86 Distribution::Distribution(const Vec &petsc_vector)
87 :communicator(PETSC_COMM_WORLD),
88  lsizes(NULL)
89 {
90  F_ENTRY;
91 
92  int ierr;
94  ASSERT( ! ierr , "Can not get MPI rank.\n" );
96  ASSERT( ! ierr , "Can not get MPI size.\n" );
97 
98  const PetscInt *petsc_starts;
99  VecGetOwnershipRanges(petsc_vector,&petsc_starts);
100  ASSERT( ! ierr , "Can not get vector ownership range.\n" );
101 
102  starts=(unsigned int *)xmalloc((np()+1)*sizeof(int));
103  for(unsigned int i=0 ; i<=np(); i++) starts[i]=petsc_starts[i];
104 }
105 
106 /**
107  * construct from given global size
108  * (collective context)
109  */
110 Distribution::Distribution(const DistributionType &type, unsigned int global_size, MPI_Comm comm)
111 :communicator(comm),
112  lsizes(NULL)
113 {
114  F_ENTRY;
115 
116  int ierr;
118  ASSERT( ! ierr , "Can not get MPI rank.\n" );
120  ASSERT( ! ierr , "Can not get MPI size.\n" );
121  ASSERT( num_of_procs > 0, "MPI size is not positive, possibly broken MPI communicator.\n");
122 
123  if (type.type_ == Block) {
124  int reminder, per_proc;
125 
126  reminder=global_size % np(); per_proc=global_size / np();
127  // set perproc rows to each proc, but for first "reminder" procs set one row more
128  starts=(unsigned int *)xmalloc((np()+1)*sizeof(unsigned int));
129  starts[0]=0;
130  for(unsigned int i=0; i<np(); i++)
131  starts[i+1]=starts[i]+per_proc+(i<reminder?1:0);
132 
133  } else if (type.type_ == Localized) {
134 
135  starts=(unsigned int *)xmalloc((np()+1)*sizeof(unsigned int));
136  starts[0]=0;
137  for(unsigned int i=1; i<=np(); i++) starts[i]=global_size;
138  }
139  else {
140  ASSERT( 0 , "Cyclic distribution is not yet implemented.\n");
141  }
142  }
143 /**
144  * copy constructor
145  *
146  */
148 : communicator(distr.communicator)
149 {
151  my_proc=distr.my_proc;
152  starts=(unsigned int *)xmalloc((np()+1)*sizeof(unsigned int));
153  memcpy(starts,distr.starts,(np()+1) * sizeof(unsigned int));
154  lsizes=NULL;
155 }
156 
157 
158 /**
159  * find the proc to which belongs index "idx" in the distribution
160  * use simple linear search, better binary search could be implemented
161  * (local context)
162  */
163 unsigned int Distribution::get_proc(unsigned int idx) const
164 {
165  ASSERT( starts,"Distribution is not initialized.\n");
166  ASSERT(idx < size(), "Index %d greater then distribution size %d.\n", idx, size());
167 
168  for(unsigned int i=0; i<np(); i++) {
169  if (is_on_proc(idx,i)) return (i);
170  }
171  ASSERT( 0 , "Can not find owner of index %d. \n", idx);
172  return (-1);
173 }
174 
175 const unsigned int * Distribution::get_lsizes_array()
176 {
177  if ( lsizes == NULL ) {
178  lsizes=(unsigned int *) xmalloc(np()*sizeof(int));
179  for(unsigned int i=0;i<np();i++) lsizes[i]=lsize(i);
180  }
181 
182  return lsizes;
183 }
184 
185 
186 
187 const unsigned int * Distribution::get_starts_array() const {
188  return starts;
189 }
190 
191 
192 
193 void Distribution::view(std::ostream &stream) const
194 {
195  stream << "[" <<myp() << "]" << "Distribution size: " << size() << " lsize: " << lsize() << " offset: " << begin() << " mpi_size: " << np() << endl;
196  for(unsigned int i=0; i<np();++i)
197  stream << "[" <<myp() << "]" << "proc: " << i << " offset: " << begin(i) << " lsize: " << lsize(i) << endl;
198 }
199 
200 /**
201  * Destructor.
202  */
204 {
205 // TODO: zavest odchytavani vyjimek a pouzivat new a delete
206  xfree(starts);
207  if (lsizes) xfree(lsizes);
208 }
209