27 |
import numarray |
import numarray |
28 |
import operator |
import operator |
29 |
import itertools |
import itertools |
30 |
|
import time |
31 |
|
import os |
32 |
|
|
33 |
# import the 'set' module if it's not defined (python2.3/2.4 difference) |
# import the 'set' module if it's not defined (python2.3/2.4 difference) |
34 |
try: |
try: |
73 |
self.__dom = minidom.parseString(xml) |
self.__dom = minidom.parseString(xml) |
74 |
self.__linkable_object_registry= {} |
self.__linkable_object_registry= {} |
75 |
self.__link_registry= [] |
self.__link_registry= [] |
76 |
self.__esys=self.__dom.firstChild |
self.__esys=self.__dom.getElementsByTagName('ESys')[0] |
77 |
self.debug=debug |
self.debug=debug |
78 |
|
|
79 |
def getClassPath(self, node): |
def getClassPath(self, node): |
216 |
self.attribute = None |
self.attribute = None |
217 |
self.setAttributeName(attribute) |
self.setAttributeName(attribute) |
218 |
|
|
219 |
|
def getTarget(self): |
220 |
|
""" |
221 |
|
returns the target |
222 |
|
""" |
223 |
|
return self.target |
224 |
def getAttributeName(self): |
def getAttributeName(self): |
225 |
""" |
""" |
226 |
returns the name of the attribute the link is pointing to |
returns the name of the attribute the link is pointing to |
469 |
setattr(self,prm,value) |
setattr(self,prm,value) |
470 |
self.parameters.add(prm) |
self.parameters.add(prm) |
471 |
|
|
|
self.trace("parameter %s has been declared."%prm) |
|
|
|
|
472 |
def releaseParameters(self,name): |
def releaseParameters(self,name): |
473 |
""" |
""" |
474 |
Removes parameter name from the paramameters. |
Removes parameter name from the paramameters. |
476 |
if self.isParameter(name): |
if self.isParameter(name): |
477 |
self.parameters.remove(name) |
self.parameters.remove(name) |
478 |
self.trace("parameter %s has been removed."%name) |
self.trace("parameter %s has been removed."%name) |
479 |
|
|
480 |
|
def checkLinkTargets(self, models, hash): |
481 |
|
""" |
482 |
|
returns a set of tuples ("<self>(<name>)", <target model>) if the parameter <name> is linked to model <target model> |
483 |
|
but <target model> is not in the list models. If the a parameter is linked to another parameter set which is not in the hash list |
484 |
|
the parameter set is checked for its models. hash gives the call history. |
485 |
|
""" |
486 |
|
out=set() |
487 |
|
for name, value in self: |
488 |
|
if isinstance(value, Link): |
489 |
|
m=value.getTarget() |
490 |
|
if isinstance(m, Model): |
491 |
|
if not m in models: out.add( (str(self)+"("+name+")",m) ) |
492 |
|
elif isinstance(m, ParameterSet) and not m in hash: |
493 |
|
out|=set( [ (str(self)+"("+name+")."+f[0],f[1]) for f in m.checkLinkTargets(models, hash+[ self ] ) ] ) |
494 |
|
return out |
495 |
|
|
496 |
def __iter__(self): |
def __iter__(self): |
497 |
""" |
""" |
543 |
for i in value: |
for i in value: |
544 |
if isinstance(i, bool): |
if isinstance(i, bool): |
545 |
elem_type = max(elem_type,0) |
elem_type = max(elem_type,0) |
546 |
if isinstance(i, int) and not isinstance(i, bool): |
elif isinstance(i, int): |
547 |
elem_type = max(elem_type,1) |
elem_type = max(elem_type,1) |
548 |
if isinstance(i, float): |
elif isinstance(i, float): |
549 |
elem_type = max(elem_type,2) |
elem_type = max(elem_type,2) |
550 |
if elem_type == 0: value = numarray.array(value,numarray.Bool) |
if elem_type == 0: value = numarray.array(value,numarray.Bool) |
551 |
if elem_type == 1: value = numarray.array(value,numarray.Int) |
if elem_type == 1: value = numarray.array(value,numarray.Int) |
603 |
dic.appendChild(i) |
dic.appendChild(i) |
604 |
param.appendChild(dic) |
param.appendChild(dic) |
605 |
else: |
else: |
|
print value |
|
606 |
raise ValueError("cannot serialize %s type to XML."%str(value.__class__)) |
raise ValueError("cannot serialize %s type to XML."%str(value.__class__)) |
607 |
|
|
608 |
node.appendChild(param) |
node.appendChild(param) |
691 |
parameters[pname] = pvalue |
parameters[pname] = pvalue |
692 |
|
|
693 |
# Create the instance of ParameterSet |
# Create the instance of ParameterSet |
694 |
o = cls(debug=esysxml.debug) |
try: |
695 |
|
o = cls(debug=esysxml.debug) |
696 |
|
except TypeError, inst: |
697 |
|
print inst.args[0] |
698 |
|
if inst.args[0]=="__init__() got an unexpected keyword argument 'debug'": |
699 |
|
raise TypeError("The Model class %s __init__ needs to have argument 'debug'.") |
700 |
|
else: |
701 |
|
raise inst |
702 |
o.declareParameters(parameters) |
o.declareParameters(parameters) |
703 |
esysxml.registerLinkableObject(o, node) |
esysxml.registerLinkableObject(o, node) |
704 |
return o |
return o |
751 |
return "<%s %d>"%(self.__class__.__name__,id(self)) |
return "<%s %d>"%(self.__class__.__name__,id(self)) |
752 |
|
|
753 |
|
|
754 |
|
def setUp(self): |
755 |
|
""" |
756 |
|
Sets up the model. |
757 |
|
|
758 |
|
This function may be overwritten. |
759 |
|
""" |
760 |
|
pass |
761 |
|
|
762 |
def doInitialization(self): |
def doInitialization(self): |
763 |
""" |
""" |
764 |
Initializes the time stepping scheme. |
Initializes the time stepping scheme. This method is not called in case of a restart. |
765 |
|
|
766 |
This function may be overwritten. |
This function may be overwritten. |
767 |
""" |
""" |
768 |
pass |
pass |
769 |
def doInitialStep(self): |
def doInitialStep(self): |
770 |
""" |
""" |
771 |
performs an iteration step in the initialization phase |
performs an iteration step in the initialization phase. This method is not called in case of a restart. |
772 |
|
|
773 |
This function may be overwritten. |
This function may be overwritten. |
774 |
""" |
""" |
776 |
|
|
777 |
def terminateInitialIteration(self): |
def terminateInitialIteration(self): |
778 |
""" |
""" |
779 |
Returns True if iteration at the inital phase is terminated. |
Returns True if iteration at the inital phase is terminated. |
780 |
""" |
""" |
781 |
return True |
return True |
782 |
|
|
783 |
def doInitialPostprocessing(self): |
def doInitialPostprocessing(self): |
784 |
""" |
""" |
785 |
finalises the initialization iteration process |
finalises the initialization iteration process. This method is not called in case of a restart. |
786 |
|
|
787 |
This function may be overwritten. |
This function may be overwritten. |
788 |
""" |
""" |
879 |
Initiates a simulation from a list of models. |
Initiates a simulation from a list of models. |
880 |
""" |
""" |
881 |
super(Simulation, self).__init__(**kwargs) |
super(Simulation, self).__init__(**kwargs) |
882 |
|
self.declareParameter(time=0., |
883 |
|
time_step=0, |
884 |
|
dt = self.UNDEF_DT) |
885 |
|
for m in models: |
886 |
|
if not isinstance(m, Model): |
887 |
|
raise TypeError("%s is not a subclass of Model."%m) |
888 |
self.__models=[] |
self.__models=[] |
|
|
|
889 |
for i in range(len(models)): |
for i in range(len(models)): |
890 |
self[i] = models[i] |
self[i] = models[i] |
891 |
|
|
930 |
""" |
""" |
931 |
return len(self.__models) |
return len(self.__models) |
932 |
|
|
933 |
|
def getAllModels(self): |
934 |
|
""" |
935 |
|
returns a list of all models used in the Simulation including subsimulations |
936 |
|
""" |
937 |
|
out=[] |
938 |
|
for m in self.iterModels(): |
939 |
|
if isinstance(m, Simulation): |
940 |
|
out+=m.getAllModels() |
941 |
|
else: |
942 |
|
out.append(m) |
943 |
|
return list(set(out)) |
944 |
|
|
945 |
|
def checkModels(self, models, hash): |
946 |
|
""" |
947 |
|
returns a list of (model,parameter, target model ) if the the parameter of model |
948 |
|
is linking to the target_model which is not in list of models. |
949 |
|
""" |
950 |
|
out=self.checkLinkTargets(models, hash + [self]) |
951 |
|
for m in self.iterModels(): |
952 |
|
if isinstance(m, Simulation): |
953 |
|
out|=m.checkModels(models, hash) |
954 |
|
else: |
955 |
|
out|=m.checkLinkTargets(models, hash + [self]) |
956 |
|
return set( [ (str(self)+"."+f[0],f[1]) for f in out ] ) |
957 |
|
|
958 |
|
|
959 |
def getSafeTimeStepSize(self,dt): |
def getSafeTimeStepSize(self,dt): |
960 |
""" |
""" |
964 |
""" |
""" |
965 |
out=min([o.getSafeTimeStepSize(dt) for o in self.iterModels()]) |
out=min([o.getSafeTimeStepSize(dt) for o in self.iterModels()]) |
966 |
return out |
return out |
967 |
|
|
968 |
|
def setUp(self): |
969 |
|
""" |
970 |
|
performs the setup for all models |
971 |
|
""" |
972 |
|
for o in self.iterModels(): |
973 |
|
o.setUp() |
974 |
|
|
975 |
def doInitialization(self): |
def doInitialization(self): |
976 |
""" |
""" |
977 |
Initializes all models. |
Initializes all models. |
978 |
""" |
""" |
|
self.n=0 |
|
|
self.tn=0. |
|
979 |
for o in self.iterModels(): |
for o in self.iterModels(): |
980 |
o.doInitialization() |
o.doInitialization() |
981 |
def doInitialStep(self): |
def doInitialStep(self): |
1039 |
""" |
""" |
1040 |
for o in self.iterModels(): |
for o in self.iterModels(): |
1041 |
o.doStepPostprocessing(dt) |
o.doStepPostprocessing(dt) |
1042 |
self.n+=1 |
self.time_step+=1 |
1043 |
self.tn+=dt |
self.time+=dt |
1044 |
|
self.dt=dt |
1045 |
|
|
1046 |
def doStep(self,dt): |
def doStep(self,dt): |
1047 |
""" |
""" |
1055 |
""" |
""" |
1056 |
self.iter=0 |
self.iter=0 |
1057 |
while not self.terminateIteration(): |
while not self.terminateIteration(): |
1058 |
if self.iter==0: self.trace("iteration at %d-th time step %e starts"%(self.n+1,self.tn+dt)) |
if self.iter==0: self.trace("iteration at %d-th time step %e starts"%(self.time_step+1,self.time+dt)) |
1059 |
self.iter+=1 |
self.iter+=1 |
1060 |
self.trace("iteration step %d"%(self.iter)) |
self.trace("iteration step %d"%(self.iter)) |
1061 |
for o in self.iterModels(): |
for o in self.iterModels(): |
1062 |
o.doStep(dt) |
o.doStep(dt) |
1063 |
if self.iter>0: self.trace("iteration at %d-th time step %e finalized."%(self.n+1,self.tn+dt)) |
if self.iter>0: self.trace("iteration at %d-th time step %e finalized."%(self.time_step+1,self.time+dt)) |
1064 |
|
|
1065 |
def run(self,check_point=None): |
def run(self,check_pointing=None): |
1066 |
""" |
""" |
1067 |
Run the simulation by performing essentially:: |
Run the simulation by performing essentially:: |
1068 |
|
|
1069 |
self.doInitialization() |
self.setUp() |
1070 |
while not self.terminateInitialIteration(): self.doInitialStep() |
if not restart: |
1071 |
self.doInitialPostprocessing() |
self.doInitialization() |
1072 |
|
while not self.terminateInitialIteration(): self.doInitialStep() |
1073 |
|
self.doInitialPostprocessing() |
1074 |
while not self.finalize(): |
while not self.finalize(): |
1075 |
dt=self.getSafeTimeStepSize() |
dt=self.getSafeTimeStepSize() |
1076 |
self.doStep(dt) |
self.doStepPreprocessing(dt_new) |
1077 |
if n%check_point==0: |
self.doStep(dt_new) |
1078 |
self.writeXML() |
self.doStepPostprocessing(dt_new) |
1079 |
self.doFinalization() |
self.doFinalization() |
1080 |
|
|
1081 |
If one of the models in throws a C{FailedTimeStepError} exception a |
If one of the models in throws a C{FailedTimeStepError} exception a |
1088 |
In both cases the time integration is given up after |
In both cases the time integration is given up after |
1089 |
C{Simulation.FAILED_TIME_STEPS_MAX} attempts. |
C{Simulation.FAILED_TIME_STEPS_MAX} attempts. |
1090 |
""" |
""" |
1091 |
self.doInitialization() |
# check the completness of the models: |
1092 |
self.doInitialStep() |
# first a list of all the models involved in the simulation including subsimulations: |
1093 |
self.doInitialPostprocessing() |
# |
1094 |
dt=self.UNDEF_DT |
missing=self.checkModels(self.getAllModels(), []) |
1095 |
|
if len(missing)>0: |
1096 |
|
msg="" |
1097 |
|
for l in missing: |
1098 |
|
msg+="\n\t"+str(l[1])+" at "+l[0] |
1099 |
|
raise MissingLink("link targets missing in the Simulation: %s"%msg) |
1100 |
|
#============================== |
1101 |
|
self.setUp() |
1102 |
|
if self.time_step < 1: |
1103 |
|
self.doInitialization() |
1104 |
|
self.doInitialStep() |
1105 |
|
self.doInitialPostprocessing() |
1106 |
while not self.finalize(): |
while not self.finalize(): |
1107 |
step_fail_counter=0 |
step_fail_counter=0 |
1108 |
iteration_fail_counter=0 |
iteration_fail_counter=0 |
1109 |
if self.n==0: |
if self.time_step==0: |
1110 |
dt_new=self.getSafeTimeStepSize(dt) |
dt_new=self.getSafeTimeStepSize(self.dt) |
1111 |
else: |
else: |
1112 |
dt_new=min(max(self.getSafeTimeStepSize(dt),dt/self.MAX_CHANGE_OF_DT),dt*self.MAX_CHANGE_OF_DT) |
dt_new=min(max(self.getSafeTimeStepSize(self.dt),self.dt/self.MAX_CHANGE_OF_DT),self.dt*self.MAX_CHANGE_OF_DT) |
1113 |
self.trace("%d. time step %e (step size %e.)" % (self.n+1,self.tn+dt_new,dt_new)) |
self.trace("%d. time step %e (step size %e.)" % (self.time_step+1,self.time+dt_new,dt_new)) |
1114 |
end_of_step=False |
end_of_step=False |
1115 |
while not end_of_step: |
while not end_of_step: |
1116 |
end_of_step=True |
end_of_step=True |
1117 |
if not dt_new>0: |
if not dt_new>0: |
1118 |
raise NonPositiveStepSizeError("non-positive step size in step %d"%(self.n+1)) |
raise NonPositiveStepSizeError("non-positive step size in step %d"%(self.time_step+1)) |
1119 |
try: |
try: |
1120 |
self.doStepPreprocessing(dt_new) |
self.doStepPreprocessing(dt_new) |
1121 |
self.doStep(dt_new) |
self.doStep(dt_new) |
1128 |
raise SimulationBreakDownError("reduction of time step to achieve convergence failed after %s steps."%self.FAILED_TIME_STEPS_MAX) |
raise SimulationBreakDownError("reduction of time step to achieve convergence failed after %s steps."%self.FAILED_TIME_STEPS_MAX) |
1129 |
self.trace("Iteration failed. Time step is repeated with new step size %s."%dt_new) |
self.trace("Iteration failed. Time step is repeated with new step size %s."%dt_new) |
1130 |
except FailedTimeStepError: |
except FailedTimeStepError: |
1131 |
dt_new=self.getSafeTimeStepSize(dt) |
dt_new=self.getSafeTimeStepSize(self.dt) |
1132 |
end_of_step=False |
end_of_step=False |
1133 |
step_fail_counter+=1 |
step_fail_counter+=1 |
1134 |
self.trace("Time step is repeated with new time step size %s."%dt_new) |
self.trace("Time step is repeated with new time step size %s."%dt_new) |
1135 |
if step_fail_counter>self.FAILED_TIME_STEPS_MAX: |
if step_fail_counter>self.FAILED_TIME_STEPS_MAX: |
1136 |
raise SimulationBreakDownError("Time integration is given up after %d attempts."%step_fail_counter) |
raise SimulationBreakDownError("Time integration is given up after %d attempts."%step_fail_counter) |
1137 |
dt=dt_new |
if not check_pointing==None: |
1138 |
if not check_point==None: |
if check_pointing.doDump(): |
|
if n%check_point==0: |
|
1139 |
self.trace("check point is created.") |
self.trace("check point is created.") |
1140 |
self.writeXML() |
self.writeXML() |
1141 |
self.doFinalization() |
self.doFinalization() |
1161 |
if isinstance(n, minidom.Text): |
if isinstance(n, minidom.Text): |
1162 |
continue |
continue |
1163 |
sims.append(esysxml.getComponent(n)) |
sims.append(esysxml.getComponent(n)) |
1164 |
sims.sort(cmp=_comp) |
sims.sort(_comp) |
1165 |
sim=cls([s[1] for s in sims], debug=esysxml.debug) |
sim=cls([s[1] for s in sims], debug=esysxml.debug) |
1166 |
esysxml.registerLinkableObject(sim, node) |
esysxml.registerLinkableObject(sim, node) |
1167 |
return sim |
return sim |
1205 |
""" |
""" |
1206 |
pass |
pass |
1207 |
|
|
1208 |
|
class MissingLink(Exception): |
1209 |
|
""" |
1210 |
|
Exception thrown when a link is missing |
1211 |
|
""" |
1212 |
|
pass |
1213 |
|
|
1214 |
class DataSource(object): |
class DataSource(object): |
1215 |
""" |
""" |
1216 |
Class for handling data sources, including local and remote files. This class is under development. |
Class for handling data sources, including local and remote files. This class is under development. |
1240 |
return self.uri |
return self.uri |
1241 |
|
|
1242 |
fromDom = classmethod(fromDom) |
fromDom = classmethod(fromDom) |
1243 |
|
|
1244 |
|
class RestartManager(object): |
1245 |
|
""" |
1246 |
|
A restart manager which does two things: it decides when restart files have created (when doDump returns true) and |
1247 |
|
manages directories for restart files. The method getNewDumper creates a new directory and returns its name. |
1248 |
|
|
1249 |
|
This restart manager will decide to dump restart files if every dump_step calls of doDump or |
1250 |
|
if more than dump_time since the last dump has elapsed. The restart manager controls two directories for dumping restart data, namely |
1251 |
|
for the current and previous dump. This way the previous dump can be used for restart in the case the current dump failed. |
1252 |
|
|
1253 |
|
@cvar SEC: unit of seconds, for instance for 5*RestartManager.SEC to define 5 seconds. |
1254 |
|
@cvar MIN: unit of minutes, for instance for 5*RestartManager.MIN to define 5 minutes. |
1255 |
|
@cvar H: unit of hours, for instance for 5*RestartManager.H to define 5 hours. |
1256 |
|
@cvar D: unit of days, for instance for 5*RestartManager.D to define 5 days. |
1257 |
|
""" |
1258 |
|
SEC=1. |
1259 |
|
MIN=60. |
1260 |
|
H=360. |
1261 |
|
D=8640. |
1262 |
|
def __init__(self,dump_time=1080., dump_step=None, dumper=None): |
1263 |
|
""" |
1264 |
|
initializes the RestartManager. |
1265 |
|
|
1266 |
|
@param dump_time: defines the minimum time interval in SEC between to dumps. If None, time is not used as criterion. |
1267 |
|
@param dump_step: defines the number of calls of doDump between to dump events. If None, the call counter is not used as criterion. |
1268 |
|
@param dumper: defines the directory for dumping restart files. Additionally the directories dumper+"_bkp" and dumper+"_bkp2" are used. |
1269 |
|
if the directory does not exist it is created. If dumper is not present a unique directory within the current |
1270 |
|
working directory is used. |
1271 |
|
""" |
1272 |
|
self.__dump_step=dump_time |
1273 |
|
self.__dump_time=dump_step |
1274 |
|
self.__counter=0 |
1275 |
|
self.__saveMarker() |
1276 |
|
if dumper == None: |
1277 |
|
self.__dumper="restart"+str(os.getpid()) |
1278 |
|
else: |
1279 |
|
self.__dumper=dumper |
1280 |
|
self.__dumper_bkp=self.__dumper+"_bkp" |
1281 |
|
self.__dumper_bkp2=self.__dumper+"_bkp2" |
1282 |
|
self.__current_dumper=None |
1283 |
|
def __saveMarker(self): |
1284 |
|
self.__last_restart_time=time.time() |
1285 |
|
self.__last_restart_counter=self.__counter |
1286 |
|
def getCurrentDumper(self): |
1287 |
|
""" |
1288 |
|
returns the name of the currently used dumper |
1289 |
|
""" |
1290 |
|
return self.__current_dumper |
1291 |
|
def doDump(self): |
1292 |
|
""" |
1293 |
|
returns true the restart should be dumped. use C{getNewDumper} to get the directory name to be used. |
1294 |
|
""" |
1295 |
|
if self.__dump_step == None: |
1296 |
|
if self.__dump_step == None: |
1297 |
|
out = False |
1298 |
|
else: |
1299 |
|
out = (self.__dump_step + self.__last_restart_counter) <= self.__counter |
1300 |
|
else: |
1301 |
|
if dump_step == None: |
1302 |
|
out = (self.__last_restart_time + self.__dump_time) <= time.time() |
1303 |
|
else: |
1304 |
|
out = ( (self.__dump_step + self.__last_restart_counter) <= self.__counter) \ |
1305 |
|
or ( (self.__last_restart_time + self.__dump_time) <= time.time() ) |
1306 |
|
if out: self.__saveMarker() |
1307 |
|
self__counter+=1 |
1308 |
|
def getNewDumper(self): |
1309 |
|
""" |
1310 |
|
creates a new directory to be used for dumping and returns its name. |
1311 |
|
""" |
1312 |
|
if os.access(self.__dumper_bkp,os.F_OK): |
1313 |
|
if os.access(self.__dumper_bkp2, os.F_OK): |
1314 |
|
raise RunTimeError("please remove %s."%self.__dumper_bkp2) |
1315 |
|
try: |
1316 |
|
os.rename(self.__dumper_bkp, self.__dumper_bkp2) |
1317 |
|
except: |
1318 |
|
self.__current_dumper=self.__dumper |
1319 |
|
raise RunTimeError("renaming back-up directory %s failed. Use %s for restart."%(self.__dumper_bkp,self.__dumper)) |
1320 |
|
if os.access(self.__dumper,os.F_OK): |
1321 |
|
if os.access(self.__dumper_bkp, os.F_OK): |
1322 |
|
raise RunTimeError("please remove %s."%self.__dumper_bkp) |
1323 |
|
try: |
1324 |
|
os.rename(self.__dumper, self.__dumper_bkp) |
1325 |
|
except: |
1326 |
|
self.__current_dumper=self.__dumper_bkp2 |
1327 |
|
raise RunTimeError("moving directory %s to back-up failed. Use %s for restart."%(self.__dumper,self.__dumper_bkp2)) |
1328 |
|
try: |
1329 |
|
os.mkdir(self.__dumper) |
1330 |
|
except: |
1331 |
|
self.__current_dumper=self.__dumper_bkp |
1332 |
|
raise RunTimeError("creating a new restart directory %s failed. Use %s for restart."%(self.__dumper,self.__dumper_bkp)) |
1333 |
|
if os.access(self.__dumper_bkp2, os.F_OK): os.rmdir(self.__dumper_bkp2) |
1334 |
|
return self.getCurrentDumper() |
1335 |
|
|
1336 |
|
|
1337 |
# vim: expandtab shiftwidth=4: |
# vim: expandtab shiftwidth=4: |