ROL
ROL_PinTVector.hpp
Go to the documentation of this file.
1 
2 // @HEADER
3 // ************************************************************************
4 //
5 // Rapid Optimization Library (ROL) Package
6 // Copyright (2014) Sandia Corporation
7 //
8 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
9 // license for use of this work by or on behalf of the U.S. Government.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact lead developers:
39 // Drew Kouri (dpkouri@sandia.gov) and
40 // Denis Ridzal (dridzal@sandia.gov)
41 //
42 // ************************************************************************
43 // @HEADER
44 
45 #ifndef ROL_PINTVECTOR_H
46 #define ROL_PINTVECTOR_H
47 
48 #include <ostream>
49 
50 #include "mpi.h"
51 
52 #include "ROL_Vector.hpp"
54 #include "ROL_StdVector.hpp"
55 
61 namespace ROL {
62 
68 public:
69  PinTCommunicators(MPI_Comm parent,int spatialProcs)
70  {
71  parentComm_ = parent;
72 
73  int myGlobalRank = -1;
74  int globalProcs = -1;
75  MPI_Comm_size(parentComm_, &globalProcs);
76  MPI_Comm_rank(parentComm_, &myGlobalRank);
77 
78  // make sure they divide evenly (for sanity!)
79  assert(globalProcs % spatialProcs == 0);
80 
81  int space = myGlobalRank / spatialProcs;
82  int time = myGlobalRank % spatialProcs;
83 
84  // this decomposition comes from X-Braid
85  MPI_Comm_split(parentComm_,space,myGlobalRank,&spaceComm_);
86  MPI_Comm_split(parentComm_, time,myGlobalRank, &timeComm_);
87 
88  MPI_Comm_size(timeComm_, &timeSize_);
89  MPI_Comm_rank(timeComm_, &timeRank_);
90 
91  MPI_Comm_size(spaceComm_, &spaceSize_);
92  MPI_Comm_rank(spaceComm_, &spaceRank_);
93  }
94 
95  // cleanup
97  { MPI_Comm_free(&spaceComm_);
98  MPI_Comm_free(&timeComm_); }
99 
100  MPI_Comm getParentCommunicator() const { return parentComm_; }
101  MPI_Comm getSpaceCommunicator() const { return spaceComm_; }
102  MPI_Comm getTimeCommunicator() const { return timeComm_; }
103 
104  int getTimeRank() const { return timeRank_; }
105  int getTimeSize() const { return timeSize_; }
106 
107  int getSpaceRank() const { return spaceRank_; }
108  int getSpaceSize() const { return spaceSize_; }
109 
110 private:
111 
112  MPI_Comm parentComm_;
113 
114  MPI_Comm spaceComm_;
115  MPI_Comm timeComm_;
120 };
121 
122 template <class Real>
124 public:
125  void send(MPI_Comm comm,int rank,Vector<Real> & source) const
126  {
127  const std::vector<Real> & std_source = *dynamic_cast<const StdVector<Real>&>(source).getVector();
128 
129  // int myRank = -1;
130  // MPI_Comm_rank(comm, &myRank);
131 
132  MPI_Send(const_cast<Real*>(&std_source[0]),int(std_source.size()),MPI_DOUBLE,rank,0,comm);
133  }
134 
135  void recv(MPI_Comm comm,int rank,Vector<Real> & dest,bool sumInto) const
136  {
137  if(sumInto)
138  recvSumInto(comm,rank,dest);
139  else
140  recv(comm,rank,dest);
141  }
142 
143  void recv(MPI_Comm comm,int rank,Vector<Real> & dest) const
144  {
145  std::vector<Real> & std_dest = *dynamic_cast<StdVector<Real>&>(dest).getVector();
146 
147  // int myRank = -1;
148  // MPI_Comm_rank(comm, &myRank);
149 
150  MPI_Recv(&std_dest[0],int(std_dest.size()),MPI_DOUBLE,rank,0,comm,MPI_STATUS_IGNORE);
151  }
152 
153  void recvSumInto(MPI_Comm comm,int rank,Vector<Real> & dest) const
154  {
155  std::vector<Real> & std_dest = *dynamic_cast<StdVector<Real>&>(dest).getVector();
156  std::vector<Real> buffer(std_dest.size(),0.0);
157 
158  int myRank = -1;
159  MPI_Comm_rank(comm, &myRank);
160 
161  MPI_Recv(&buffer[0],int(buffer.size()),MPI_DOUBLE,rank,0,comm,MPI_STATUS_IGNORE);
162 
163  for(size_t i=0;i<std_dest.size();i++)
164  std_dest[i] += buffer[i];
165  }
166 };
167 
168 template <class Real>
170  : public Vector<Real>
171 {
172 protected:
173  // Class to build all the communciators
174 
175  // members
177 
178  Ptr<const PinTCommunicators> communicators_;
179 
180  Ptr<Vector<Real>> localVector_;
181  int steps_;
182  std::vector<int> stencil_;
183 
184  // parallel distribution information
186  int stepEnd_;
187 
188  mutable Ptr<PinTVector<Real>> dual_;
189 
190  Ptr<PartitionedVector<Real>> stepVectors_;
191  std::vector<Ptr<Vector<Real>>> leftVectors_;
192  std::vector<Ptr<Vector<Real>>> rightVectors_;
193 
194  Ptr<PinTVectorCommunication<Real>> vectorComm_;
195 
196  // Using parallel communication and a linear decomposition
197  // determine where this processor lives in the global
198  // scheme of things
199  void computeStepStartEnd(int steps)
200  {
201  int numRanks = communicators_->getTimeSize();
202  int myRank = communicators_->getTimeRank();
203 
204  // determine which steps are owned by this processor
205  {
206  int stepsPerRank = steps / numRanks;
207  int remainder = steps % numRanks;
208 
209  stepStart_ = 0;
210 
211  if(myRank<remainder) {
212  stepStart_ = myRank*(stepsPerRank+1);
213  stepEnd_ = (myRank+1)*(stepsPerRank+1);
214  }
215  else if(myRank==remainder) {
216  stepStart_ = myRank*(stepsPerRank+1);
217  stepEnd_ = (myRank+1)*stepsPerRank + myRank;
218  }
219  else if(myRank>remainder) {
220  stepStart_ = myRank*stepsPerRank + remainder;
221  stepEnd_ = (myRank+1)*stepsPerRank + remainder;
222  }
223  }
224 
225  assert(stepStart_>=0);
226  assert(stepEnd_>stepStart_);
227  }
228 
230  {
231  int numLeft = 0;
232  int numRight = 0;
233 
234  for(int i=0;i<(int)stencil_.size();i++) {
235  if(stencil_[i]<0)
236  numLeft = std::max(numLeft,std::abs(stencil_[i]));
237  else if(stencil_[i]>0)
238  numRight = std::max(numRight,stencil_[i]);
239  }
240 
241  // there is a slight over allocation here if the stencil is sparse
242  leftVectors_.resize(numLeft);
243  for(int i=0;i<numLeft;i++) {
244  leftVectors_[i] = localVector_->clone();
245  leftVectors_[i]->set(*localVector_); // make sure each subvector is initialized
246  }
247 
248  // there is a slight over allocation here if the stencil is sparse
249  rightVectors_.resize(numRight);
250  for(int i=0;i<numRight;i++) {
251  rightVectors_[i] = localVector_->clone();
252  rightVectors_[i]->set(*localVector_); // make sure each subvector is initialized
253  }
254  }
255 
256 public:
257 
259 
261  : isInitialized_(false)
262  {}
263 
265  {
267 
268  // make sure you copy boundary exchange "end points" - handles initial conditions
269  for(std::size_t i=0;i<leftVectors_.size();i++)
270  leftVectors_[i]->set(*v.leftVectors_[i]);
271 
272  // make sure you copy boundary exchange "end points" - handles initial conditions
273  for(std::size_t i=0;i<rightVectors_.size();i++)
274  rightVectors_[i]->set(*v.rightVectors_[i]);
275  }
276 
277  PinTVector(const Ptr<const PinTCommunicators> & comm,
278  const Ptr<Vector<Real>> & localVector,
279  int steps,
280  const std::vector<int> & stencil)
281  : isInitialized_(false)
282  {
283  initialize(comm,localVector,steps,stencil);
284  }
285 
286  virtual ~PinTVector() {}
287 
288  void initialize(const Ptr<const PinTCommunicators> & comm,
289  const Ptr<Vector<Real>> & localVector,
290  int steps,
291  const std::vector<int> & stencil)
292  {
293  communicators_ = comm;
294  localVector_ = localVector;
295  steps_ = steps;
296  stencil_ = stencil;
297  vectorComm_ = makePtr<PinTVectorCommunication<Real>>();
298 
301 
302  std::vector<Ptr<Vector<Real>>> stepVectors;
303  stepVectors.resize(stepEnd_-stepStart_ + rightVectors_.size() + leftVectors_.size());
304 
305  // build up local vectors
306  for(int i=0;i<(int)stepVectors.size();i++) {
307  stepVectors[i] = localVector_->clone();
308  stepVectors[i]->set(*localVector_); // make sure each subvector is initialized
309  }
310 
311  stepVectors_ = makePtr<PartitionedVector<Real>>(stepVectors);
312 
313  isInitialized_ = true;
314  }
315 
323  int numOwnedVectors() const
324  {
325  return stepVectors_->numVectors();
326  }
327 
334  int numOwnedSteps() const
335  {
336  return stepVectors_->numVectors()-leftVectors_.size()-rightVectors_.size();
337  }
338 
345  const std::vector<int> & stencil() const { return stencil_; }
346 
349  const PinTCommunicators & communicators() const { return *communicators_; }
350 
351 
358  bool isValidIndex(int i) const
359  {
360  int leftCount = leftVectors_.size();
361  int rightCount = rightVectors_.size();
362 
363  if(0<=i && i <numOwnedSteps()) {
364  return true;
365  }
366 
367  // these are "neighbor" unowned vectors (left)
368  if(-leftCount <= i && i < 0) {
369  return true;
370  }
371 
372  // these are "neighbor" unowned vectors (right)
373  if((int)numOwnedSteps() <= i && i<numOwnedSteps()+rightCount) {
374  return true;
375  }
376 
377  return false;
378  }
379 
382  Ptr<Vector<Real>> getVectorPtr(int i) const
383  {
384  if(not isValidIndex(i))
385  return nullPtr;
386 
387  return stepVectors_->get(i+leftVectors_.size());
388  }
389 
394  Ptr<Vector<Real>> getRemoteBufferPtr(int i) const
395  {
396  assert(isValidIndex(i));
397  assert(i<0 and i>=numOwnedSteps());
398 
399  int leftCount = leftVectors_.size();
400  int rightCount = rightVectors_.size();
401 
402  // these are "neighbor" unowned vectors (left)
403  if(-leftCount <= i && i < 0)
404  return leftVectors_[leftVectors_.size()+i];
405 
406  // these are "neighbor" unowned vectors (right)
407  if(numOwnedSteps() <= i && i<numOwnedSteps()+rightCount)
408  return rightVectors_[i-numOwnedSteps()];
409 
410  return nullPtr;
411  }
412 
422  {
423  MPI_Comm timeComm = communicators_->getTimeCommunicator();
424  int myRank = communicators_->getTimeRank();
425 
426  bool sendToRight = stepEnd_ < steps_;
427  bool recvFromRight = stepEnd_ < steps_;
428 
429  bool sendToLeft = stepStart_ > 0;
430  bool recvFromLeft = stepStart_ > 0;
431 
432  // this allows finer granularity of control of send recieve
433  // and will permit some blocking communication
434  if(send_recv==SEND_ONLY) {
435  recvFromRight = false;
436  recvFromLeft = false;
437  }
438  if(send_recv==RECV_ONLY) {
439  sendToRight = false;
440  sendToLeft = false;
441  }
442  // do nothing if(send_recv==SEND_AND_RECV)
443 
444  // send from left to right
445  for(std::size_t i=0;i<stencil_.size();i++) {
446  int offset = stencil_[i];
447  if(offset >= 0)
448  continue;
449 
450  if(sendToRight)
451  vectorComm_->send(timeComm,myRank+1,*getVectorPtr(numOwnedSteps()+offset)); // this is "owned"
452 
453  if(recvFromLeft)
454  vectorComm_->recv(timeComm,myRank-1,*getRemoteBufferPtr(offset),false);
455  }
456 
457  // send from right to left
458  for(std::size_t i=0;i<stencil_.size();i++) {
459  int offset = stencil_[i];
460  if(offset <= 0)
461  continue;
462 
463  if(sendToLeft)
464  vectorComm_->send(timeComm,myRank-1,*getVectorPtr(offset-1)); // this is "owned"
465 
466  if(recvFromRight)
467  vectorComm_->recv(timeComm,myRank+1,*getRemoteBufferPtr(numOwnedSteps()+offset-1),false);
468  }
469  }
470 
480  {
481  MPI_Comm timeComm = communicators_->getTimeCommunicator();
482  int myRank = communicators_->getTimeRank();
483 
484  bool sendToRight = stepEnd_ < steps_;
485  bool recvFromRight = stepEnd_ < steps_;
486 
487  bool sendToLeft = stepStart_ > 0;
488  bool recvFromLeft = stepStart_ > 0;
489 
490  // send from left to right
491  for(std::size_t i=0;i<stencil_.size();i++) {
492  int offset = stencil_[i];
493  if(offset >= 0)
494  continue;
495 
496  if(recvFromRight) {
497  vectorComm_->recv(timeComm,myRank+1,*getVectorPtr(numOwnedSteps()+offset),true); // this is "owned"
498  }
499 
500  if(sendToLeft) {
501  vectorComm_->send(timeComm,myRank-1,*getRemoteBufferPtr(offset));
502  }
503  }
504 
505  // send from right to left
506  for(std::size_t i=0;i<stencil_.size();i++) {
507  int offset = stencil_[i];
508  if(offset <= 0)
509  continue;
510 
511  if(recvFromLeft)
512  vectorComm_->recv(timeComm,myRank-1,*getVectorPtr(offset-1),true); // this is "owned"
513 
514  if(sendToRight)
515  vectorComm_->send(timeComm,myRank+1,*getRemoteBufferPtr(numOwnedSteps()+offset-1));
516  }
517  }
518 
519  // Vector virtual methods
520 
529  virtual void plus( const Vector<Real> &x )
530  {
531  typedef PinTVector<Real> PinTVector;
532  const PinTVector &xs = dynamic_cast<const PinTVector&>(x);
533 
534  stepVectors_->plus(*xs.stepVectors_);
535  }
536 
537 
546  virtual void scale( const Real alpha )
547  {
548  stepVectors_->scale(alpha);
549  }
550 
551 
559  virtual Real dot( const Vector<Real> &x ) const
560  {
561  // this is probably very inefficient way to do this... oh well!
562  typedef PinTVector<Real> PinTVector;
563  const PinTVector &xs = dynamic_cast<const PinTVector&>(x);
564 
565  // this won't work for Real!=double...oh well!
566  Real subdot = stepVectors_->dot(*xs.stepVectors_);
567  if(communicators_->getSpaceRank()!=0) // the space vectors compute the right 'dot', but we need to get rid of them
568  subdot = 0.0;
569 
570  // NOTE: it might be cheaper to use the TimeCommunicator on the all reduce and then
571  // broadcast to the space communicator
572  Real dot = 0;
573  MPI_Allreduce(&subdot,&dot,1,MPI_DOUBLE,MPI_SUM,communicators_->getParentCommunicator());
574 
575  return dot;
576  }
577 
584  virtual Real norm() const
585  {
586  // this is probably very inefficient way to do this... oh well!
587  return std::sqrt(this->dot(*this));
588  }
589 
598  virtual ROL::Ptr<Vector<Real>> clone() const
599  {
600  return makePtr<PinTVector<Real>>(*this);
601  }
602 
603  virtual void print( std::ostream &outStream) const override
604  {
605  stepVectors_->print(outStream);
606  }
607 
608  virtual void applyUnary( const Elementwise::UnaryFunction<Real> &f ) override {
609  stepVectors_->applyUnary(f);
610  }
611 
622  virtual void set( const Vector<Real> &x ) override {
623  typedef PinTVector<Real> PinTVector;
624  const PinTVector &xs = dynamic_cast<const PinTVector&>(x);
625 
626  stepVectors_->set(*xs.stepVectors_);
627  }
628 
640  virtual void axpy( const Real alpha, const Vector<Real> &x ) override {
641  typedef PinTVector<Real> PinTVector;
642  const PinTVector &xs = dynamic_cast<const PinTVector&>(x);
643 
644  stepVectors_->axpy(alpha,*xs.stepVectors_);
645  }
646 
649  virtual void zeroAll()
650  {
651  stepVectors_->zero();
652 
653  // make sure you copy boundary exchange "end points" - handles initial conditions
654  for(std::size_t i=0;i<leftVectors_.size();i++)
655  leftVectors_[i]->zero();
656 
657  // make sure you copy boundary exchange "end points" - handles initial conditions
658  for(std::size_t i=0;i<rightVectors_.size();i++)
659  rightVectors_[i]->zero();
660  }
661 
662 #if 0
663 
670  virtual void zero();
671 
680  virtual int dimension() const;
681 #endif
682 
683 }; // class Vector
684 
685 } // namespace ROL
686 
687 #endif
virtual ROL::Ptr< Vector< Real > > clone() const
Clone to make a new (uninitialized) vector.
virtual void set(const Vector< Real > &x) override
Set where .
Ptr< Vector< Real > > getVectorPtr(int i) const
virtual int dimension() const
Return dimension of the vector space.
Definition: ROL_Vector.hpp:194
void allocateBoundaryExchangeVectors()
std::vector< Ptr< Vector< Real > > > leftVectors_
std::vector< Ptr< Vector< Real > > > rightVectors_
virtual Real dot(const Vector< Real > &x) const
Compute where .
void boundaryExchange(ESendRecv send_recv=SEND_AND_RECV) const
Exchange unknowns with neighboring processors.
Ptr< const PinTCommunicators > communicators_
int numOwnedSteps() const
std::vector< int > stencil_
virtual void zeroAll()
Zeros all entries of the vector, including boundary exchange fields.
virtual void zero()
Set to zero vector.
Definition: ROL_Vector.hpp:165
Defines the linear algebra or vector space interface.
Definition: ROL_Vector.hpp:78
const std::vector< int > & stencil() const
void recv(MPI_Comm comm, int rank, Vector< Real > &dest) const
void initialize(const Ptr< const PinTCommunicators > &comm, const Ptr< Vector< Real >> &localVector, int steps, const std::vector< int > &stencil)
void recvSumInto(MPI_Comm comm, int rank, Vector< Real > &dest) const
Ptr< PartitionedVector< Real > > stepVectors_
void recv(MPI_Comm comm, int rank, Vector< Real > &dest, bool sumInto) const
Ptr< PinTVector< Real > > dual_
int numOwnedVectors() const
Defines a parallel in time vector.
PinTVector(const PinTVector &v)
virtual void scale(const Real alpha)
Compute where .
bool isValidIndex(int i) const
Determine if an index is valid including the stencil.
Ptr< PinTVectorCommunication< Real > > vectorComm_
void boundaryExchangeSumInto()
Exchange unknowns with neighboring processors using summation.
void computeStepStartEnd(int steps)
virtual void applyUnary(const Elementwise::UnaryFunction< Real > &f) override
virtual Real norm() const
Returns where .
PinTVector(const Ptr< const PinTCommunicators > &comm, const Ptr< Vector< Real >> &localVector, int steps, const std::vector< int > &stencil)
Ptr< Vector< Real > > localVector_
Ptr< Vector< Real > > getRemoteBufferPtr(int i) const
virtual void axpy(const Real alpha, const Vector< Real > &x) override
Compute where .
MPI_Comm getTimeCommunicator() const
const PinTCommunicators & communicators() const
void send(MPI_Comm comm, int rank, Vector< Real > &source) const
virtual void plus(const Vector< Real > &x)
Compute , where .
MPI_Comm getSpaceCommunicator() const
MPI_Comm getParentCommunicator() const
PinTCommunicators(MPI_Comm parent, int spatialProcs)
virtual void print(std::ostream &outStream) const override