AmpTools
ParameterManagerMPI.cc
Go to the documentation of this file.
1 
2 #include <mpi.h>
3 #include <sstream>
4 
5 //******************************************************************************
6 // This file is part of AmpTools, a package for performing Amplitude Analysis
7 //
8 // Copyright Trustees of Indiana University 2010, all rights reserved
9 //
10 // This software written by Matthew Shepherd, Ryan Mitchell, and
11 // Hrayr Matevosyan at Indiana University, Bloomington
12 //
13 // Redistribution and use in source and binary forms, with or without
14 // modification, are permitted provided that the following conditions
15 // are met:
16 // 1. Redistributions of source code must retain the above copyright
17 // notice and author attribution, this list of conditions and the
18 // following disclaimer.
19 // 2. Redistributions in binary form must reproduce the above copyright
20 // notice and author attribution, this list of conditions and the
21 // following disclaimer in the documentation and/or other materials
22 // provided with the distribution.
23 // 3. Neither the name of the University nor the names of its contributors
24 // may be used to endorse or promote products derived from this software
25 // without specific prior written permission.
26 //
27 // Creation of derivative forms of this software for commercial
28 // utilization may be subject to restriction; written permission may be
29 // obtained from the Trustees of Indiana University.
30 //
31 // INDIANA UNIVERSITY AND THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES,
32 // EXPRESS OR IMPLIED. By way of example, but not limitation, INDIANA
33 // UNIVERSITY MAKES NO REPRESENTATIONS OR WARRANTIES OF MERCANTABILITY OR
34 // FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THIS SOFTWARE OR
35 // DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS,
36 // OR OTHER RIGHTS. Neither Indiana University nor the authors shall be
37 // held liable for any liability with respect to any claim by the user or
38 // any other party arising from use of the program.
39 //******************************************************************************
40 
42 #include "IUAmpToolsMPI/MPITag.h"
43 
46  IntensityManager* intenManager ) :
47 ParameterManager( minuitManager, intenManager )
48 {
49  setupMPI();
50 
51  if( !m_isMaster ){
52 
53  cerr << "Instance of MinuitMinimizationManager exists on worker node"
54  << endl;
55 
56  assert( false );
57  }
58 }
59 
62  const vector<IntensityManager*>& intenManagers ) :
63 ParameterManager( minuitManager, intenManagers )
64 {
65  setupMPI();
66 
67  if( !m_isMaster ){
68 
69  cerr << "Instance of MinuitMinimizationManager exists on worker node"
70  << endl;
71 
72  assert( false );
73  }
74 }
75 
78 ParameterManager( intenManager ),
79 m_intenManagers( 0 )
80 {
81  setupMPI();
82 
83  if( m_isMaster ){
84 
85  cerr << "Master ParameterManager has no MinuitMinimizationManager"
86  << endl;
87 
88  assert( false );
89  }
90 
91  m_intenManagers.push_back( intenManager );
92 }
93 
95 ParameterManagerMPI( const vector< IntensityManager* >& intenManagers ) :
96 ParameterManager( intenManagers ),
97 m_intenManagers( intenManagers )
98 {
99  setupMPI();
100 
101  if( m_isMaster ){
102 
103  cerr << "Master ParameterManager has no MinuitMinimizationManager"
104  << endl;
105 
106  assert( false );
107  }
108 }
109 
111 {
112 
113  // we need to deallocate the memory on the worker nodes that
114  // was used to hold the parameter values
115 
116  if( !m_isMaster ){
117 
118  for( map< string, complex< double >* >::iterator mapItr = m_prodParMap.begin();
119  mapItr != m_prodParMap.end();
120  ++mapItr )
121  delete mapItr->second;
122 
123  for( map< string, double* >::iterator mapItr = m_ampParMap.begin();
124  mapItr != m_ampParMap.end();
125  ++mapItr )
126  delete mapItr->second;
127  }
128 }
129 
130 void
131 ParameterManagerMPI::setupMPI()
132 {
133  MPI_Comm_rank( MPI_COMM_WORLD, &m_rank );
134  MPI_Comm_size( MPI_COMM_WORLD, &m_numProc );
135 
136  m_isMaster = ( m_rank == 0 );
137 }
138 
139 void ParameterManagerMPI::addProductionParameter( const string& termName,
140  bool real, bool fixed )
141 {
142 
143  if( m_isMaster ){
144 
145  // utilize the base class functionality for the master node
146  ParameterManager::addProductionParameter( termName, real, fixed );
147 
148  // then use member data to hang onto a pointer to the complex number
149  m_prodParMap[ termName ] = getProdParPtr( termName );
150  }
151  else {
152 
153  // find the Amplitude Manager that has this amplitude
154 
155  vector< IntensityManager* >::iterator intenManPtr = m_intenManagers.begin();
156  for( ; intenManPtr != m_intenManagers.end(); ++intenManPtr ){
157  if( (*intenManPtr)->hasTerm( termName ) ) break;
158  }
159 
160  if( intenManPtr == m_intenManagers.end() ){
161 
162  cout << "ParameterManager ERROR: Could not find production amplitude for "
163  << termName << endl;
164  assert( false );
165  }
166 
167  // now allocate memory to hold the parameter values on the worker nodes
168  // initialize with the inital value from the amplitude manager.
169 
170  m_prodParMap[termName] =
171  new complex< double >( (**intenManPtr).productionFactor( termName ) );
172 
173  // and tell the amplitude manager to look to this memory for updates
174  (**intenManPtr).setExternalProductionFactor( termName,
175  m_prodParMap[termName] );
176  }
177 }
178 
179 void ParameterManagerMPI::addAmplitudeParameter( const string& termName,
180  const ParameterInfo* parInfo )
181 {
182 
183  const string& parName = parInfo->parName();
184 
185  if( m_isMaster ){
186 
187  // utilize the base class functionality for the master node
188  ParameterManager::addAmplitudeParameter( termName, parInfo );
189 
190  // then use member data to hang onto a pointer to the double
191  m_ampParMap[parName] = getAmpParPtr( parName );
192  }
193  else{
194 
195  // if this is a new parameter, we need to allocate memory for it
196  if( m_ampParMap.find( parName ) == m_ampParMap.end() ){
197 
198  // need to allocate memory for this parameter
199  m_ampParMap[parName] = new double( parInfo->value() );
200  }
201 
202  // now tell amplitudes to look to this memory for the value
203  bool foundOne = false;
204  vector< IntensityManager* >::iterator intenManPtr = m_intenManagers.begin();
205  for( ; intenManPtr != m_intenManagers.end(); ++intenManPtr ){
206 
207  if( !(*intenManPtr)->hasTerm( termName ) ) continue;
208 
209  foundOne = true;
210 
211  if( parInfo->fixed() ){
212 
213  // if it is fixed just go ahead and set the parameter by value
214  // this prevents Amplitude class from thinking that is has
215  // a free parameter
216 
217  (**intenManPtr).setParValue( termName, parName, parInfo->value() );
218  }
219  else{
220 
221  (**intenManPtr).setParPtr( termName, parName, m_ampParMap[parName] );
222  }
223  }
224 
225  if( !foundOne ){
226 
227  cout << "WARNING: could not find term named " << termName
228  << " while trying to set parameter " << parName << endl;
229  }
230  }
231 }
232 
233 
235 {
236  // pointers to parameters are stored in maps on both the
237  // master and worker nodes -- these maps contain the
238  // same keys and should be sorted in the same way
239  //
240  // iterate over the map and pack an array and then broadcast
241  // this from the master to the workers, then copy back
242  // out of the array into the map on the workers
243 
244  double* parData = new double[2*m_prodParMap.size()+m_ampParMap.size()];
245 
246  int i = 0;
247  for( map< string, complex< double >* >::iterator
248  parItr = m_prodParMap.begin();
249  parItr != m_prodParMap.end();
250  ++parItr ) {
251 
252  parData[i++] = real( *(parItr->second) );
253  parData[i++] = imag( *(parItr->second) );
254  }
255 
256  for( map< string, double* >::iterator
257  parItr = m_ampParMap.begin();
258  parItr != m_ampParMap.end();
259  ++parItr ) {
260 
261  parData[i++] = *(parItr->second);
262  }
263 
264  MPI_Bcast( parData, i, MPI_DOUBLE, 0, MPI_COMM_WORLD );
265 
266  if( !m_isMaster ){
267 
268  i = 0;
269  for( map< string, complex< double >* >::iterator
270  parItr = m_prodParMap.begin();
271  parItr != m_prodParMap.end();
272  ++parItr ) {
273 
274  (*(parItr->second)) = complex< double >( parData[i],
275  parData[i+1] );
276  i += 2;
277  }
278 
279  for( map< string, double* >::iterator
280  parItr = m_ampParMap.begin();
281  parItr != m_ampParMap.end();
282  ++parItr ) {
283 
284  (*(parItr->second)) = parData[i++];
285  }
286  }
287 
288  delete[] parData;
289 }
290 
291 
292 void ParameterManagerMPI::updateAmpParameter( const string& parName )
293 {
294 
295  int nameLength;
296  char parNameArr[kMaxNameLength];
297  double value;
298 
299  MPI_Status status;
300 
301  if( m_isMaster ){
302 
303  map< string, double* >::iterator parItr =
304  m_ampParMap.find( parName );
305 
306  // we should *always* be able to find the parameter with the
307  // the appropriate name
308  assert( parItr != m_ampParMap.end() );
309 
310  nameLength = parItr->first.length();
311  assert( nameLength <= kMaxNameLength );
312  strcpy( parNameArr, parItr->first.c_str() );
313 
314  MPI_Bcast( &nameLength, 1, MPI_INT, 0, MPI_COMM_WORLD );
315  MPI_Bcast( parNameArr, nameLength, MPI_CHAR, 0, MPI_COMM_WORLD );
316 
317  value = *(parItr->second);
318 
319  MPI_Bcast( &value, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD );
320 
321  }
322  else{
323 
324  MPI_Bcast( &nameLength, 1, MPI_INT, 0, MPI_COMM_WORLD );
325  MPI_Bcast( parNameArr, nameLength, MPI_CHAR, 0, MPI_COMM_WORLD );
326  MPI_Bcast( &value, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD );
327 
328  ostringstream name;
329  for( int i = 0; i < nameLength; ++i ) name << parNameArr[i];
330 
331  // check that the name is sane and the reset the value
332  map< string, double* >::iterator parItr = m_ampParMap.find( name.str() );
333  assert( parItr != m_ampParMap.end() );
334  (*(parItr->second)) = value;
335 
336  // now we need to trigger the update method using the base class
337  // this will call the update routines in the individual amplitudes
338 
339  ParameterManager::update( name.str() );
340  }
341 }
342 
343 void
344 ParameterManagerMPI::update( const string& parName ){
345 
346  // should only be called directly on the master via
347  // the call to virtual ParameterManager::update
348 
349  assert( m_isMaster );
350 
351  // this puts workers into the updateAmpParameter routine above
353 
354  // now put the master there
355  updateAmpParameter( parName );
356 }
357 
bool fixed() const
double * getAmpParPtr(const string &parName)
void updateAmpParameter(const string &parName="")
double value() const
static void broadcastToFirst(FitCommand command)
void addAmplitudeParameter(const string &termName, const ParameterInfo *parInfo)
virtual void addAmplitudeParameter(const string &ampName, const ParameterInfo *parInfo)
void addProductionParameter(const string &termName, bool real=false, bool fixed=false)
void update(const MISubject *parPtr)
virtual void addProductionParameter(const string &ampName, bool real=false, bool fixed=false)
string parName() const
complex< double > * getProdParPtr(const string &ampName)
ParameterManagerMPI(MinuitMinimizationManager *minuitManager, IntensityManager *intenManager)
void update(const string &parName)