AmpTools
NormIntInterfaceMPI.cc
Go to the documentation of this file.
1 //******************************************************************************
2 // This file is part of AmpTools, a package for performing Amplitude Analysis
3 //
4 // Copyright Trustees of Indiana University 2010, all rights reserved
5 //
6 // This software written by Matthew Shepherd, Ryan Mitchell, and
7 // Hrayr Matevosyan at Indiana University, Bloomington
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions
11 // are met:
12 // 1. Redistributions of source code must retain the above copyright
13 // notice and author attribution, this list of conditions and the
14 // following disclaimer.
15 // 2. Redistributions in binary form must reproduce the above copyright
16 // notice and author attribution, this list of conditions and the
17 // following disclaimer in the documentation and/or other materials
18 // provided with the distribution.
19 // 3. Neither the name of the University nor the names of its contributors
20 // may be used to endorse or promote products derived from this software
21 // without specific prior written permission.
22 //
23 // Creation of derivative forms of this software for commercial
24 // utilization may be subject to restriction; written permission may be
25 // obtained from the Trustees of Indiana University.
26 //
27 // INDIANA UNIVERSITY AND THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES,
28 // EXPRESS OR IMPLIED. By way of example, but not limitation, INDIANA
29 // UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES OF MERCANTABILITY OR
30 // FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THIS SOFTWARE OR
31 // DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS,
32 // OR OTHER RIGHTS. Neither Indiana University nor the authors shall be
33 // held liable for any liability with respect to any claim by the user or
34 // any other party arising from use of the program.
35 //******************************************************************************
36 
37 #include <iostream>
38 
39 #include <mpi.h>
40 #include <cstring>
41 
43 
45 #include "IUAmpToolsMPI/MPITag.h"
46 
47 using namespace std;
48 
50  DataReader* accMCData,
51  const IntensityManager& intenManager ):
52 NormIntInterface( genMCData, accMCData, intenManager )
53 {
54  setupMPI();
55 }
56 
57 NormIntInterfaceMPI::NormIntInterfaceMPI( const string& normIntFile ) :
58 NormIntInterface( normIntFile )
59 {}
60 
62 
63 }
64 
65 complex< double >
66 NormIntInterfaceMPI::normInt( string amp, string conjAmp, bool forceUseCache ) const {
67 
68  // in the case that we have a free parameter, recompute the NI's in parallel
69  // note that evaluation order is important; if the NI interface comes from a file
70  // the the ampManager pointer will be NULL. We rely on hasAccessToMC to short
71  // circuit the evaluation to avoid a segmentation fault.
72  if( hasAccessToMC() && intenManager()->hasTermWithFreeParam() && !forceUseCache )
73  forceCacheUpdate( true );
74 
75  // then we can use the parent class to return the value from the
76  // updated cache
77  return NormIntInterface::normInt( amp, conjAmp, true );
78 }
79 
80 void NormIntInterfaceMPI::forceCacheUpdate( bool normIntOnly ) const {
81 
82  if( !m_isMaster ) NormIntInterface::forceCacheUpdate( normIntOnly );
83 
84  if( !normIntOnly ) sumIntegrals( kAmpInt );
85  sumIntegrals( kNormInt );
86 }
87 
88 void
89 NormIntInterfaceMPI::setupMPI()
90 {
91  MPI_Comm_rank( MPI_COMM_WORLD, &m_rank );
92  MPI_Comm_size( MPI_COMM_WORLD, &m_numProc );
93 
94  MPI_Status status;
95 
96  m_isMaster = ( m_rank == 0 );
97 
98  int totalGenEvents = 0;
99  int totalAccEvents = 0;
100 
101  if( m_isMaster ){
102 
103  for( int i = 1; i < m_numProc; ++i ){
104 
105  int thisEvents;
106 
107  // trigger sending of events from workers -- data is irrelevant
108  MPI_Send( &thisEvents, 1, MPI_INT, i, MPITag::kAcknowledge,
109  MPI_COMM_WORLD );
110 
111  // now receive actual data
112  MPI_Recv( &thisEvents, 1, MPI_INT, i, MPITag::kIntSend,
113  MPI_COMM_WORLD, &status );
114  totalGenEvents += thisEvents;
115 
116  MPI_Recv( &thisEvents, 1, MPI_INT, i, MPITag::kIntSend,
117  MPI_COMM_WORLD, &status );
118  totalAccEvents += thisEvents;
119 
120  // send acknowledgment
121  MPI_Send( &thisEvents, 1, MPI_INT, i, MPITag::kAcknowledge,
122  MPI_COMM_WORLD );
123  }
124 
125  setGenEvents( totalGenEvents );
126  setAccEvents( totalAccEvents );
127  }
128  else{
129 
130  int thisEvents;
131 
132  // if we are not the master, send generated and accepted events
133  // to master and wait for acknowledge
134 
135  // workers can beat the master to this point in the code if the master is
136  // still distributing data -- need to pause here and wait for master
137  // to signal that it is ready to accept numbers of events
138 
139  // data is irrelevant for this receive
140  MPI_Recv( &thisEvents, 1, MPI_INT, 0, MPITag::kAcknowledge, MPI_COMM_WORLD,
141  &status );
142 
143  thisEvents = numGenEvents();
144  MPI_Send( &thisEvents, 1, MPI_INT, 0, MPITag::kIntSend, MPI_COMM_WORLD );
145 
146  thisEvents = numAccEvents();
147  MPI_Send( &thisEvents, 1, MPI_INT, 0, MPITag::kIntSend, MPI_COMM_WORLD );
148 
149  MPI_Recv( &thisEvents, 1, MPI_INT, 0, MPITag::kAcknowledge, MPI_COMM_WORLD,
150  &status );
151  }
152 }
153 
154 void
155 NormIntInterfaceMPI::sumIntegrals( IntType type ) const
156 {
157  // first collect integrals from all nodes -- const cast is bad
158  // but we're going to reset the memory in the NormIntInterface
159  // at the end of this routine. This avoids copying.
160 
161  GDouble* integrals =
162  const_cast< GDouble* >( type == kNormInt ? normIntMatrix() : ampIntMatrix() );
163 
164  // scale up the integrals
165  for( int i = 0; i < cacheSize(); ++i ) integrals[i] *= numGenEvents();
166 
167  GDouble* result = new GDouble[cacheSize()];
168 
169  // zero out the result array
170  if( m_isMaster ) memset( integrals, 0, cacheSize() * sizeof( GDouble ) );
171 
172  // at this point, the master should be holding an array full of zeroes
173  // and other nodes will hold integrals for their subsets of data
174 
175  // sum over all nodes and distribute results to each
176  MPI_Datatype t =
177  ( sizeof( GDouble ) == sizeof( double ) ? MPI_DOUBLE : MPI_FLOAT );
178  MPI_Allreduce( integrals, result, cacheSize(), t, MPI_SUM, MPI_COMM_WORLD );
179 
180  // now broadcast the total number of events from the master to the
181  // workers so that they may renormalize the sum properly
182  int totalEvents = numGenEvents();
183  MPI_Bcast( &totalEvents, 1, MPI_INT, 0, MPI_COMM_WORLD );
184 
185  // and renormalize the sum
186  for( int i = 0; i < cacheSize(); ++i ) result[i] /= totalEvents;
187 
188  // reset the memory in the parent class
189  if( type == kNormInt ){
190 
191  setNormIntMatrix( result );
192  }
193  else{
194 
195  setAmpIntMatrix( result );
196  }
197 
198  delete[] result;
199 }
int numAccEvents() const
int cacheSize() const
virtual complex< double > normInt(string amp, string conjAmp, bool forceUseCache=false) const
const IntensityManager * intenManager() const
double GDouble
virtual void forceCacheUpdate(bool normIntOnly=false) const
complex< double > normInt(string amp, string conjAmp, bool forceUseCache=false) const
void forceCacheUpdate(bool normIntOnly=false) const
bool hasAccessToMC() const
void setAccEvents(int events)
void setGenEvents(int events)
const GDouble * normIntMatrix() const
const GDouble * ampIntMatrix() const
void setAmpIntMatrix(const double *input) const
NormIntInterfaceMPI(const string &normIntFile)
int numGenEvents() const
void setNormIntMatrix(const double *input) const