1 #include "DDaceServer.h"
2 #include "ArrayComm.h"
3 #include <iostream>
4 #include <fstream>
5 using namespace std;
6 #include "System.h"
7 #include "PComm.h"
8 #include "DDace.h"
9 #include "SmartPtr.h"
10 #include "XMLObject.h"
11 #include "DDaceSampler.h"
12 #include "UniformDistribution.h"
13 #include "NormalDistribution.h"
14 #include "DDaceLHSampler.h"
15 #include "DDaceRandomSampler.h"
16 #include "DDaceOASampler.h"
17 #include "DDaceFactorialSampler.h"
18 #include "DDaceUserInputSampler.h"
19 
20 // ------------------------------------------------------------------------
21 // Ctors for DDaceServer. DDaceServer holds all problem data, names, etc.
22 //
23 // The DDaceServer object is constructed from existing objects rather
24 // than by parsing an input file; we assume that the input file (if any)
25 // has been parsed at a higher level.
26 // ------------------------------------------------------------------------
27 
DDaceServer(const DDaceSampler & sampler,const Array<String> & varNames,const Array<String> & outputNames,const String & archiveFilename)28 DDaceServer::DDaceServer(const DDaceSampler& sampler,
29 			 const Array<String>& varNames,
30 			 const Array<String>& outputNames,
31 			 const String& archiveFilename)
32   : DDaceMachineBase(),
33     stackPtr_(0),
34     results_(0),
35     status_(0),
36     sampler_(sampler),
37     archiveFilename_(archiveFilename),
38     varNames_(varNames),
39     outputNames_(outputNames)
40 {
41   sampler_.getSamples(pts_);
42   results_.resize(pts_.length());
43   status_.resize(pts_.length());
44   for (int i=0; i<status_.length(); i++) status_[i] = DDaceRunNotStarted;
45   pts_.bcast(0, DDace::getComm());
46 }
47 
48 
49 
DDaceServer(const DDaceSampler & sampler)50 DDaceServer::DDaceServer(const DDaceSampler& sampler)
51   : DDaceMachineBase(),
52     stackPtr_(0),
53     results_(0),
54     status_(0),
55     sampler_(sampler),
56     archiveFilename_("ddaceArchive"),
57     varNames_(sampler.nInputs()),
58     outputNames_(0)
59 {
60   int i;
61   sampler_.getSamples(pts_);
62   results_.resize(pts_.length());
63   status_.resize(pts_.length());
64   for (i=0; i<status_.length(); i++) status_[i] = DDaceRunNotStarted;
65   // sould we initialize the values in results_?
66 
67   pts_.bcast(0, DDace::getComm());
68 
69   // make up some dummy variable names if the user hasn't given any.
70   for (i=0; i<varNames_.length(); i++)
71     {
72       char tmp[20];
73       sprintf(tmp, "var%d", i);
74       varNames_[i] = tmp;
75     }
76 }
77 
DDaceServer(const XMLObject & xmlObj)78 DDaceServer::DDaceServer(const XMLObject& xmlObj)
79   : DDaceMachineBase(),
80     stackPtr_(0),
81     results_(0),
82     status_(0),
83     sampler_(),
84     archiveFilename_(""),
85     varNames_(0),
86     outputNames_(0)
87 {
88 
89 try
90 {
91   int nc = 0;
92 
93   int nsamples = 0, nreplications = 0, nsymbols = 0;
94 
95   bool noise;
96   std::string userInputFile, archiveFile;
97   std::vector<std::string> varNames(0);
98   std::vector<std::string> outNames(0);
99   std::vector<Distribution> distributions(0);
100   std::string samplerName;
101 
102   if(xmlObj.getTag() == "DDace")
103   {
104  	nc = xmlObj.numChildren(); // should be 4 -- sampler, archive name,
105   	 // input variable names, output names
106  	for(int i=0; i < nc; i++)
107  	{
108  	  XMLObject xKid = xmlObj.getChild(i);
109 
110  	// Settings associated with the samplers:
111 	  if((xKid.getTag() == "Random") ||
112    	(xKid.getTag() == "Factorial") ||
113    	(xKid.getTag() == "OrthogonalArray") ||
114    	(xKid.getTag() == "LatinHypercube") ||
115    	(xKid.getTag() == "UserInputSampler"))
116   	  {
117   	    //keep track of the sampler name....
118   	    samplerName = xKid.getTag();
119 
120   	    if((xKid.getTag() == "Random") ||
121   		 (xKid.getTag() == "Factorial") ||
122   		 (xKid.getTag() == "OrthogonalArray") ||
123   		 (xKid.getTag() == "LatinHypercube"))
124   		{
125   			nsamples = xKid.getAttribute("samples").atoi();
126   		}
127 
128   	if((xKid.getTag() == "Factorial") ||
129   		 (xKid.getTag() == "LatinHypercube") ||
130   		 (xKid.getTag() == "OrthogonalArray"))
131   		{
132   			noise = xKid.getAttribute("noise").atob();
133   		}
134 
135   	if(xKid.getTag() == "Factorial")
136   		nsymbols = xKid.getAttribute("symbols").atoi();
137   	else if(xKid.getTag() == "LatinHypercube")
138   		nreplications = xKid.getAttribute("replications").atoi();
139   	else if(xKid.getTag() == "UserInputSampler")
140   		{
141   			XMLObject tmpKid = xKid.getChild(0);
142   			userInputFile = tmpKid.getAttribute("filename");
143   		}
144   }
145  			// Settings associated with the archive file:
146  			else if(xKid.getTag() == "Archive")
147   archiveFile = xKid.getAttribute("name");
148 
149  			// Array: could be input variable names (varNames) or
150  			// output variable names (outVarNames)....
151  			else if(xKid.getTag() == "Array")
152   {
153   	// set up an Array of input variable names....
154   	//if(xKid.getAttribute("name") == "inputVariables")
155   	if(xKid.getAttribute("name") == "inputVariables")
156   		{
157   			int nc1 = xKid.numChildren();
158   			if(nc1 == 0)
159    ExceptionBase::raise("DDaceServer XML ctor : number "
160      		 "of input variables must be\n"
161      		 "greater than zero.");
162 
163   			varNames.resize(nc1);
164   			distributions.resize(nc1);
165   			for(int j = 0; j < nc1; j++)
166    {
167    	XMLObject varKid = xKid.getChild(j);
168    	if(varKid.getTag() == "DDaceVariable")
169    		{
170    			// get variable name
171    			varNames[j] = varKid.getAttribute("variable");
172 
173    			// get distribution information
174    			XMLObject distKid = varKid.getChild(0);
175    			if(distKid.getTag() == "UniformDistribution")
176     {
177     	double lwr = distKid.getAttribute("lower").atof();
178     	double upr = distKid.getAttribute("upper").atof();
179 
180     	distributions[j] = UniformDistribution(lwr, upr);
181     	//distributions.append(UniformDistribution(lwr, upr));
182     }
183    			else if(distKid.getTag() == "NormalDistribution")
184     {
185     	double mean = distKid.getAttribute("mean").atof();
186     	double sigma = distKid.getAttribute("sigma").atof();
187 
188     	//distributions.append(NormalDistribution(mean, sigma));
189     	distributions[j] = NormalDistribution(mean, sigma);
190     }
191    			else
192     ExceptionBase::raise("DDaceServer XML ctor : "
193       		 "only support for Normal\n"
194       		 "and Uniform distributions"
195       		 " in current version of "
196       		 "DDace.");
197    		}
198    	else
199    		ExceptionBase::raise("DDaceServer XML ctor : "
200        "Array with name "
201        "inputVariables\ndoes not"
202        "contain DDaceVariables...");
203    }
204   		}
205   	else if(xKid.getAttribute("name") == "outVarNames")
206   		{
207   			int nc2 = xKid.numChildren();
208   			if(nc2 == 0)
209    ExceptionBase::raise("DDaceServer XML ctor : number "
210      		 "of output variables must be\n"
211      		 "greater than zero.");
212   			outNames.resize(nc2);
213   			for(int k=0; k < nc2; k++)
214    {
215    	XMLObject outKid = xKid.getChild(k);
216    	outNames[k] = outKid.getAttribute("value");
217    }
218   		}
219   }
220  		}
221  }
222 			else
223  {
224  	ExceptionBase::raise("DDaceServer XML ctor : XML object not of"
225    			 "type DDace.");
226  }
227 
228 
229 			// we should have all the pieces to build a DDace object, so build it:
230 
231 			// First, build the sampler:
232 			if(samplerName == "Random")
233  sampler_ = DDaceRandomSampler(nsamples, distributions);
234 			else if(samplerName == "Factorial")
235  sampler_ = DDaceFactorialSampler(nsamples,nsymbols,
236       noise, distributions);
237 			else if(samplerName == "LatinHypercube")
238  sampler_ = DDaceLHSampler(nsamples, nreplications, noise, distributions);
239 			else if(samplerName == "OrthogonalArray")
240  sampler_ = DDaceOASampler(nsamples, noise, distributions);
241 			else if(samplerName == "UserInputSampler")
242  sampler_ = DDaceUserInputSampler(userInputFile);
243 			else
244  ExceptionBase::raise("DDaceServer XML ctor : sampler name not "
245    		 "recognized.");
246 
247 			sampler_.getSamples(pts_);
248 			results_.resize(pts_.length());
249 			status_.resize(pts_.length());
250 			for (int i=0; i<status_.length(); i++) status_[i] = DDaceRunNotStarted;
251 
252 			pts_.bcast(0, DDace::getComm());
253 
254 			varNames_.resize(sampler_.nInputs());
255 			if(varNames.length() != varNames_.length())
256  ExceptionBase::raise("DDaceServer XML ctor : number of variables read "
257    		 "from XMLObject \nis not the same as number of "
258    		 "variables expected from XMLObject.");
259 			else
260  varNames_ = varNames;
261 
262 			outputNames_.resize(outNames.length());
263 			outputNames_ = outNames;
264 
265 			if(archiveFile != "")
266  archiveFilename_ = archiveFile;
267 			else
268  archiveFilename_ = "ddaceArchive";
269 		}
270 	catch(ExceptionBase& e)
271 		{
272 			e.trace("in DDaceServer XML ctor");
273 		}
274 }
275 
276 
277 // ------------------------------------------------------------------------
278 // On the server, getNextSample doles out sample points to the processors
279 // and then waits for data to be returned.
280 // It loops until everything is done, and then returns false to terminate
281 // the calling loop.
282 // ------------------------------------------------------------------------
283 
284 
getNextSample(DDaceSamplePoint &)285 bool DDaceServer::getNextSample(DDaceSamplePoint& /* pt */)
286 {
287   if (pts_.length()==0) return false;
288 
289   int nProc = DDace::getComm().getNProc();
290 
291   Array<int> dataIndex(nProc);
292   int request;
293 
294   // status variables:
295   // bool done indicates whether all processors are finished
296   bool done = false;
297 
298   // masterDone indicates whether all sample points have been handed out.
299   // After the master is done, we need to keep running to collect data
300   // from those processors that are still working.
301   bool masterDone = false;
302 
303   // processorNotified indicates whether processor #i has been told that
304   // all samples are done.
305   Array<bool> processorNotified(nProc, false);
306 
307   // procStatus indicated the current state of processor #i.
308   // "Available" means that it is ready to send a request for a new sample pt.
309   // "AskedForRequest" means that the master is waiting for a request from it.
310   // "AskedForData" means that the master is waiting for data from it.
311   // "Busy" means that it is running a function evaluation.
312   // "Faulty" means that we've detected an error in a transmission from it.
313   Array<ProcStatus> procStatus(nProc, Available);
314 
315   while (!done)
316     {
317       // look for requests from all available processors.
318       // look for results from all busy processors.
319       for (int i=1; i<nProc; i++)
320 	{
321 	  cerr << "Server: Check for Proc Status" << endl;
322 	  if (procStatus[i] == Available)
323 	    {
324 	      cerr << "Server: Proc Available; receive request" << endl;
325 	      PMachine::irecv(&request, 1, PMachine::INT, (int) RequestTag, i,
326 			      DDace::getComm());
327 	      procStatus[i] = AskedForRequest;
328 	      cerr << "Server: Proc Asked for Request" << endl;
329 	    }
330 	  else if (procStatus[i] == Busy)
331 	    {
332 	      dataIndex[i] = -1;
333 	      PMachine::irecv(&(dataIndex[i]), 1, PMachine::INT,
334 			      (int) ResultIndexTag, i, DDace::getComm());
335 	      procStatus[i] = AskedForData;
336 	    }
337 	}
338 
339       // pick up next incoming transmission
340 
341       cerr << "Server: waitAny pick up next incoming transmission" << endl;
342       int srcID = PMachine::waitAny(DDace::getComm());
343       cerr << "Server: after waitAny srcID = " << srcID << endl;
344 
345       // check for bad processor
346       if (srcID < 0)
347 	{
348 	  procStatus[-srcID] = Faulty;
349 	  break;
350 	}
351 
352 
353       // if we've been waiting for a request for a sample pt, send it
354       // the index for the next sample.
355       if (procStatus[srcID] == AskedForRequest)
356 	{
357 	  int sendIndex = stackPtr_;
358 	  procStatus[srcID] = Busy;
359 	  if (stackPtr_ >= pts_.length())
360 	    {
361 	      masterDone = true;
362 	      sendIndex = -1;
363 	      processorNotified[srcID] = true;
364 	      procStatus[srcID] = Done;
365 	    }
366 	  cerr << "Server: send sample point to p" << srcID << endl;
367 
368 	  PMachine::send(&sendIndex, 1, PMachine::INT,
369 			 (int) IndexTag, srcID, DDace::getComm());
370 	  stackPtr_++;
371 	}
372       // if we've been waiting for data, receive the next data point.
373       else if (procStatus[srcID] == AskedForData)
374 	{
375 	  int status;
376 	  cerr << "Server: waiting for data" << endl;
377 	  PMachine::recv(&status, 1, PMachine::INT, (int) ResultIndexTag,
378 			 srcID, DDace::getComm());
379 	  cerr << "Server: received data from p " << srcID << endl;
380 	  status_[dataIndex[srcID]] = (DDaceRunStatus) status;
381 	  if (status_[dataIndex[srcID]] == DDaceRunOK)
382 	    {
383 	      Array<double> values;
384 	      ArrayComm::recv(values, (int) ResultValueTag, srcID,
385 			      DDace::getComm());
386 	      results_[dataIndex[srcID]] = values;
387 	    }
388 	  procStatus[srcID] = Available;
389 	  writeToArchive();
390 	}
391       else
392 	{
393 	  done = true;
394 	  break;
395 	}
396 
397       // if all sample points have been sent, keep going until all processors
398       // have finished.
399       if (masterDone)
400 	{
401 	  done = true;
402 	  for (int i=1; i<nProc; i++)
403 	    {
404 	      if (!processorNotified[i])
405 		{
406 		  done = false;
407 		  break;
408 		}
409 	    }
410 	}
411     }
412   return false;
413 
414 }
415 
416 
getSampler(DDaceSampler & sampler) const417 void DDaceServer::getSampler(DDaceSampler& sampler) const
418 {
419   sampler = sampler_;
420 }
421 
getRunStatus(Array<DDaceRunStatus> & status) const422 void DDaceServer::getRunStatus(Array<DDaceRunStatus>& status) const
423 {
424   status = status_;
425 }
426 
getArchiveFilename(String & archiveFilename) const427 void DDaceServer::getArchiveFilename(String& archiveFilename) const
428 {
429   archiveFilename = archiveFilename_;
430 }
431 
getVarNames(Array<String> & names) const432 void DDaceServer::getVarNames(Array<String>& names) const
433 {
434   names = varNames_;
435 }
436 
getOutputNames(Array<String> & names) const437 void DDaceServer::getOutputNames(Array<String>& names) const
438 {
439   names = outputNames_;
440 }
441 
getNumOutputs() const442 int DDaceServer::getNumOutputs() const
443 {
444   return outputNames_.length();
445 }
446 
447 // ------------------------------------------------------------------------
448 // The server's copy of storeFunctionValue is a dummy. The actual
449 // storing of function values on the server side is done in the getSample
450 // function call. Wierd but true.
451 // ------------------------------------------------------------------------
452 
storeFunctionValue(const DDaceSamplePoint &,const Array<double> &)453 void DDaceServer::storeFunctionValue(const DDaceSamplePoint& /* pt */,
454       const Array<double>& /* values */)
455 {
456   ExceptionBase::raise("internal error: DDaceServer::storeFunctionValue should never be called");
457 }
458 
recordRunStatus(const DDaceSamplePoint & pt,DDaceRunStatus status)459 void DDaceServer::recordRunStatus(const DDaceSamplePoint& pt,
460    DDaceRunStatus status)
461 {
462   ExceptionBase::raise("internal error: DDaceServer::recordRunStatus should never be called");
463 }
464 
465 
466 // ------------------------------------------------------------------------
467 // Write all information to the archive file. This is intended to be a
468 // dump that can be used for restart.
469 // ------------------------------------------------------------------------
470 
writeToArchive()471 void DDaceServer::writeToArchive()
472 {
473   int i;
474   int j;
475   String file;
476 
477   if (archivePath_.length() > 0)
478     {
479       file = archivePath_ + "/" + archiveFilename_;
480     }
481   else
482     {
483       file = archiveFilename_;
484     }
485   ofstream of(file.cString());
486 
487   of << "<DDaceArchive date=\"" << System::date() << "\">" << endl;
488   of << sampler_ << endl;
489 
490   if(sampler_.typeName() == "DDaceUserInputSampler")
491     {
492       for (i=0; i<sampler_.nInputs(); i++)
493 	{
494 	  of << "<Variable name=\"" << varNames_[i]
495 	     << "\" lower=\"" << sampler_.lowerBounds()[i]
496 	     << "\" upper=\"" << sampler_.upperBounds()[i]
497 	     << "\"/>" << endl;
498 	}
499     }
500   else
501     {
502       for (i=0; i<sampler_.nInputs(); i++)
503 	{
504 	  of << "<Variable name=\"" << varNames_[i] << "\" ";
505 	  sampler_.dist()[i].printAttributes(of);
506 	  of << "/>" << endl;
507 	}
508     }
509   for (i=0; i<outputNames_.length(); i++)
510     {
511       of << "<Output name=\"" << outputNames_[i] << "\"/>" << endl;
512     }
513   of << "<Results>" << endl;
514   for (i=0; i<pts_.length(); i++)
515     {
516       of << "<Sample tag=\"" << i << "\">" << endl;
517       of << "<SamplePoint> " << endl;
518       for (j=0; j<pts_[i].length(); j++)
519 	{
520 	  of << '\t' << pts_[i][j] << endl;
521 	}
522       of << "</SamplePoint>" << endl;
523       of << "<SampleResult status=\"";
524 
525       if (status_[i]==DDaceRunOK)
526 	{
527 	  of << "Run OK\">" << endl;
528 	  for (j=0; j<results_[i].length(); j++)
529 	    {
530 	      of << '\t' << results_[i][j] << endl;
531 	    }
532 	  of << "</SampleResult>" << endl;
533 	}
534       else
535 	{
536 	  for (j=0; j<outputNames_.length(); j++)
537 	    {
538 	      switch(status_[i])
539 		{
540 		case DDaceRunFailed:
541 		  of << "Run failed\"/>" << endl;
542 		  break;
543 		case DDacePostProcFailed:
544 		  of << "Post processing failed\"/>" << endl;
545 		  break;
546 		case DDaceRunPending:
547 		  of << "Run pending\"/>" << endl;
548 		  break;
549 		case DDaceRunNotStarted:
550 		  of << "Run not started\"/>" << endl;
551 		  break;
552 		default:
553 		  ExceptionBase::raise("DDaceServer::writeToArchive unrecognized run status");
554 		}
555 	    }
556 	}
557       of << "</Sample>" << endl;
558 
559     }
560   of << "</Results>" << endl;
561   of << "</DDaceArchive>" << endl;
562 }
563 
564 
565 
566 // ------------------------------------------------------------------------
567 // mutators for variable names and such
568 // ------------------------------------------------------------------------
569 
setArchivePath(const String & archivePath)570 void DDaceServer::setArchivePath(const String& archivePath)
571 {
572 	archivePath_ = archivePath;
573 }
574 
setArchiveName(const String & archiveFilename)575 void DDaceServer::setArchiveName(const String& archiveFilename)
576 {
577 	archiveFilename_ = archiveFilename;
578 }
579 
setVariableNames(const Array<String> & varNames)580 void DDaceServer::setVariableNames(const Array<String>& varNames)
581 {
582 	if (varNames.length() != sampler_.nInputs())
583 		{
584 			ExceptionBase::raise("DDaceServer::setVariableNames: mismatched array dimension");
585 		}
586 	varNames_ = varNames;
587 }
588 
setOutputNames(const Array<String> & outputNames)589 void DDaceServer::setOutputNames(const Array<String>& outputNames)
590 {
591 	outputNames_ = outputNames;
592 }
593 
594 
595 //----------------------------------------------------------------------
596 // getting results
597 //----------------------------------------------------------------------
598 
getResults(Array<DDaceSamplePoint> & pts,Array<Array<double>> & funcValues) const599 void DDaceServer::getResults(Array<DDaceSamplePoint>& pts,
600    		 Array<Array<double> >& funcValues) const
601 {
602 	pts = pts_;
603 	funcValues = results_;
604 }
605 
606 
607 
608 
609 
610