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