Flow123d  release_2.2.0-914-gf1a3a4f
distribution.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file distribution.cc
15  * @ingroup system
16  * @brief Objects and functions for mesh partitioning.
17  */
18 
19 #include "system/global_defs.h"
20 #include "system/system.hh"
21 #include "distribution.hh"
22 
23 /**
24  * create a Distribution from local sizes (dim = np )
25  * (collective context)
26  */
27 Distribution::Distribution(const unsigned int size, MPI_Comm comm)
28 :communicator(comm),
29 lsizes(NULL)
30 {
31  int ierr;
33  OLD_ASSERT( ! ierr , "Can not get MPI rank.\n" );
35  OLD_ASSERT( ! ierr , "Can not get MPI size.\n" );
36 // TODO: zavest odchytavani vyjimek a pouzivat new a delete
37 
38  // communicate global sizes array
39  starts= new unsigned int [np()+1];
40  unsigned int lsize=size; // since size is const
42  // count starts
43  starts[0]=0;
44  for( unsigned int i=1 ; i<=np(); i++) starts[i]+=starts[i-1];
45 }
46 
47 /**
48  * create a Distribution from local sizes (dim = np )
49  * (local context)
50  */
51 Distribution::Distribution(const unsigned int * const sizes, MPI_Comm comm)
52 :communicator(comm),
53  lsizes(NULL)
54 {
55  int ierr;
57  OLD_ASSERT( ! ierr , "Can not get MPI rank.\n" );
59  OLD_ASSERT( ! ierr , "Can not get MPI size.\n" );
60 // TODO: zavest odchytavani vyjimek a pouzivat new a delete
61  starts= new unsigned int [np()+1];
62  starts[0]=0;
63  for(unsigned int i=0 ; i<np(); i++) starts[i+1]=starts[i]+sizes[i];
64 }
65 
66 /**
67  * constructor from existing PETSC vector
68  * (collective context)
69  */
70 Distribution::Distribution(const Vec &petsc_vector)
71 :communicator(PETSC_COMM_WORLD),
72  lsizes(NULL)
73 {
74  int ierr;
76  OLD_ASSERT( ! ierr , "Can not get MPI rank.\n" );
78  OLD_ASSERT( ! ierr , "Can not get MPI size.\n" );
79 
80  const PetscInt *petsc_starts;
81  VecGetOwnershipRanges(petsc_vector,&petsc_starts);
82  OLD_ASSERT( ! ierr , "Can not get vector ownership range.\n" );
83 
84  starts= new unsigned int [np()+1];
85  for(unsigned int i=0 ; i<=np(); i++) starts[i]=petsc_starts[i];
86 }
87 
88 /**
89  * construct from given global size
90  * (collective context)
91  */
92 Distribution::Distribution(const DistributionType &type, unsigned int global_size, MPI_Comm comm)
93 :communicator(comm),
94  lsizes(NULL)
95 {
96  int ierr;
98  OLD_ASSERT( ! ierr , "Can not get MPI rank.\n" );
100  OLD_ASSERT( ! ierr , "Can not get MPI size.\n" );
101  OLD_ASSERT( num_of_procs > 0, "MPI size is not positive, possibly broken MPI communicator.\n");
102 
103  if (type.type_ == Block) {
104  unsigned int reminder, per_proc;
105 
106  reminder=global_size % np(); per_proc=global_size / np();
107  // set perproc rows to each proc, but for first "reminder" procs set one row more
108  starts= new unsigned int [np()+1];
109  starts[0]=0;
110  for(unsigned int i=0; i<np(); i++)
111  starts[i+1]=starts[i]+per_proc+(i<reminder?1:0);
112 
113  } else if (type.type_ == Localized) {
114 
115  starts= new unsigned int [np()+1];
116  starts[0]=0;
117  for(unsigned int i=1; i<=np(); i++) starts[i]=global_size;
118  }
119  else {
120  OLD_ASSERT( 0 , "Cyclic distribution is not yet implemented.\n");
121  }
122  }
123 /**
124  * copy constructor
125  *
126  */
128 : communicator(distr.communicator)
129 {
131  my_proc=distr.my_proc;
132  starts= new unsigned int [np()+1];
133  memcpy(starts,distr.starts,(np()+1) * sizeof(unsigned int));
134  lsizes=NULL;
135 }
136 
137 
138 /**
139  * find the proc to which belongs index "idx" in the distribution
140  * use simple linear search, better binary search could be implemented
141  * (local context)
142  */
143 unsigned int Distribution::get_proc(unsigned int idx) const
144 {
145  OLD_ASSERT( starts,"Distribution is not initialized.\n");
146  OLD_ASSERT(idx < size(), "Index %d greater then distribution size %d.\n", idx, size());
147 
148  for(unsigned int i=0; i<np(); i++) {
149  if (is_on_proc(idx,i)) return (i);
150  }
151  OLD_ASSERT( 0 , "Can not find owner of index %d. \n", idx);
152  return (-1);
153 }
154 
155 const unsigned int * Distribution::get_lsizes_array()
156 {
157  if ( lsizes == NULL ) {
158  lsizes= new unsigned int [np()];
159  for(unsigned int i=0;i<np();i++) lsizes[i]=lsize(i);
160  }
161 
162  return lsizes;
163 }
164 
165 
166 
167 const unsigned int * Distribution::get_starts_array() const {
168  return starts;
169 }
170 
171 
172 
173 void Distribution::view(std::ostream &stream) const
174 {
175  stream << "[" <<myp() << "]" << "Distribution size: " << size() << " lsize: " << lsize() << " offset: " << begin() << " mpi_size: " << np() << endl;
176  for(unsigned int i=0; i<np();++i)
177  stream << "[" <<myp() << "]" << "proc: " << i << " offset: " << begin(i) << " lsize: " << lsize(i) << endl;
178 }
179 
180 /**
181  * Destructor.
182  */
184 {
185 // TODO: zavest odchytavani vyjimek a pouzivat new a delete
186  delete [] starts;
187  if (lsizes) delete [] lsizes;
188 }
189 
unsigned int size() const
get global size
unsigned int get_proc(unsigned int idx) const
get processor of the given index
int my_proc
my proc number
unsigned int * starts
starts[i] index of the first index on the proc i; starts[n_procs]=size of whole array ...
int MPI_Comm
Definition: mpi.h:141
unsigned int begin() const
Distribution(const unsigned int size, MPI_Comm comm)
Definition: distribution.cc:27
int num_of_procs
number of procs
unsigned int lsize() const
const unsigned int * get_lsizes_array()
get local sizes array
#define OLD_ASSERT(...)
Definition: global_defs.h:131
void view(std::ostream &stream) const
distribution view
Global macros to enhance readability and debugging, general constants.
const MPI_Comm communicator
communicator
const unsigned int * get_starts_array() const
get local starts array
#define MPI_Allgather(sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, comm)
Definition: mpi.h:580
unsigned int np() const
get num of processors
#define MPI_Comm_size
Definition: mpi.h:235
#define MPI_Comm_rank
Definition: mpi.h:236
unsigned int myp() const
get my processor
unsigned int * lsizes
local sizes
Support classes for parallel programing.
#define MPI_INT
Definition: mpi.h:160
bool is_on_proc(unsigned int idx, unsigned int proc) const