/[escript]/branches/subworld2/escriptcore/src/SubWorld.cpp
ViewVC logotype

Contents of /branches/subworld2/escriptcore/src/SubWorld.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5505 - (show annotations)
Wed Mar 4 23:05:47 2015 UTC (3 years, 11 months ago) by jfenwick
File size: 22074 byte(s)
Changes which were sitting in my trunk dir
1
2 /*****************************************************************************
3 *
4 * Copyright (c) 2014-2015 by University of Queensland
5 * http://www.uq.edu.au
6 *
7 * Primary Business: Queensland, Australia
8 * Licensed under the Open Software License version 3.0
9 * http://www.opensource.org/licenses/osl-3.0.php
10 *
11 * Development until 2012 by Earth Systems Science Computational Center (ESSCC)
12 * Development 2012-2013 by School of Earth Sciences
13 * Development from 2014 by Centre for Geoscience Computing (GeoComp)
14 *
15 *****************************************************************************/
16
17 #define ESNEEDPYTHON
18 #include "esysUtils/first.h"
19
20
21 #include "SubWorld.h"
22 #include "SplitWorldException.h"
23 #include "esysUtils/pyerr.h"
24
25 #include "MPIDataReducer.h"
26 #include "MPIScalarReducer.h"
27
28 #include <boost/python/import.hpp>
29 #include <boost/python/dict.hpp>
30
31 #include <iostream>
32
33 using namespace escript;
34 namespace bp=boost::python;
35 using namespace esysUtils;
36 namespace rs=escript::reducerstatus;
37
38 using namespace std;
39
40 SubWorld::SubWorld(JMPI& global, JMPI& comm, JMPI& corr, unsigned int subworldcount, unsigned int local_id, bool manualimport)
41 :everyone(global), swmpi(comm), corrmpi(corr), domain((AbstractDomain*)0),
42 swcount(subworldcount), localid(local_id), manualimports(manualimport)
43 #ifdef ESYS_MPI
44 ,globalinfoinvalid(true)
45 #endif
46 {
47 }
48
49 SubWorld::~SubWorld()
50 {
51 }
52
53 JMPI& SubWorld::getMPI()
54 {
55 return swmpi;
56 }
57
58 JMPI& SubWorld::getCorrMPI()
59 {
60 return corrmpi;
61 }
62
63 void SubWorld::setDomain(Domain_ptr d)
64 {
65 domain=d;
66 }
67
68 Domain_ptr SubWorld::getDomain()
69 {
70 return domain;
71 }
72
73 void SubWorld::addJob(boost::python::object j)
74 {
75 jobvec.push_back(j);
76 }
77
78 void SubWorld::clearJobs()
79 {
80 jobvec.clear();
81 }
82
83 void SubWorld::setMyVarState(const std::string& vname, char state)
84 {
85 setVarState(vname, state, localid);
86 }
87
88 void SubWorld::setAllVarsState(std::string& vname, char state)
89 {
90 #ifdef ESYS_MPI
91 // we need to know where the variable is in thbe sequence
92 str2char::iterator it=varstate.find(vname);
93 size_t c=0;
94 for (;it!=varstate.end();++it,++c)
95 {
96 if (it->first==vname)
97 {
98 break;
99 }
100 }
101 if (it==varstate.end())
102 {
103 return;
104 }
105 it->second=state;
106 c--; // we now have the sequence position of the variable
107 for (char z=rs::NONE; z<=rs::NEW;++z)
108 {
109 globalvarcounts[vname][z]=0;
110 }
111 globalvarcounts[vname][state]=swcount;
112 if (!globalinfoinvalid) // it will be updated in the next synch
113 {
114 for (size_t p=c;p<globalvarinfo.size();p+=getNumVars())
115 {
116 globalvarinfo[p]=state;
117 }
118 }
119 #else
120 varstate[vname]=state;
121 #endif
122
123
124 }
125
126
127 void SubWorld::setVarState(const std::string& vname, char state, int rank)
128 {
129 #ifdef ESYS_MPI
130 // we need to know where the variable is in thbe sequence
131 str2char::iterator it;
132 size_t c=0;
133 for (it=varstate.begin();it!=varstate.end();++it,++c)
134 {
135 if (it->first==vname)
136 {
137 break;
138 }
139 }
140 if (it==varstate.end())
141 {
142 return;
143 }
144
145 // we now have the sequence position of the variable
146 if (!globalinfoinvalid) // it will be updated in the next synch
147 {
148 unsigned char ostate=globalvarinfo[c+getNumVars()*rank];
149 globalvarinfo[c+getNumVars()*rank]=state;
150 globalvarcounts[vname][ostate]--;
151 globalvarcounts[vname][state]++;
152 }
153 if (rank==localid) // we are updating our own state so we need to change "varstate"
154 {
155 it->second=state;
156 }
157 #else
158 varstate[vname]=state;
159 #endif
160 }
161
162
163 // this will give the imported values to interested jobs
164 bool SubWorld::deliverImports(std::string& errmsg)
165 {
166 for (size_t i=0;i<jobvec.size();++i)
167 {
168 if (manualimports)
169 {
170 bp::list wanted=bp::extract<bp::list>(jobvec[i].attr("wantedvalues"))();
171 for (size_t j=0;j<len(wanted);++j)
172 {
173 bp::extract<std::string> exs(wanted[j]); // must have been checked by now
174 std::string n=exs();
175 // now we need to check to see if this value is known
176 str2reduce::iterator it=reducemap.find(n);
177 if (it==reducemap.end())
178 {
179 errmsg="Attempt to import variable \""+n+"\". SplitWorld was not told about this variable.";
180 return false;
181 }
182 try
183 {
184 jobvec[i].attr("setImportValue")(it->first, reducemap[it->first]->getPyObj());
185 }
186 catch (boost::python::error_already_set e)
187 {
188 getStringFromPyException(e, errmsg);
189 return false;
190 }
191 }
192 }
193 else
194 {
195 // For automatic imports, we want to import "Everything" into every job.
196 // However, we don't want to import things with no value yet
197 for (str2reduce::iterator it=reducemap.begin();it!=reducemap.end();++it)
198 {
199 if (it->second->hasValue())
200 {
201 try
202 {
203 jobvec[i].attr("setImportValue")(it->first, it->second->getPyObj());
204 }
205 catch (boost::python::error_already_set e)
206 {
207 getStringFromPyException(e, errmsg);
208 return false;
209 }
210 }
211 }
212 }
213 }
214 return true;
215 }
216
217 // Gather exported values from jobs and merge them in the reducer
218 bool SubWorld::localTransport(std::string& errmsg)
219 {
220 for (size_t i=0;i<jobvec.size();++i)
221 {
222 bp::dict expmap=bp::extract<bp::dict>(jobvec[i].attr("exportedvalues"))();
223 bp::list items=expmap.items();
224 size_t l=bp::len(items);
225 for (int j=0;j<l;++j)
226 {
227 bp::object o1=items[j][0];
228 bp::object o2=items[j][1];
229 bp::extract<std::string> ex1(o1);
230 if (!ex1.check())
231 {
232 errmsg="Job attempted export using a name which was not a string.";
233 return false;
234 }
235 std::string name=ex1();
236 std::map<std::string, Reducer_ptr>::iterator it=reducemap.find(name);
237 if (it==reducemap.end())
238 {
239 errmsg="Attempt to export variable \""+name+"\". SplitWorld was not told about this variable.";
240 return false;
241 }
242 // so now we know it is a known name, we check that it is not None and that it is compatible
243 if (o2.is_none())
244 {
245 errmsg="Attempt to export variable \""+name+"\" with value of None, this is not permitted.";
246 return false;
247 }
248 if (!(it->second)->valueCompatible(o2))
249 {
250 errmsg="Attempt to export variable \""+name+"\" with an incompatible value. Using ";
251 errmsg+=(it->second)->description();
252 return false;
253 }
254 if (!(it->second)->reduceLocalValue(o2, errmsg))
255 {
256 return false; // the error string will be set by the reduceLocalValue
257 }
258 setMyVarState(name, rs::NEW);
259 }
260 }
261 return true;
262 }
263
264 void SubWorld::debug()
265 {
266 using namespace std;
267 using namespace escript::reducerstatus;
268 std::cout << "Variables:";
269 #ifdef ESYS_MPI
270 if (!globalinfoinvalid)
271 {
272 cout << "{ NONE INTR OLD OINT NEW }";
273 }
274 else
275 {
276 cout << "(no valid global info)";
277 }
278 #endif
279 std::cout << std::endl;
280 int i=0;
281 for (str2char::iterator it=varstate.begin();it!=varstate.end();++it,++i)
282 {
283 std::cout << it->first << ": ";
284 std::cout << reducemap[it->first]->description() << " ";
285 switch (it->second)
286 {
287 case NONE: cout << "NONE "; break;
288 case INTERESTED: cout << "INTR "; break;
289 case OLDINTERESTED: cout << "OINT "; break;
290 case OLD: cout << "OLD "; break;
291 case NEW: cout << "NEW "; break;
292 }
293 #ifdef ESYS_MPI
294 if (!globalinfoinvalid)
295 {
296 cout << "{ ";
297 for (unsigned char z=rs::NONE;z<=rs::NEW;++z)
298 {
299 cout << globalvarcounts[it->first][z] << ' ';
300 }
301 cout << " } ";
302
303 }
304 else
305 {
306 cout << "(no valid global info)";
307 }
308 #endif
309 cout << endl;
310 }
311
312 #ifdef ESYS_MPI
313
314 if (!globalinfoinvalid)
315 {
316 cout << "[";
317 for (size_t i=0;i<globalvarinfo.size();++i)
318 {
319 if (i%getNumVars()==0)
320 {
321 cout << " ";
322 }
323 cout << (short)globalvarinfo[i];
324 }
325 cout << " ] ";
326
327 }
328
329
330 #endif
331 std::cout << "Debug end\n";
332 std::cout.flush();
333
334 }
335
336
337 // not to be called while running jobs
338 // The tricky bit, is that this could be be called between job runs
339 // this means that the values of variables may not have been synched yet
340 double SubWorld::getScalarVariable(const std::string& name)
341 {
342 str2reduce::iterator it=reducemap.find(name);
343 if (it==reducemap.end())
344 {
345 throw SplitWorldException("No variable of that name.");
346 }
347 // need to indicate we are interested in the variable
348 if (varstate[name]==rs::NONE)
349 {
350 setMyVarState(name, rs::INTERESTED);
351 }
352 else if (varstate[name]==rs::OLD)
353 {
354 setMyVarState(name, rs::OLDINTERESTED);
355 }
356 // anything else, indicates interest anyway
357 #ifdef ESYS_MPI
358 std::string errmsg;
359 if (!synchVariableInfo(errmsg))
360 {
361 throw SplitWorldException(std::string("(Getting scalar --- Variable information) ")+errmsg);
362 }
363 if (!synchVariableValues(errmsg))
364 {
365 throw SplitWorldException(std::string("(Getting scalar --- Variable value) ")+errmsg);
366 }
367 #endif
368
369 if (dynamic_cast<MPIScalarReducer*>(it->second.get())==0)
370 {
371 throw SplitWorldException("Variable is not scalar.");
372 }
373 return dynamic_cast<MPIScalarReducer*>(it->second.get())->getDouble();
374 }
375
376 bool SubWorld::checkRemoteCompatibility(std::string& errmsg)
377 {
378 for (str2reduce::iterator it=reducemap.begin();it!=reducemap.end();++it)
379 {
380 if (! it->second->checkRemoteCompatibility(corrmpi, errmsg))
381 {
382 return false;
383 }
384 }
385 return true;
386 }
387
388 #ifdef ESYS_MPI
389
390 bool SubWorld::makeComm(MPI_Comm& sourcecom, MPI_Comm& subcom,std::vector<int>& members)
391 {
392 MPI_Group sourceg, g;
393 if (MPI_Comm_group(sourcecom, &sourceg)!=MPI_SUCCESS) {return false;}
394 if (MPI_Group_incl(sourceg, members.size(), &members[0], &g)!=MPI_SUCCESS) {return false;}
395 // then create a communicator with that group
396 if (MPI_Comm_create(sourcecom, g, &subcom)!=MPI_SUCCESS)
397 {
398 return false;
399
400 }
401 return true;
402 }
403
404 // a group with NEW nodes at the front and INT and OLDINT at the back
405 // NONE worlds get an empty communicator
406 bool SubWorld::makeGroupComm1(MPI_Comm& srccom, int vnum, char mystate, MPI_Comm& com)
407 {
408 if ((mystate==rs::NEW)
409 || (mystate==rs::INTERESTED)
410 || (mystate==rs::OLDINTERESTED))
411 {
412 // first create a group with [updates, interested and oldinterested in it]
413 std::vector<int> members;
414 for (int i=0+vnum;i<globalvarinfo.size();i+=getNumVars())
415 {
416 // make a vector of the involved procs with New at the front
417 switch (globalvarinfo[i])
418 {
419 case rs::NEW: members.insert(members.begin(), i/getNumVars()); break;
420 case rs::INTERESTED:
421 case rs::OLDINTERESTED:
422 members.push_back(i/getNumVars());
423 break;
424 }
425 }
426 return makeComm(srccom, com, members);
427 }
428 else // for people not in involved in the value shipping
429 { // This would be a nice time to use MPI_Comm_create_group
430 // but it does not exist in MPI2.1
431 return MPI_Comm_create(srccom, MPI_GROUP_EMPTY, &com);
432 }
433 }
434
435 // A group with a single OLD or OLDINT at the front and all the INT worlds
436 // following it
437 bool SubWorld::makeGroupComm2(MPI_Comm& srccom, int vnum, char mystate, MPI_Comm& com)
438 {
439 if ((mystate==rs::OLD)
440 || (mystate==rs::INTERESTED)
441 || (mystate==rs::OLDINTERESTED))
442 {
443 // first create a group with [old, interested and oldinterested in it]
444 std::vector<int> members;
445 bool havesrc=false;
446 for (int i=0+vnum;i<globalvarinfo.size();i+=getNumVars())
447 {
448 // make a vector of the involved procs with New at the front
449 switch (globalvarinfo[i])
450 {
451 case rs::NEW: return false; break;
452 case rs::INTERESTED: members.push_back(i/getNumVars()); break;
453 case rs::OLD:
454 case rs::OLDINTERESTED:
455 if (!havesrc)
456 {
457 members.insert(members.begin(), i/getNumVars());
458 havesrc=true;
459 }
460 break;
461 }
462 }
463 return makeComm(srccom, com, members);
464 }
465 else // for people not in involved in the value shipping
466 { // This would be a nice time to use MPI_Comm_create_group
467 // but it does not exist in MPI2.1
468 return MPI_Comm_create(srccom, MPI_GROUP_EMPTY, &com);
469 }
470 }
471
472 #endif
473
474
475 bool SubWorld::synchVariableValues(std::string& err)
476 {
477 #ifdef ESYS_MPI
478 // There are three possibilities here but since all worlds have the same knowledge
479 // we can be sure that they will all make the same choice
480 // 1) No updates are required
481 // 2) There is a single world with a new value so it can broadcast it
482 // 3) There are multiple worlds with updates
483
484 // need to keep track of which vars have updates
485 std::vector<std::string> varswithupdates;
486
487 int vnum=0;
488 for (str2reduce::iterator it=reducemap.begin();it!=reducemap.end();++it, ++vnum)
489 {
490 if (it->second->localOnly())
491 {
492 continue;
493 }
494 // check to see if anyone needs it
495 int needcount=0; // who wants a new value
496 int newcount=0; // who has a new version
497 int oldcount=0; // who has an old version
498 int oldintcount=0;
499 newcount=globalvarcounts[it->first][rs::NEW];
500 oldcount=globalvarcounts[it->first][rs::OLD];
501 oldintcount=globalvarcounts[it->first][rs::OLDINTERESTED];
502 needcount=globalvarcounts[it->first][rs::INTERESTED]+oldintcount;
503 if (newcount>0)
504 {
505 varswithupdates.push_back(it->first);
506 }
507 if (needcount+newcount+oldcount==0)
508 {
509 continue; // noone cares about this variable
510 }
511 if (needcount>0 && (oldcount+oldintcount+newcount)==0)
512 {
513 err="Import attempted for a variable \""+(it->first)+"\" with no value.";
514 return false;
515 }
516 // worlds have the variable but noone is interested in it
517 // note that if there are multiple new values, we still want to merge them
518 if ((needcount==0) && (newcount<=1))
519 {
520 continue;
521 }
522 if (swcount==1)
523 { // nobody else to communicate with
524 continue;
525 }
526 // to reach this point, there must be >=1 source and >=1 sink and multiple worlds
527 // first deal updates as source(s)
528 if (newcount==1) // only one update so send from that
529 {
530 MPI_Comm com;
531 if (!makeGroupComm1(corrmpi->comm, vnum, varstate[it->first],com))
532 {
533 err="Error creating group for sharing values,";
534 return false;
535 }
536 if (varstate[it->first]!=rs::NONE && varstate[it->first]!=rs::OLD)
537 {
538 it->second->groupSend(com);
539 // Now record the fact that we have the variable now
540 if (varstate[it->first]==rs::INTERESTED)
541 {
542 setMyVarState(it->first, rs::OLDINTERESTED);
543 }
544 }
545 // disolve the group
546 MPI_Comm_free(&com);
547 continue;
548 }
549 if (newcount>1)
550 {
551 // form a group to send to [updates and interested and oldinterested]
552 MPI_Comm com;
553 if (!makeGroupComm1(corrmpi->comm, vnum, varstate[it->first],com))
554 {
555 err="Error creating group for sharing values,";
556 return false;
557 }
558 it->second->groupReduce(com,varstate[it->first]);
559 MPI_Comm_free(&com);
560 continue;
561 }
562 // at this point, we need to ship info around but there are no updates
563 // that is, we are shipping an old copy
564 // picking a source arbitarily (the first one in the array)
565
566 // but first, eliminate the special case where the only interested ones
567 // already have a copy
568 if (oldintcount==needcount)
569 {
570 continue;
571 }
572 MPI_Comm com;
573 if (!makeGroupComm2(corrmpi->comm, vnum, varstate[it->first],com))
574 {
575 err="Error creating group for sharing values";
576 return false;
577 }
578 // form group to send to [latestsource and interested]
579 it->second->groupSend(com);
580 // dissolve the group
581 MPI_Comm_free(&com);
582 }
583 // now we need to age any out of date copies of vars
584 for (size_t i=0;i<varswithupdates.size();++i)
585 {
586 std::string vname=varswithupdates[i];
587 if (varstate[vname]==rs::NEW)
588 {
589 setMyVarState(vname, rs::OLD);
590 }
591 else if (varstate[vname]==rs::OLD)
592 {
593 setMyVarState(vname, rs::NONE);
594 reducemap[vname]->clear();
595 }
596 }
597 #endif
598 return true;
599 }
600
601 bool SubWorld::amLeader()
602 {
603 return swmpi->rank==0;
604 }
605
606 // Find out which variables the local queued jobs are interested in
607 // share that info around
608 bool SubWorld::synchVariableInfo(std::string& err)
609 {
610 if (manualimports) // manual control over imports
611 {
612 for (size_t i=0;i<jobvec.size();++i)
613 {
614 bp::list wanted=bp::extract<bp::list>(jobvec[i].attr("wantedvalues"))();
615 for (size_t j=0;j<len(wanted);++j)
616 {
617 bp::extract<std::string> exs(wanted[j]);
618 if (!exs.check())
619 {
620 err="names in wantedvalues must be strings";
621 return false;
622 }
623 std::string n=exs();
624 // now we need to check to see if this value is known
625 str2char::iterator it=varstate.find(n);
626 if (it==varstate.end())
627 {
628 err="Attempt to import variable \""+n+"\". SplitWorld was not told about this variable.";
629 return false;
630 }
631 // So at least one job wants this variable
632 switch (it->second)
633 {
634 case rs::NONE: it->second=rs::INTERESTED; break;
635 case rs::INTERESTED: break;
636 case rs::OLD: it->second=rs::OLDINTERESTED; break;
637 case rs::NEW: break;
638 default:
639 err="Unknown variable state";
640 return false;
641 }
642 }
643 }
644 }
645 // Make a vector to hold the info from the map (so we can send it around)
646 std::vector<char> lb(getNumVars(), rs::NONE);
647 size_t i=0;
648 for (str2char::iterator it=varstate.begin();it!=varstate.end();++it,++i)
649 {
650 lb[i]=it->second;
651 }
652
653
654 #ifdef ESYS_MPI
655 // Vector to hold the result
656 globalvarinfo.resize(getNumVars()*swcount, rs::NONE);
657 if (amLeader()) // we only need on representative from each world to send
658 {
659 // The leaders of each world, send their variable information to the proc "0" in
660 // the global world (which will be the leader of subworld "0").
661 // There is an issue here if this operation fails
662 if (MPI_Gather(&lb[0], getNumVars(), MPI_CHAR, &globalvarinfo[0], getNumVars(),
663 MPI_CHAR, 0, getCorrMPI()->comm)!=MPI_SUCCESS)
664 {
665 for (size_t i=0;i<globalvarinfo.size();++i)
666 {
667 globalvarinfo[i]=rs::ERROR;
668 }
669 }
670 }
671 // now share the combined info with all processes
672 if ((MPI_Bcast(&globalvarinfo[0], globalvarinfo.size(), MPI_CHAR, 0, everyone->comm)!=MPI_SUCCESS)
673 || (globalvarinfo[0]==rs::ERROR))
674 {
675 err="Error while gathering variable use information.";
676 return false;
677 }
678 // now we convert that info into a form which is easier to read
679 int p=0;
680 for (str2reduce::iterator it=reducemap.begin();it!=reducemap.end();++it,++p)
681 {
682 globalvarcounts[it->first][rs::NONE]=0;
683 globalvarcounts[it->first][rs::INTERESTED]=0;
684 globalvarcounts[it->first][rs::OLD]=0;
685 globalvarcounts[it->first][rs::OLDINTERESTED]=0;
686 globalvarcounts[it->first][rs::NEW]=0;
687 for (int j=p;j<globalvarinfo.size();j+=getNumVars())
688 {
689 if (globalvarinfo[j]<=rs::NEW)
690 {
691 globalvarcounts[it->first][globalvarinfo[j]]++;
692 }
693 }
694 }
695
696 #endif
697 if (!manualimports)
698 {
699 // import all known variables _BUT_ don't import something if noone has a value
700 // for it
701 int vnum=0;
702 for (str2char::iterator it=varstate.begin();it!=varstate.end();++it, ++vnum)
703 {
704 #ifdef ESYS_MPI
705 // if at least one world has a value for a variable
706 if (globalvarcounts[it->first][rs::OLDINTERESTED]
707 + globalvarcounts[it->first][rs::OLD]
708 + globalvarcounts[it->first][rs::NEW] > 0 )
709 {
710 #endif
711
712 if (it->second==rs::NONE)
713 {
714 it->second=rs::INTERESTED;
715 }
716 else if (it->second==rs::OLD)
717 {
718 it->second=rs::OLDINTERESTED;
719 }
720 #ifdef ESYS_MPI
721 // now we need to update the globalvarinfo to record all the extra interest
722 for (int j=vnum;j<globalvarinfo.size();j+=getNumVars())
723 {
724 if (globalvarinfo[j]==rs::NONE)
725 {
726 globalvarinfo[j]=rs::INTERESTED;
727 globalvarcounts[it->first][rs::NONE]--;
728 globalvarcounts[it->first][rs::INTERESTED]++;
729 }
730 else if (globalvarinfo[j]==rs::OLD)
731 {
732 globalvarinfo[j]=rs::OLDINTERESTED;
733 globalvarcounts[it->first][rs::OLD]--;
734 globalvarcounts[it->first][rs::OLDINTERESTED]++;
735 }
736
737 }
738 }
739 #endif
740 }
741 }
742 #ifdef ESYS_MPI
743 globalinfoinvalid=false;
744 #endif
745
746 return true;
747 }
748
749 // if 4, a Job performed an invalid export
750 // if 3, a Job threw an exception
751 // if 2, a Job did not return a bool
752 // if 1, at least one Job returned False
753 // if 0, all jobs in this world returned True
754 char SubWorld::runJobs(std::string& errormsg)
755 {
756 errormsg.clear();
757 int ret=0;
758 try
759 {
760 for (size_t i=0;i<jobvec.size();++i)
761 {
762 boost::python::object result=jobvec[i].attr("work")();
763 boost::python::extract<bool> ex(result);
764 if (!ex.check() || (result.is_none()))
765 {
766 return 2;
767 }
768 // check to see if we need to keep running
769 if (!ex())
770 {
771 ret=1;
772 }
773
774 }
775 }
776 catch (boost::python::error_already_set e)
777 {
778 getStringFromPyException(e, errormsg);
779 return 3;
780 }
781 return ret;
782 }
783
784 size_t SubWorld::getNumVars()
785 {
786 return reducemap.size();
787 }
788
789 // if manual import is false, add this new variable to all the Jobs in this world
790 void SubWorld::addVariable(std::string& name, Reducer_ptr& rp)
791 {
792 if (reducemap.find(name)!=reducemap.end())
793 {
794 std::ostringstream oss;
795 throw SplitWorldException(oss.str());
796 }
797 reducemap[name]=rp;
798 varstate[name]=reducerstatus::NONE;
799 if (!manualimports)
800 {
801 for (size_t i=0;i<jobvec.size();++i)
802 {
803 jobvec[i].attr("requestImport")(name);
804 }
805 }
806 #ifdef ESYS_MPI
807 globalinfoinvalid=true; // since we need to regenerate globalvarinfo
808 #endif
809 }
810
811 void SubWorld::removeVariable(std::string& s)
812 {
813 reducemap.erase(s);
814 varstate.erase(s);
815 #ifdef ESYS_MPI
816 globalinfoinvalid=true;
817 globalvarinfo.resize(0);
818 globalvarcounts.erase(s);
819 #endif
820 }
821
822 void SubWorld::clearVariable(std::string& name)
823 {
824 str2reduce::iterator it=reducemap.find(name);
825 if (it==reducemap.end())
826 {
827 return;
828 }
829 it->second->reset();
830 // if we got here, we must have a valid name so we can change state directly
831 setAllVarsState(name, rs::NONE);
832 }
833
834 void SubWorld::resetInterest()
835 {
836 for (str2char::iterator it=varstate.begin();it!=varstate.end();++it)
837 {
838 if (it->second==rs::INTERESTED)
839 {
840 it->second=rs::NONE;
841 }
842 else if (it->second==rs::OLDINTERESTED)
843 {
844 it->second=rs::OLD;
845 }
846 }
847 }
848

  ViewVC Help
Powered by ViewVC 1.1.26