laura is hosted by Hepforge, IPPP Durham
Laura++  v3r5
A maximum likelihood fitting package for performing Dalitz-plot analysis.
LauSimFitMaster.cc
Go to the documentation of this file.
1 
2 /*
3 Copyright 2013 University of Warwick
4 
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8 
9  http://www.apache.org/licenses/LICENSE-2.0
10 
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 */
17 
18 /*
19 Laura++ package authors:
20 John Back
21 Paul Harrison
22 Thomas Latham
23 */
24 
29 #include <cstdlib>
30 #include <iostream>
31 #include <limits>
32 
33 #include "TMath.h"
34 #include "TMatrixD.h"
35 #include "TMessage.h"
36 #include "TMonitor.h"
37 #include "TObjArray.h"
38 #include "TObjString.h"
39 #include "TServerSocket.h"
40 #include "TSocket.h"
41 #include "TSystem.h"
42 
43 #include "LauAbsFitter.hh"
44 #include "LauFitNtuple.hh"
45 #include "LauFitter.hh"
46 #include "LauFormulaPar.hh"
47 #include "LauParameter.hh"
48 #include "LauParamFixed.hh"
49 #include "LauSimFitMaster.hh"
50 
51 
53 
54 
55 LauSimFitMaster::LauSimFitMaster( UInt_t numSlaves, UInt_t port ) :
56  nSlaves_(numSlaves),
57  reqPort_(port),
58  socketMonitor_(0),
59  messageFromSlave_(0),
60  fitNtuple_(0)
61 {
62  messagesToSlaves_.resize( nSlaves_ );
63  for ( UInt_t iSlave(0); iSlave < nSlaves_; ++iSlave ) {
64  messagesToSlaves_[iSlave] = new TMessage();
65  }
66 }
67 
69 {
70  delete socketMonitor_; socketMonitor_ = 0;
71 
72  // Tell all slaves that they are finished and delete corresponding socket
73  TString msgStr("Finish");
74  TMessage message( kMESS_STRING );
75  message.WriteTString(msgStr);
76  for ( std::vector<TSocket*>::iterator iter = sSlaves_.begin(); iter != sSlaves_.end(); ++iter ) {
77  (*iter)->Send(message);
78  (*iter)->Close();
79  delete (*iter);
80  }
81  sSlaves_.clear();
82 
83  // Remove the components created to apply constraints to fit parameters
84  for (std::vector<LauAbsRValue*>::iterator iter = conVars_.begin(); iter != conVars_.end(); ++iter){
85  if ( !(*iter)->isLValue() ){
86  delete (*iter);
87  (*iter) = 0;
88  }
89  }
90  conVars_.clear();
91 
92  // Remove all fit parameters
93  for ( std::vector<LauParameter*>::iterator iter = params_.begin(); iter != params_.end(); ++iter ) {
94  delete *iter;
95  }
96  params_.clear();
97 
98  for ( std::vector<Double_t*>::iterator iter = vectorPar_.begin(); iter != vectorPar_.end(); ++iter ) {
99  delete[] (*iter);
100  }
101  vectorPar_.clear();
102 
104 
105  for ( std::vector<TMessage*>::iterator iter = messagesToSlaves_.begin(); iter != messagesToSlaves_.end(); ++iter ) {
106  delete (*iter);
107  }
108  messagesToSlaves_.clear();
109 
110  delete fitNtuple_;
111 }
112 
114 {
115  if ( socketMonitor_ != 0 ) {
116  std::cerr << "ERROR in LauSimFitMaster::initSockets : Sockets already initialised." << std::endl;
117  return;
118  }
119 
120  //initialise socket connection, then accept a connection and return a full-duplex communication socket.
121  socketMonitor_ = new TMonitor();
122 
123  TServerSocket *ss = new TServerSocket( reqPort_, kFALSE );
124  UInt_t actual_port = ss->GetLocalPort();
125 
126  std::cout << "INFO in LauSimFitMaster::initSockets : Waiting for connection with " << nSlaves_ << " workers on port " << actual_port << std::endl;
127 
128  sSlaves_.resize(nSlaves_);
129  for ( UInt_t iSlave(0); iSlave<nSlaves_; ++iSlave ) {
130  sSlaves_[iSlave] = ss->Accept();
131  std::cout << " : Added slave " << iSlave << std::endl;
132  }
133 
134  // tell the clients to start
135  std::cout << "INFO in LauSimFitMaster::initSockets : Initialising slaves" << std::endl;
136  for ( UInt_t iSlave(0); iSlave<nSlaves_; ++iSlave ) {
137 
138  TMessage message( kMESS_ANY );
139  message.WriteUInt(iSlave);
140  message.WriteUInt(nSlaves_);
141  message.WriteBool(this->useAsymmFitErrors());
142 
143  sSlaves_[iSlave]->Send(message);
144 
145  socketMonitor_->Add(sSlaves_[iSlave]);
146  }
147  std::cout << " : Now start fit\n" << std::endl;
148 
149  ss->Close();
150  delete ss;
151 }
152 
153 /*
154  * OLD VERSION THAT JUST GETS THE NAMES - COULD HAVE A SERIES OF EXCHANGES TO GET THE NAMES, INIT VALUES, RANGES, ETC. INSTEAD OF PASSING PARAMETERS
155  * THIS INCREASES THE GENERALITY OF THE CODE, I.E. THERE IS NO NEED FOR THE SLAVES TO KNOW ANY LAURA++ CLASS BUT THIS ONE, BUT MAKES IT RATHER MORE DENSE
156  * FOR THE MOMENT I WILL STICK WITH THE METHOD OF PASSING LAUPARAMETER OBJECTS AROUND AND CONSIDER GOING BACK TO THIS GENERAL METHOD ONCE EVERYTHING IS WORKING
157  *
158 void LauSimFitMaster::getParametersFromSlavesFirstTime()
159 {
160  slaveIndices_.resize( nSlaves_ );
161 
162  TSocket* sActive(0);
163  for ( UInt_t iSlave(0); iSlave<nSlaves_; ++iSlave ) {
164  // Send a message to the slave, requesting the list of parameter names
165  TString msgStr = "Parameter Names";
166  TMessage message( kMESS_STRING );
167  message.WriteTString( msgStr );
168  sSlaves_[iSlave]->Send(message);
169 
170  // Wait to receive the response and check that it has come from the slave we just requested from
171  sActive = socketMonitor_->Select();
172  if ( sActive != sSlaves_[iSlave] ) {
173  std::cerr << "ERROR in LauSimFitMaster::getParametersFromSlavesFirstTime : Received message from a different slave than expected!" << std::endl;
174  gSystem->Exit(1);
175  }
176 
177  // Read the object and extract the parameter names
178  sSlaves_[iSlave]->Recv( messageFromSlave_ );
179  TObjArray * objarray = dynamic_cast<TObjArray*>( messageFromSlave_->ReadObject( messageFromSlave_->GetClass() ) );
180  if ( ! objarray ) {
181  std::cerr << "ERROR in LauSimFitMaster::getParametersFromSlavesFirstTime : Error reading parameter names from slave" << std::endl;
182  gSystem->Exit(1);
183  }
184 
185  Int_t nPars = objarray->GetEntries();
186  for ( Int_t iPar(0); iPar < nPars; ++iPar ) {
187  TObjString* objstring = dynamic_cast<TObjString*>( (*objarray)[iPar] );
188  if ( ! objstring ) {
189  std::cerr << "ERROR in LauSimFitMaster::getParametersFromSlavesFirstTime : Error reading parameter names from slave" << std::endl;
190  gSystem->Exit(1);
191  }
192  TString parname = objstring->GetString();
193 
194  std::map< TString, UInt_t >::iterator iter = parIndices_.find( parname );
195  if ( iter != parIndices_.end() ) {
196  UInt_t index = iter->second;
197  slaveIndices_[iSlave].push_back( index );
198  } else {
199  UInt_t index = parIndices_.size();
200  parIndices_.insert( std::make_pair( parname, index ) );
201  parNames_.insert( std::make_pair( index, parname ) );
202  slaveIndices_[iSlave].push_back( index );
203  }
204  }
205 
206  delete objarray; objarray = 0;
207  delete messageFromSlave_; messageFromSlave_ = 0;
208  }
209 
210  UInt_t nPars = parNames_.size();
211  parValues_.resize( nPars );
212 }
213 */
214 
216 {
217  if ( socketMonitor_ == 0 ) {
218  std::cerr << "ERROR in LauSimFitMaster::getParametersFromSlaves : Sockets not initialised." << std::endl;
219  return;
220  }
221 
222  if ( params_.empty() ) {
224 
225  // Add variables to Gaussian constrain to a list
226  this->addConParameters();
227  } else {
229  }
230 }
231 
233 {
234  TSocket* sActive(0);
235 
236  // Construct a message, requesting the list of parameter names
237  TString msgStr = "Send Parameters";
238  TMessage message( kMESS_STRING );
239  message.WriteTString( msgStr );
240 
241  for ( UInt_t iSlave(0); iSlave<nSlaves_; ++iSlave ) {
242  // Send the message to the slave
243  sSlaves_[iSlave]->Send(message);
244 
245  // Wait to receive the response and check that it has come from the slave we just requested from
246  sActive = socketMonitor_->Select();
247  if ( sActive != sSlaves_[iSlave] ) {
248  std::cerr << "ERROR in LauSimFitMaster::updateParametersFromSlaves : Received message from a different slave than expected!" << std::endl;
249  gSystem->Exit(1);
250  }
251 
252  // Read the object and extract the parameter names
253  sSlaves_[iSlave]->Recv( messageFromSlave_ );
254  TObjArray * objarray = dynamic_cast<TObjArray*>( messageFromSlave_->ReadObject( messageFromSlave_->GetClass() ) );
255  if ( ! objarray ) {
256  std::cerr << "ERROR in LauSimFitMaster::updateParametersFromSlaves : Error reading parameter names from slave" << std::endl;
257  gSystem->Exit(1);
258  }
259 
260  // We want to auto-delete the supplied parameters since we only copy their values in this case
261  objarray->SetOwner(kTRUE);
262 
263  const UInt_t nPars = objarray->GetEntries();
264  if ( nPars != slaveIndices_[iSlave].size() ) {
265  std::cerr << "ERROR in LauSimFitMaster::updateParametersFromSlaves : Unexpected number of parameters received from slave" << std::endl;
266  gSystem->Exit(1);
267  }
268 
269  for ( UInt_t iPar(0); iPar < nPars; ++iPar ) {
270  LauParameter* parameter = dynamic_cast<LauParameter*>( (*objarray)[iPar] );
271  if ( ! parameter ) {
272  std::cerr << "ERROR in LauSimFitMaster::updateParametersFromSlaves : Error reading parameter from slave" << std::endl;
273  gSystem->Exit(1);
274  }
275 
276  TString parname = parameter->name();
277  Double_t parvalue = parameter->initValue();
278 
279  std::map< TString, UInt_t >::iterator iter = parIndices_.find( parname );
280  if ( iter == parIndices_.end() ) {
281  std::cerr << "ERROR in LauSimFitMaster::updateParametersFromSlaves : Unexpected parameter name received from slave" << std::endl;
282  gSystem->Exit(1);
283  }
284 
285  const UInt_t index = iter->second;
286  if ( slaveIndices_[iSlave][iPar] != index ) {
287  std::cerr << "ERROR in LauSimFitMaster::updateParametersFromSlaves : Unexpected parameter received from slave" << std::endl;
288  gSystem->Exit(1);
289  }
290 
291  params_[index]->initValue( parvalue );
292  parValues_[index] = parvalue;
293  vectorPar_[iSlave][iPar] = parvalue;
294  this->checkParameter( parameter, index );
295  }
296 
297  delete objarray; objarray = 0;
299  }
300 }
301 
303 {
304  slaveIndices_.resize( nSlaves_ );
305  slaveFreeIndices_.resize( nSlaves_ );
306  vectorPar_.resize( nSlaves_ );
307  vectorRes_.resize( nSlaves_ );
308 
309  TSocket* sActive(0);
310 
311  // Construct a message, requesting the list of parameter names
312  TString msgStr = "Send Parameters";
313  TMessage message( kMESS_STRING );
314  message.WriteTString( msgStr );
315 
316  for ( UInt_t iSlave(0); iSlave<nSlaves_; ++iSlave ) {
317  // Send the message to the slave
318  sSlaves_[iSlave]->Send(message);
319 
320  // Wait to receive the response and check that it has come from the slave we just requested from
321  sActive = socketMonitor_->Select();
322  if ( sActive != sSlaves_[iSlave] ) {
323  std::cerr << "ERROR in LauSimFitMaster::getParametersFromSlavesFirstTime : Received message from a different slave than expected!" << std::endl;
324  gSystem->Exit(1);
325  }
326 
327  // Read the object and extract the parameter names
328  sSlaves_[iSlave]->Recv( messageFromSlave_ );
329  TObjArray * objarray = dynamic_cast<TObjArray*>( messageFromSlave_->ReadObject( messageFromSlave_->GetClass() ) );
330  if ( ! objarray ) {
331  std::cerr << "ERROR in LauSimFitMaster::getParametersFromSlavesFirstTime : Error reading parameters from slave" << std::endl;
332  gSystem->Exit(1);
333  }
334 
335  const UInt_t nPars = objarray->GetEntries();
336 
337  vectorPar_[iSlave] = new Double_t[nPars];
338 
339  for ( UInt_t iPar(0); iPar < nPars; ++iPar ) {
340  LauParameter* parameter = dynamic_cast<LauParameter*>( (*objarray)[iPar] );
341  if ( ! parameter ) {
342  std::cerr << "ERROR in LauSimFitMaster::getParametersFromSlavesFirstTime : Error reading parameter from slave" << std::endl;
343  gSystem->Exit(1);
344  }
345 
346  TString parname = parameter->name();
347  Double_t parvalue = parameter->initValue();
348  Bool_t parfixed = parameter->fixed();
349 
350  std::map< TString, UInt_t >::iterator iter = parIndices_.find( parname );
351  if ( iter != parIndices_.end() ) {
352  UInt_t index = iter->second;
353  slaveIndices_[iSlave].push_back( index );
354  if ( ! parfixed ) {
355  slaveFreeIndices_[iSlave].push_back( index );
356  }
357  this->checkParameter( parameter, index );
358  } else {
359  UInt_t index = parIndices_.size();
360  parIndices_.insert( std::make_pair( parname, index ) );
361  parNames_.insert( std::make_pair( index, parname ) );
362  slaveIndices_[iSlave].push_back( index );
363  if ( ! parfixed ) {
364  slaveFreeIndices_[iSlave].push_back( index );
365  }
366  params_.push_back( parameter );
367  parValues_.push_back( parvalue );
368  }
369  vectorPar_[iSlave][iPar] = parvalue;
370  }
371 
372  delete objarray; objarray = 0;
374  }
375 }
376 
378 {
379  for ( UInt_t iSlave(0); iSlave<nSlaves_; ++iSlave ) {
380  const std::vector<UInt_t>& indices = slaveIndices_[iSlave];
381 
382  std::cout << "INFO in LauSimFitMaster::printParInfo : Slave " << iSlave << " has the following parameters:\n";
383  for ( std::vector<UInt_t>::const_iterator iter = indices.begin(); iter != indices.end(); ++iter ) {
384  const TString& parName = parNames_.find(*iter)->second;
385  Double_t parValue = parValues_[*iter];
386  const LauParameter* par = params_[*iter];
387  if ( par->name() != parName || par->initValue() != parValue ) {
388  std::cerr << "ERROR in LauSimFitMaster::printParInfo : Discrepancy in parameter name and value records, this is very strange!!" << std::endl;
389  }
390 
391  std::cout << " : " << parName << " = " << parValue << " and has index " << *iter << "\n";
392  }
393 
394  std::cout << std::endl;
395  }
396 
397  std::cout << "INFO in LauSimFitMaster::printParInfo : " << "There are " << params_.size() << " parameters in total" << std::endl;
398 }
399 
400 void LauSimFitMaster::checkParameter( const LauParameter* param, UInt_t index ) const
401 {
402  const LauParameter* storedPar = params_[index];
403 
404  TString parName = storedPar->name();
405  if ( param->name() != parName ) {
406  std::cerr << "ERROR in LauSimFitMaster::checkParameter : Parameter name is different!! This shouldn't happen!!" << std::endl;
407  }
408  if ( param->initValue() != storedPar->initValue() ) {
409  std::cerr << "WARNING in LauSimFitMaster::checkParameter : Initial value for parameter " << parName << " is different, will use the value first set: " << storedPar->initValue() << std::endl;
410  }
411  if ( param->minValue() != storedPar->minValue() ) {
412  std::cerr << "WARNING in LauSimFitMaster::checkParameter : Minimum allowed value for parameter " << parName << " is different, will use the value first set: " << storedPar->minValue() << std::endl;
413  }
414  if ( param->maxValue() != storedPar->maxValue() ) {
415  std::cerr << "WARNING in LauSimFitMaster::checkParameter : Maximum allowed value for parameter " << parName << " is different, will use the value first set: " << storedPar->maxValue() << std::endl;
416  }
417  if ( param->fixed() != storedPar->fixed() ) {
418  std::cerr << "WARNING in LauSimFitMaster::checkParameter : Fixed/floating property of parameter " << parName << " is different, will use the value first set: " << (storedPar->fixed() ? "fixed" : "floating") << std::endl;
419  }
420  if ( param->secondStage() != storedPar->secondStage() ) {
421  std::cerr << "WARNING in LauSimFitMaster::checkParameter : Second stage property of parameter " << parName << " is different, will use the value first set: " << (storedPar->secondStage() ? "true" : "false") << std::endl;
422  }
423 }
424 
426 {
427  this->initSockets();
428 }
429 
430 void LauSimFitMaster::runSimFit( const TString& fitNtupleFileName, const UInt_t nExp, const UInt_t firstExp, const Bool_t useAsymmErrors, const Bool_t doTwoStageFit )
431 {
432  // Routine to perform the total fit.
433 
434  // First, initialise
435  this->useAsymmFitErrors(useAsymmErrors);
436  this->twoStageFit(doTwoStageFit);
437  this->initialise();
438 
439  std::cout << "INFO in LauSimFitMaster::runSimFit : First experiment = " << firstExp << std::endl;
440  std::cout << "INFO in LauSimFitMaster::runSimFit : Number of experiments = " << nExp << std::endl;
441 
442  // Start the cumulative timer
443  cumulTimer_.Start();
444 
445  this->resetFitCounters();
446 
447  // Create and setup the fit results ntuple
448  std::cout << "INFO in LauSimFitMaster::runSimFit : Creating fit ntuple." << std::endl;
449  if (fitNtuple_ != 0) {delete fitNtuple_; fitNtuple_ = 0;}
450  fitNtuple_ = new LauFitNtuple(fitNtupleFileName, useAsymmErrors);
451 
452  // Loop over the number of experiments
453  for (UInt_t iExp = firstExp; iExp < (firstExp+nExp); ++iExp) {
454 
455  // Start the timer to see how long each fit takes
456  timer_.Start();
457 
458  this->setCurrentExperiment( iExp );
459 
460  // Instruct the slaves to read the data for this experiment
461  Bool_t readOK = this->readData();
462  if ( ! readOK ) {
463  std::cerr << "ERROR in LauSimFitMaster::runSimFit : One or more slaves reported problems with reading data for experiment " << iExp << ", skipping..." << std::endl;
464  timer_.Stop();
465  continue;
466  }
467 
468  // Instruct the slaves to perform the caching
469  this->cacheInputData();
470 
471  // Do the fit
472  this->fitExpt();
473 
474  // Stop the timer and see how long the program took so far
475  timer_.Stop();
476  timer_.Print();
477 
478  // Instruct the slaves to finalise the results
479  this->finalise();
480  }
481 
482  // Print out total timing info.
483  std::cout << "INFO in LauSimFitMaster::runSimFit : Cumulative timing:" << std::endl;
484  cumulTimer_.Stop();
485  cumulTimer_.Print();
486 
487  // Print out stats on OK fits.
488  const UInt_t nOKFits = this->numberOKFits();
489  const UInt_t nBadFits = this->numberBadFits();
490  std::cout << "INFO in LauSimFitMaster::runSimFit : Number of OK Fits = " << nOKFits << std::endl;
491  std::cout << "INFO in LauSimFitMaster::runSimFit : Number of Failed Fits = " << nBadFits << std::endl;
492  Double_t fitEff(0.0);
493  if (nExp != 0) {fitEff = nOKFits/(1.0*nExp);}
494  std::cout << "INFO in LauSimFitMaster::runSimFit : Fit efficiency = " << fitEff*100.0 << "%." << std::endl;
495 
496  // Instruct the slaves to write out any fit results (ntuples etc...).
497  this->writeOutResults();
498 }
499 
500 void LauSimFitMaster::withinAsymErrorCalc(const Bool_t inAsymErrCalc)
501 {
502  this->LauFitObject::withinAsymErrorCalc(inAsymErrCalc);
503 
504  if ( socketMonitor_ == 0 ) {
505  std::cerr << "ERROR in LauSimFitMaster::withinAsymErrorCalc : Sockets not initialised." << std::endl;
506  return;
507  }
508 
509  // Construct a message, informing the slaves whether or not we are now within the asymmetric error calculation
510  TString msgStr("Asym Error Calc");
511  const Bool_t asymErrorCalc( this->withinAsymErrorCalc() );
512  TMessage message( kMESS_STRING );
513  message.WriteTString( msgStr );
514  message.WriteBool( asymErrorCalc );
515 
516  // Send the message to the slaves
517  for ( UInt_t iSlave(0); iSlave<nSlaves_; ++iSlave ) {
518  sSlaves_[iSlave]->Send(message);
519  }
520 
521  TSocket* sActive(0);
522  UInt_t responsesReceived(0);
523  while ( responsesReceived != nSlaves_ ) {
524 
525  // Get the next queued response
526  sActive = socketMonitor_->Select();
527 
528  // Extract from the message the ID of the slave and the number of events read
529  Bool_t response(kTRUE);
530  UInt_t iSlave(0);
531  sActive->Recv( messageFromSlave_ );
532  messageFromSlave_->ReadUInt( iSlave );
533  messageFromSlave_->ReadBool( response );
534 
535  if ( response != asymErrorCalc ) {
536  std::cerr << "WARNING in LauSimFitMaster::withinAsymErrorCalc : Problem informing slave " << iSlave << std::endl;
537  }
538 
539  ++responsesReceived;
540  }
541 
542 }
543 
545 {
546  if ( socketMonitor_ == 0 ) {
547  std::cerr << "ERROR in LauSimFitMaster::readData : Sockets not initialised." << std::endl;
548  return kFALSE;
549  }
550 
551  // Construct a message, requesting to read the data for the given experiment
552  TString msgStr("Read Expt");
553  const UInt_t iExp( this->iExpt() );
554  TMessage message( kMESS_STRING );
555  message.WriteTString( msgStr );
556  message.WriteUInt( iExp );
557 
558  // Send the message to the slaves
559  for ( UInt_t iSlave(0); iSlave<nSlaves_; ++iSlave ) {
560  sSlaves_[iSlave]->Send(message);
561  }
562 
563  TSocket* sActive(0);
564  UInt_t responsesReceived(0);
565  Bool_t ok(kTRUE);
566  while ( responsesReceived != nSlaves_ ) {
567 
568  // Get the next queued response
569  sActive = socketMonitor_->Select();
570 
571  // Extract from the message the ID of the slave and the number of events read
572  sActive->Recv( messageFromSlave_ );
573  UInt_t iSlave(0);
574  UInt_t nEvents(0);
575  messageFromSlave_->ReadUInt( iSlave );
576  messageFromSlave_->ReadUInt( nEvents );
577 
578  if ( nEvents <= 0 ) {
579  std::cerr << "ERROR in LauSimFitMaster::readData : Slave " << iSlave << " reports no events found for experiment " << iExp << std::endl;
580  ok = kFALSE;
581  } else {
582  std::cerr << "INFO in LauSimFitMaster::readData : Slave " << iSlave << " reports " << nEvents << " events found for experiment " << iExp << std::endl;
583  }
584 
585  ++responsesReceived;
586  }
587 
588  return ok;
589 }
590 
592 {
593  if ( socketMonitor_ == 0 ) {
594  std::cerr << "ERROR in LauSimFitMaster::cacheInputData : Sockets not initialised." << std::endl;
595  return kFALSE;
596  }
597 
598  // Construct a message, requesting it to read the data for the given experiment
599  TString msgStr("Cache");
600  TMessage message( kMESS_STRING );
601  message.WriteTString( msgStr );
602 
603  for ( UInt_t iSlave(0); iSlave<nSlaves_; ++iSlave ) {
604  // Send the message to the slave
605  sSlaves_[iSlave]->Send(message);
606  }
607 
608  TSocket* sActive(0);
609  UInt_t responsesReceived(0);
610  Bool_t allOK(kTRUE);
611  while ( responsesReceived != nSlaves_ ) {
612 
613  // Get the next queued response
614  sActive = socketMonitor_->Select();
615 
616  // Extract from the message the ID of the slave and the success/failure flag
617  sActive->Recv( messageFromSlave_ );
618  UInt_t iSlave(0);
619  Bool_t ok(kTRUE);
620  messageFromSlave_->ReadUInt( iSlave );
621  messageFromSlave_->ReadBool( ok );
622 
623  if ( ! ok ) {
624  std::cerr << "ERROR in LauSimFitMaster::cacheInputData : Slave " << iSlave << " reports an error performing caching" << std::endl;
625  allOK = kFALSE;
626  }
627 
628  ++responsesReceived;
629  }
630 
631  return allOK;
632 }
633 
635 {
636  this->getParametersFromSlaves();
637  this->printParInfo();
638 }
639 
641 {
642  // Routine to perform the actual fit for the given experiment
643 
644  // Instruct the slaves to update initial fit parameters if required (e.g. if using random numbers).
645  this->checkInitFitParams();
646 
647  // Initialise the fitter
651 
652  this->startNewFit( LauFitter::fitter()->nParameters(), LauFitter::fitter()->nFreeParameters() );
653 
654  // Now ready for minimisation step
655  std::cout << "\nINFO in LauSimFitMaster::fitExpt : Start minimisation...\n";
657 
658  // If we're doing a two stage fit we can now release (i.e. float)
659  // the 2nd stage parameters and re-fit
660  if (this->twoStageFit()) {
661  if ( fitResult.status != 3 ) {
662  std::cerr << "ERROR in LauSimFitMaster:fitExpt : Not running second stage fit since first stage failed." << std::endl;
664  } else {
666  this->startNewFit( LauFitter::fitter()->nParameters(), LauFitter::fitter()->nFreeParameters() );
667  fitResult = LauFitter::fitter()->minimise();
668  }
669  }
670 
671  const TMatrixD& covMat = LauFitter::fitter()->covarianceMatrix();
672  this->storeFitStatus( fitResult, covMat );
673 
674  // Store the final fit results and errors into protected internal vectors that
675  // all sub-classes can use within their own finalFitResults implementation
676  // used below (e.g. putting them into an ntuple in a root file)
678 }
679 
680 void LauSimFitMaster::setParsFromMinuit(Double_t* par, Int_t npar)
681 {
682  // This function sets the internal parameters based on the values
683  // that Minuit is using when trying to minimise the total likelihood function.
684 
685  // MINOS reports different numbers of free parameters depending on the
686  // situation, so disable this check
687  if ( ! this->withinAsymErrorCalc() ) {
688  const UInt_t nFreePars = this->nFreeParams();
689  if (static_cast<UInt_t>(npar) != nFreePars) {
690  std::cerr << "ERROR in LauSimFitMaster::setParsFromMinuit : Unexpected number of free parameters: " << npar << ".\n";
691  std::cerr << " Expected: " << nFreePars << ".\n" << std::endl;
692  gSystem->Exit(EXIT_FAILURE);
693  }
694  }
695 
696  // Despite npar being the number of free parameters
697  // the par array actually contains all the parameters,
698  // free and floating...
699  // Update all the parameters with their new values.
700  // Change the value in the array to be sent out to the slaves and the
701  // parameters themselves (so that constraints are correctly calculated)
702  for (UInt_t i(0); i<this->nTotParams(); ++i) {
703  if (!params_[i]->fixed()) {
704  parValues_[i] = par[i];
705  params_[i]->value(par[i]);
706  }
707  }
708 }
709 
711 {
712  if ( socketMonitor_ == 0 ) {
713  std::cerr << "ERROR in LauSimFitMaster::getTotNegLogLikelihood : Sockets not initialised." << std::endl;
714  return 0.0;
715  }
716 
717  // Send current values of the parameters to the slaves.
718  for ( UInt_t iSlave(0); iSlave<nSlaves_; ++iSlave ) {
719 
720  std::vector<UInt_t>& indices = slaveIndices_[iSlave];
721  std::vector<UInt_t>& freeIndices = slaveFreeIndices_[iSlave];
722  UInt_t nPars = indices.size();
723  UInt_t nFreePars = freeIndices.size();
724  for ( UInt_t iPar(0); iPar < nPars; ++iPar ) {
725  vectorPar_[iSlave][iPar] = parValues_[ indices[iPar] ];
726  }
727 
728  TMessage* message = messagesToSlaves_[iSlave];
729  message->Reset( kMESS_ANY );
730  message->WriteUInt( nPars );
731  message->WriteUInt( nFreePars );
732  message->WriteFastArray( vectorPar_[iSlave], nPars );
733 
734  sSlaves_[iSlave]->Send(*message);
735  }
736 
737  Double_t negLogLike(0.0);
738  TSocket *sActive(0);
739  UInt_t responsesReceived(0);
740  Bool_t allOK(kTRUE);
741  while ( responsesReceived != nSlaves_ ) {
742 
743  sActive = socketMonitor_->Select();
744  sActive->Recv(messageFromSlave_);
745 
746  messageFromSlave_->ReadDouble( vectorRes_[responsesReceived] );
747 
748  Double_t& nLL = vectorRes_[responsesReceived];
749  if ( nLL == 0.0 || TMath::IsNaN(nLL) || !TMath::Finite(nLL) ) {
750  allOK = kFALSE;
751  }
752 
753  negLogLike += vectorRes_[responsesReceived];
754 
755  ++responsesReceived;
756  }
757 
758  // Calculate any penalty terms from Gaussian constrained variables
759  if ( ! conVars_.empty() ){
760  negLogLike += this->getLogLikelihoodPenalty();
761  }
762 
763  const Double_t worstNegLogLike = -1.0*this->worstLogLike();
764  if ( ! allOK ) {
765  std::cerr << "WARNING in LauSimFitMaster::getTotNegLogLikelihood : Strange NLL value returned by one or more slaves\n";
766  std::cerr << " : Returning worst NLL found so far to force MINUIT out of this region." << std::endl;
767  negLogLike = worstNegLogLike;
768  } else if ( negLogLike > worstNegLogLike ) {
769  this->worstLogLike( -negLogLike );
770  }
771 
772  return negLogLike;
773 }
774 
776 {
777  Double_t penalty(0.0);
778 
779  for ( std::vector<LauAbsRValue*>::const_iterator iter = conVars_.begin(); iter != conVars_.end(); ++iter ) {
780  Double_t val = (*iter)->unblindValue();
781  Double_t mean = (*iter)->constraintMean();
782  Double_t width = (*iter)->constraintWidth();
783 
784  Double_t term = ( val - mean )*( val - mean );
785  penalty += term/( 2*width*width );
786  }
787 
788  return penalty;
789 }
790 
792 {
793  // Add penalties from the constraints to fit parameters
794 
795  // First, constraints on the fit parameters themselves
796  for ( std::vector<LauParameter*>::const_iterator iter = params_.begin(); iter != params_.end(); ++iter ) {
797  if ( (*iter)->gaussConstraint() ) {
798  conVars_.push_back( *iter );
799  std::cout << "INFO in LauSimFitMaster::addConParameters : Added Gaussian constraint to parameter "<< (*iter)->name() << std::endl;
800  }
801  }
802 
803  // Second, constraints on arbitrary combinations
804  const std::vector<StoreConstraints>& storeCon = this->constraintsStore();
805  for ( std::vector<StoreConstraints>::const_iterator iter = storeCon.begin(); iter != storeCon.end(); ++iter ) {
806  const std::vector<TString>& names = (*iter).conPars_;
807  std::vector<LauParameter*> params;
808  for ( std::vector<TString>::const_iterator iternames = names.begin(); iternames != names.end(); ++iternames ) {
809  for ( std::vector<LauParameter*>::const_iterator iterfit = params_.begin(); iterfit != params_.end(); ++iterfit ) {
810  if ( (*iternames) == (*iterfit)->name() ){
811  params.push_back(*iterfit);
812  }
813  }
814  }
815 
816  // If the parameters are not found, skip it
817  if ( params.size() != (*iter).conPars_.size() ) {
818  std::cerr << "WARNING in LauSimFitMaster::addConParameters: Could not find parameters to constrain in the formula... skipping" << std::endl;
819  continue;
820  }
821 
822  LauFormulaPar* formPar = new LauFormulaPar( (*iter).formula_, (*iter).formula_, params );
823  formPar->addGaussianConstraint( (*iter).mean_, (*iter).width_ );
824  conVars_.push_back(formPar);
825 
826  std::cout << "INFO in LauSimFitMaster::addConParameters : Added Gaussian constraint to formula\n";
827  std::cout << " : Formula: " << (*iter).formula_ << std::endl;
828  for ( std::vector<LauParameter*>::iterator iterparam = params.begin(); iterparam != params.end(); ++iterparam ) {
829  std::cout << " : Parameter: " << (*iterparam)->name() << std::endl;
830  }
831  }
832 
833 }
834 
836 {
837  if ( socketMonitor_ == 0 ) {
838  std::cerr << "ERROR in LauSimFitMaster::finalise : Sockets not initialised." << std::endl;
839  return kFALSE;
840  }
841 
842  // Prepare the covariance matrices
843  const TMatrixD& covMatrix = this->covarianceMatrix();
844  covMatrices_.resize( nSlaves_ );
845 
846  LauParamFixed pred;
847 
848  std::map<UInt_t,UInt_t> freeParIndices;
849 
850  UInt_t counter(0);
851  for ( UInt_t iPar(0); iPar < this->nTotParams(); ++iPar ) {
852  const LauParameter* par = params_[iPar];
853  if ( ! pred(par) ) {
854  freeParIndices.insert( std::make_pair(iPar,counter) );
855  ++counter;
856  }
857  }
858 
859  for ( UInt_t iSlave(0); iSlave<nSlaves_; ++iSlave ) {
860  const UInt_t nPar = slaveIndices_[iSlave].size();
861 
862  std::vector<UInt_t> freeIndices;
863  freeIndices.reserve( nPar );
864 
865  for ( UInt_t iPar(0); iPar < nPar; ++iPar ) {
866  UInt_t index = slaveIndices_[iSlave][iPar];
867  std::map<UInt_t,UInt_t>::iterator freeIter = freeParIndices.find(index);
868  if ( freeIter == freeParIndices.end() ) {
869  continue;
870  }
871  UInt_t freeIndex = freeIter->second;
872  freeIndices.push_back( freeIndex );
873  }
874 
875  const UInt_t nFreePars = freeIndices.size();
876  TMatrixD& covMat = covMatrices_[iSlave];
877  covMat.ResizeTo( nFreePars, nFreePars );
878 
879  for ( UInt_t iPar(0); iPar < nFreePars; ++iPar ) {
880  for ( UInt_t jPar(0); jPar < nFreePars; ++jPar ) {
881  UInt_t i = freeIndices[iPar];
882  UInt_t j = freeIndices[jPar];
883  covMat( iPar, jPar ) = covMatrix( i, j );
884  }
885  }
886  }
887 
888  // The array to hold the parameters
889  TObjArray array;
890 
891  // Send messages to all slaves containing the final parameters and fit status, NLL
892  for ( UInt_t iSlave(0); iSlave<nSlaves_; ++iSlave ) {
893 
894  array.Clear();
895 
896  std::vector<UInt_t>& indices = slaveIndices_[iSlave];
897  UInt_t nPars = indices.size();
898  for ( UInt_t iPar(0); iPar < nPars; ++iPar ) {
899  array.Add( params_[ indices[iPar] ] );
900  }
901 
902  const Int_t status = this->statusCode();
903  const Double_t NLL = this->nll();
904  const Double_t EDM = this->edm();
905  TMatrixD& covMat = covMatrices_[iSlave];
906 
907  TMessage* message = messagesToSlaves_[iSlave];
908  message->Reset( kMESS_OBJECT );
909  message->WriteInt( status );
910  message->WriteDouble( NLL );
911  message->WriteDouble( EDM );
912  message->WriteObject( &array );
913  message->WriteObject( &covMat );
914 
915  sSlaves_[iSlave]->Send(*message);
916  }
917 
918  TSocket *sActive(0);
919  UInt_t responsesReceived(0);
920  Bool_t allOK(kTRUE);
921  while ( responsesReceived != nSlaves_ ) {
922 
923  // Get the next queued response
924  sActive = socketMonitor_->Select();
925 
926  // Extract from the message the ID of the slave and the number of events read
927  sActive->Recv( messageFromSlave_ );
928  UInt_t iSlave(0);
929  Bool_t ok(kTRUE);
930  messageFromSlave_->ReadUInt( iSlave );
931  messageFromSlave_->ReadBool( ok );
932 
933  if ( ok ) {
934  TObjArray * objarray = dynamic_cast<TObjArray*>( messageFromSlave_->ReadObject( messageFromSlave_->GetClass() ) );
935  if ( ! objarray ) {
936  std::cerr << "ERROR in LauSimFitMaster::finalise : Error reading finalised parameters from slave" << std::endl;
937  allOK = kFALSE;
938  } else {
939  // We want to auto-delete the supplied parameters since we only copy their values in this case
940  objarray->SetOwner(kTRUE);
941 
942  const UInt_t nPars = objarray->GetEntries();
943  if ( nPars != slaveIndices_[iSlave].size() ) {
944  std::cerr << "ERROR in LauSimFitMaster::finalise : Unexpected number of finalised parameters received from slave" << std::endl;
945  allOK = kFALSE;
946  } else {
947  for ( UInt_t iPar(0); iPar < nPars; ++iPar ) {
948  LauParameter* parameter = dynamic_cast<LauParameter*>( (*objarray)[iPar] );
949  if ( ! parameter ) {
950  std::cerr << "ERROR in LauSimFitMaster::finalise : Error reading parameter from slave" << std::endl;
951  allOK = kFALSE;
952  continue;
953  }
954 
955  TString parname = parameter->name();
956 
957  std::map< TString, UInt_t >::iterator iter = parIndices_.find( parname );
958  if ( iter == parIndices_.end() ) {
959  std::cerr << "ERROR in LauSimFitMaster::finalise : Unexpected parameter name received from slave" << std::endl;
960  allOK = kFALSE;
961  continue;
962  }
963 
964  const UInt_t index = iter->second;
965  if ( slaveIndices_[iSlave][iPar] != index ) {
966  std::cerr << "ERROR in LauSimFitMaster::finalise : Unexpected parameter received from slave" << std::endl;
967  allOK = kFALSE;
968  continue;
969  }
970 
971  Double_t parvalue = parameter->value();
972  params_[index]->value( parvalue );
973  parValues_[index] = parvalue;
974  vectorPar_[iSlave][iPar] = parvalue;
975  }
976  }
977  delete objarray;
978  }
979  } else {
980  std::cerr << "ERROR in LauSimFitMaster::finalise : Slave " << iSlave << " reports an error performing finalisation" << std::endl;
981  allOK = kFALSE;
982  }
983 
984  ++responsesReceived;
985  }
986 
987  // Fill our ntuple as well
988  if ( fitNtuple_ != 0 ) {
989  for ( std::vector<LauParameter*>::iterator iter = params_.begin(); iter != params_.end(); ++iter ) {
990  if (!(*iter)->fixed()) {
991  (*iter)->updatePull();
992  }
993  }
994  std::vector<LauParameter> extraVars;
995  fitNtuple_->storeParsAndErrors( params_, extraVars );
996  fitNtuple_->storeCorrMatrix(this->iExpt(), this->fitStatus(), this->covarianceMatrix());
998  }
999 
1000  return allOK;
1001 }
1002 
1004 {
1005  if ( socketMonitor_ == 0 ) {
1006  std::cerr << "ERROR in LauSimFitMaster::writeOutResults : Sockets not initialised." << std::endl;
1007  return kFALSE;
1008  }
1009 
1010  // Construct a message, requesting to write out the fit results
1011  TString msgStr("Write Results");
1012  TMessage message( kMESS_STRING );
1013  message.WriteTString( msgStr );
1014 
1015  // Send the message to the slaves
1016  for ( UInt_t iSlave(0); iSlave<nSlaves_; ++iSlave ) {
1017  sSlaves_[iSlave]->Send(message);
1018  }
1019 
1020  TSocket *sActive(0);
1021  UInt_t responsesReceived(0);
1022  Bool_t allOK(kTRUE);
1023  while ( responsesReceived != nSlaves_ ) {
1024 
1025  // Get the next queued response
1026  sActive = socketMonitor_->Select();
1027 
1028  // Extract from the message the ID of the slave and the number of events read
1029  sActive->Recv( messageFromSlave_ );
1030  UInt_t iSlave(0);
1031  Bool_t ok(kTRUE);
1032  messageFromSlave_->ReadUInt( iSlave );
1033  messageFromSlave_->ReadBool( ok );
1034 
1035  if ( ! ok ) {
1036  std::cerr << "ERROR in LauSimFitMaster::writeOutResults : Slave " << iSlave << " reports an error performing finalisation" << std::endl;
1037  allOK = kFALSE;
1038  }
1039 
1040  ++responsesReceived;
1041  }
1042 
1043  // Write out our ntuple as well
1044  if (fitNtuple_ != 0) {
1046  }
1047 
1048  return allOK;
1049 }
1050 
TMonitor * socketMonitor_
Parallel setup monitor.
UInt_t nTotParams() const
Access the total number of fit parameters.
virtual const FitStatus & minimise()=0
Perform the minimisation of the fit function.
Int_t statusCode() const
Access the fit status code.
std::vector< std::vector< UInt_t > > slaveIndices_
Lists of indices for each slave.
std::vector< LauAbsRValue * > conVars_
Gaussian constraints.
Bool_t readData()
Instruct the slaves to read the input data for the given experiment.
File containing declaration of LauFormulaPar class.
void getParametersFromSlaves()
Determine/update the parameter initial values from all slaves.
Bool_t fixed() const
Check whether the parameter is fixed or floated.
virtual void updateParameters()=0
Update the values and errors of the parameters based on the fit minimum.
TStopwatch timer_
The fit timer.
std::map< UInt_t, TString > parNames_
Reverse map of index in the values vector to parameter names.
void addConParameters()
Add parameters to the list of Gaussian constrained parameters.
File containing declaration of LauParamFixed class.
Bool_t withinAsymErrorCalc() const
Query whether the fit is calculating the asymmetric errors.
Definition: LauFitObject.hh:88
LauFitNtuple * fitNtuple_
The fit results ntuple.
Double_t maxValue() const
The maximum value allowed for the parameter.
Bool_t writeOutResults()
Instruct the slaves to write out the fit results.
ClassImp(LauAbsCoeffSet)
std::vector< LauParameter * > params_
Parameters.
const TString & name() const
The parameter name.
Class for defining combinations of fit parameter objects.
Double_t worstLogLike() const
Access the worst log likelihood found so far.
virtual Bool_t twoStageFit() const =0
Determine whether the two-stage fit is enabled.
File containing declaration of LauAbsFitter class.
void storeFitStatus(const LauAbsFitter::FitStatus &status, const TMatrixD &covMatrix)
Store fit status information.
Definition: LauFitObject.cc:70
Double_t minValue() const
The minimum value allowed for the parameter.
void getParametersFromSlavesFirstTime()
Determine the parameter names and initial values from all slaves.
Bool_t twoStageFit() const
Report whether the two-stage fit is enabled.
Definition: LauFitObject.hh:73
std::vector< TSocket * > sSlaves_
Sockets for each of the slaves.
const UInt_t reqPort_
The requested port.
void updateFitNtuple()
Update the fit ntuple.
std::vector< Double_t > vectorRes_
Likelihood values returned from the slaves.
UInt_t nFreeParams() const
Access the total number of fit parameters.
std::map< TString, UInt_t > parIndices_
Map of parameter names to index in the values vector.
void addGaussianConstraint(Double_t newGaussMean, Double_t newGaussWidth)
Add a Gaussian constraint (or modify an existing one)
void runSimFit(const TString &fitNtupleFileName, const UInt_t nExp, const UInt_t firstExp=0, const Bool_t useAsymmErrors=kFALSE, const Bool_t doTwoStageFit=kFALSE)
Run the fit.
virtual void initialise(LauFitObject *fitObj, const std::vector< LauParameter * > &parameters)=0
Initialise the fitter, setting the information on the parameters.
void resetFitCounters()
Reset the good/bad fit counters.
Definition: LauFitObject.cc:53
File containing declaration of LauFitter class.
void initSockets()
Initialise socket connections for the slaves.
void storeCorrMatrix(const UInt_t iExpt, const LauAbsFitter::FitStatus &fitStatus, const TMatrixD &covMatrix)
Store the correlation matrix and other fit information.
Definition: LauFitNtuple.cc:74
Double_t edm() const
Access the current EDM value.
void writeOutFitResults()
Write out fit results.
Double_t getLogLikelihoodPenalty()
Calculate the penalty terms to the log likelihood from Gaussian constraints.
void setCurrentExperiment(const UInt_t curExpt)
Set the ID of the current experiment.
const std::vector< StoreConstraints > & constraintsStore() const
Const access to the constraints store.
std::vector< std::vector< UInt_t > > slaveFreeIndices_
Lists of indices of free parameters for each slave.
void checkInitFitParams()
Instruct the slaves to update the initial fit parameter values, if required.
Int_t status
The status code of the fit.
Definition: LauAbsFitter.hh:57
File containing declaration of LauParameter class.
Struct to store fit status information.
Definition: LauAbsFitter.hh:55
Predicate to allow counting of the number of fixed parameters.
std::vector< Double_t * > vectorPar_
Parameter values to send to the slaves.
Bool_t secondStage() const
Check whether the parameter should be floated only in the second stage of a two stage fit...
void updateParametersFromSlaves()
Update and verify the parameter initial values from all slaves.
std::vector< TMatrixD > covMatrices_
The covariance sub-matrices for each slave.
std::vector< TMessage * > messagesToSlaves_
Messages to slaves.
virtual void releaseSecondStageParameters()=0
Release parameters marked as &quot;second stage&quot;.
void checkParameter(const LauParameter *param, UInt_t index) const
Check for compatibility between two same-named parameters, which should therefore be identical...
const TMatrixD & covarianceMatrix() const
Access the fit covariance matrix.
Class for defining the fit parameter objects.
Definition: LauParameter.hh:49
The master process for simultaneous/combined fits.
static LauAbsFitter * fitter()
Method that provides access to the singleton fitter.
Definition: LauFitter.cc:51
Bool_t finalise()
Return the final parameters to the slaves and instruct them to perform their finalisation.
TStopwatch cumulTimer_
The total fit timer.
virtual void setParsFromMinuit(Double_t *par, Int_t npar)
This function sets the parameter values from Minuit.
Bool_t useAsymmFitErrors() const
Report whether or not calculation of asymmetric errors is enabled.
Definition: LauFitObject.hh:57
std::vector< Double_t > parValues_
Parameter values.
const UInt_t nSlaves_
The number of slaves.
UInt_t numberOKFits() const
Access the number of successful fits.
File containing declaration of LauSimFitMaster class.
void storeParsAndErrors(const std::vector< LauParameter * > &fitVars, const std::vector< LauParameter > &extraVars)
Store parameters and their errors.
UInt_t numberBadFits() const
Access the number of failed fits.
Double_t initValue() const
The initial value of the parameter.
TMessage * messageFromSlave_
Message from slaves to the master.
Double_t nll() const
Access the current NLL value.
void fitExpt()
Perform the fit for the current experiment.
void startNewFit(const UInt_t nPars, const UInt_t nFreePars)
Indicate the start of a new fit.
Definition: LauFitObject.cc:60
const LauAbsFitter::FitStatus & fitStatus() const
Access the fit status information.
virtual Bool_t useAsymmFitErrors() const =0
Determine whether calculation of asymmetric errors is enabled.
Bool_t cacheInputData()
Instruct the slaves to perform the caching.
Double_t value() const
The value of the parameter.
void initialise()
Initialise.
friend class LauFitNtuple
LauFitNtuple is a friend class.
virtual Double_t getTotNegLogLikelihood()
Calculate the new value of the negative log likelihood.
UInt_t iExpt() const
Obtain the number of the current experiment.
virtual ~LauSimFitMaster()
Destructor.
File containing declaration of LauFitNtuple class.
virtual const TMatrixD & covarianceMatrix() const =0
Retrieve the fit covariance matrix.
void printParInfo() const
Print information on the parameters.