def makeGenInfoEntry(generator, allgen_names, swmap_list=[]): """Create an entry for the genInfo attribute of a Model.""" assert isinstance(allgen_names, list), \ "'allgen_names' argument must be a list" special_reasons = ['time'] + generator.variables.keys() assert generator.name not in special_reasons + ['terminate'], \ "Cannot use variable names or internal names 'time' and 'terminate' as generator names" try: allEndReasonNames = map(lambda (n,o):n, generator.eventstruct.getTermEvents()) \ + special_reasons except AttributeError: # no events associated with the generator allEndReasonNames = special_reasons assert generator.name in allgen_names, ( 'Generator`s name not in list of all ' 'available Generator names!') assert alltrue([name not in allEndReasonNames for name in allgen_names]), \ 'Generator names overlapped with event or variable names' alltarg_names = allgen_names + ['terminate'] # if no event map function specified, assume the identity fn seenReasons = [] swmap_pairs = [] if swmap_list != []: for mapentry in swmap_list: # check the entries of swmap_list and turn into a # (reason, infopair) pair, adding a default event map function # to some entries reason = mapentry[0] mapping_info = mapentry[1] if len(mapentry) > 2: raise ValueError( "mapping entry must be (reason, infopair) tuple") if isinstance(mapping_info, tuple): genTargetName = mapping_info[0] numargs = len(mapping_info) elif isinstance(mapping_info, str): genTargetName = mapentry[1] numargs = 1 else: raise TypeError("Invalid event mapping entry") if numargs == 2: epmap = mapping_info[1] assert isinstance(epmap, EvMapping), "Must supply EvMapping class" swmap_pairs.append((reason, mapping_info)) elif numargs == 1: # use default identity mapping fn for event # and make this entry into a three-tuple swmap_pairs.append((reason, (genTargetName, EvMapping()))) else: raise ValueError("Expected 2 or 3 arguments to Generator " "switch map entry") assert reason not in seenReasons, ('reason cannot appear more than' ' once in map domain') seenReasons.append(reason) assert reason in allEndReasonNames, ("name '" + reason + "' in map " "domain is missing") assert genTargetName in alltarg_names, ("name '" + genTargetName + "' in " "map range is missing") else: # There had better be only a single Generator in allgen_names, # otherwise we need a map assert len(allgen_names) == 1, ( "There must be an event mapping " "specified when there is more than one Generator in the Model") unseen_sr = remain(allEndReasonNames, seenReasons) if unseen_sr != []: # then there are 'end reasons' that do not have switch rules, # so give them defaults (terminate) for r in unseen_sr: swmap_pairs.append((r, ('terminate', EvMapping()))) if len(swmap_pairs) != len(allEndReasonNames): info(dict(swmap_pairs)) print "(%i in total),versus:" % len(swmap_pairs) print allEndReasonNames, "(%i in total)" % len(allEndReasonNames) raise ValueError('Incorrect number of map pairs given in argument') return {generator.name: (generator, dict(swmap_pairs))}
def getModel(self): """Build and return (hybrid) model made up of declared Generators and the mappings between events used to change vector fields in a hybrid system.""" # 1. build constituent generators # 2. combine all generators' FScompatibleNames symbol maps FScompatibleNames = {} FScompatibleNamesInv = {} allGenNames = [] genObjs = {} for gname, geninfodict in self._generators.iteritems(): genSpec = geninfodict['modelspec'] allGenNames.append(genSpec.name) assert gname == genSpec.name, "Generator name mismatch in geninfodict" genTarg = geninfodict['target'] if 'algparams' in geninfodict: genAlgPars = geninfodict['algparams'] else: genAlgPars = {} if self.inputs is not None: genInputs = self.inputs else: genInputs = {} if 'unravelinfo' in geninfodict: genUnravelInfo = geninfodict['unravelinfo'] else: genUnravelInfo = True if 'options' in geninfodict: genOpts = geninfodict['options'] else: genOpts = {} try: genEvents = self._events[gname] except KeyError: genEvents = [] # extract par values and ic values relevant to this generator genPars = {} for p, val in self.parvalues.iteritems(): # don't bother to check that p is a valid param name # for this generator -- that will be checked by # GeneratorConstructor if p in genSpec._registry: genPars[p] = val genICs = {} for v, val in self.icvalues.iteritems(): # don't bother to check that v is a valid variable name # for this generator -- that will be checked by # GeneratorConstructor if v in genSpec._registry: genICs[v] = val genCon = GeneratorConstructor( genSpec, checklevel=self.checklevel, userevents=genEvents, targetGen=genTarg, algparams=genAlgPars, indepvar=self.indepvar, parvalues=genPars, inputs=genInputs, icvalues=genICs, options=genOpts, unravelInfo=genUnravelInfo, reuseTerms=self.reuseTerms, abseps=self.abseps, eventtol=self.eventtol, activateAllBounds=self.activateAllBounds, activatedBounds=self.activatedBounds) genObjs[gname] = genCon.getGenerator() # assume that there won't be any name clashes (there shouldn't be) FScompatibleNames.update(genCon.FScompatibleNames.lookupDict) FScompatibleNamesInv.update(genCon.FScompatibleNamesInv.lookupDict) # 3. build event mappings genInfoEntries = {} for hostGen, genObj in genObjs.iteritems(): allGenTermEvents = genObj.eventstruct.getTermEvents() allGenTermEvNames = [e[0] for e in allGenTermEvents] if hostGen in self.eventmaps: genMaps = self.eventmaps[hostGen] genMapNames = [] for gmtuple in genMaps: genMapNames.append(gmtuple[0]) for evname in remain(allGenTermEvNames, genMapNames): genMaps.append((evname, 'terminate')) genInfoEntries[hostGen] = makeGenInfoEntry( genObj, allGenNames, genMaps) else: # default for a generator without an event mapping is to # terminate when its time is up. genMaps = [('time', 'terminate')] for evname in allGenTermEvNames: genMaps.append((evname, 'terminate')) if not isfinite(genObj.indepvariable.depdomain.get(1)): print "Warning: Generator %s has no termination event" % genObj.name print "because it has an non-finite end computation time..." genInfoEntries[hostGen] = makeGenInfoEntry( genObj, allGenNames, genMaps) genInfoDict = makeGenInfo(genInfoEntries.values()) # 4. build model mod_args = { 'name': self.name, 'genInfo': genInfoDict, 'mspecdict': copy.copy(self._generators), 'FScompatibleNames': symbolMapClass(FScompatibleNames), 'FScompatibleNamesInv': symbolMapClass(FScompatibleNamesInv) } model = Model.Model(mod_args) model.forceIntVars(self.forcedIntVars) del genObjs del genInfoEntries del genInfoDict return model
def getGenerator(self): """Build and return a Generator instance from an abstract specification.""" ### Instantiate (flatten) target model structured specification ## Flatten ModelSpec self.mspec using indepvarname global and inputs # and using connectivity bindings (latter not yet implemented) globalRefs = [self.indepvarname] + self.inputs.keys() try: flatspec = self.mspec.flattenSpec(self.unravelInfo, globalRefs, ignoreInputs=True) except: print "Problem flattening Model Spec '%s'" % self.mspec.name print "Global refs: ", globalRefs raise FScompatibleNames = flatspec['FScompatibleNames'] FScompatibleNamesInv = flatspec['FScompatibleNamesInv'] ## Check target Generator info if self.targetGen in self.mspec.compatibleGens \ and self.targetGen in theGenSpecHelper: gsh = theGenSpecHelper(self.targetGen) if gsh.lang not in self.mspec.targetLangs: raise ValueError( "Incompatible target language between supplied" " ModelSpec and target Generator") else: print "ModelSpec's compatible Generators:", \ ", ".join(self.mspec.compatibleGens) print "ModelConstructor target Generator:", self.targetGen raise ValueError("Target Generator mismatch during generator " "construction") self.targetLang = gsh.lang ## Make Generator initialization argument dictionary a = args() if self.abseps is not None: a.abseps = self.abseps a.pars = {} parnames = flatspec['pars'].keys() for p, valstr in flatspec['pars'].iteritems(): if valstr == '': if FScompatibleNamesInv(p) not in self.parvalues: raise ValueError("Parameter %s is missing a value" % FScompatibleNamesInv(p)) else: try: a.pars[p] = float(valstr) except ValueError: raise ValueError("Invalid parameter value set in ModelSpec" " for '%s'" % p) # override any par vals set in ModelSpec with those explicitly set # here for p, val in self.parvalues.iteritems(): try: pr = FScompatibleNames(p) except KeyError: raise NameError("Parameter '%s' missing from ModelSpec" % p) if pr not in flatspec['pars']: raise NameError("Parameter '%s' missing from ModelSpec" % p) a.pars[pr] = val if self.icvalues != {}: a.ics = {} for v, val in self.icvalues.iteritems(): try: vr = FScompatibleNames(v) except KeyError: raise NameError("Variable '%s' missing from ModelSpec" % v) if vr not in flatspec['vars']: raise NameError("Variable '%s' missing from ModelSpec" % v) a.ics[vr] = val a.tdomain = self.indepvardomain # a.ttype = 'float' or 'int' ? a.inputs = self.inputs a.name = self.mspec.name xdomain = {} pdomain = {} for k, d in flatspec['domains'].iteritems(): # e.g. d == (float, Continuous, [-Inf, Inf]) assert d[1] == gsh.domain, "Domain mismatch with target Generator" if k in flatspec['vars']: assert len(d[2]) == 2, "Domain spec must be a valid interval" xdomain[k] = d[2] elif k in flatspec['pars']: assert len(d[2]) == 2, "Domain spec must be a valid interval" pdomain[k] = d[2] a.xdomain = xdomain a.pdomain = pdomain exp_vars = [v for (v,t) in flatspec['spectypes'].items() \ if t == 'ExpFuncSpec'] rhs_vars = [v for (v,t) in flatspec['spectypes'].items() \ if t == 'RHSfuncSpec'] imp_vars = [v for (v,t) in flatspec['spectypes'].items() \ if t == 'ImpFuncSpec'] if gsh.specType == 'RHSfuncSpec': assert imp_vars == [], "Cannot use implicitly defined variables" assert self.forcedAuxVars == [], "Cannot force auxiliary variables" varnames = rhs_vars auxvarnames = exp_vars elif gsh.specType == 'ExpFuncSpec': assert imp_vars == [], "Cannot use implicitly defined variables" assert rhs_vars == [], "Cannot use RHS-type variables" varnames = exp_vars invalid_auxvars = remain(self.forcedAuxVars, varnames) if invalid_auxvars == []: # then all forced aux varnames were legitimate # so remove them from varnames and put them in auxvarnames varnames = remain(varnames, self.forcedAuxVars) auxvarnames = self.forcedAuxVars else: print "Invalid auxiliary variable names:" print invalid_auxvars raise ValueError( "Forced auxiliary variable names were invalid") elif gsh.specType == 'ImpFuncSpec': assert rhs_vars == [], "Cannot use RHS-type variables" varnames = imp_vars auxvarnames = exp_vars # search for explicit variable interdependencies and resolve by # creating 'reuseterms' declarations, substituting in the cross-ref'd # definitions # e.g. state variables v and w, and explicit aux vars are given by: # x = 1+v # y = f(x) + w # Here, y illegally depends on x, so define a 'reused' temporary # definition, and re-write in terms of that: # temp = 1+v # x = temp # y = f(temp) + w # e.g. state variables v and w, aux var x: # v' = 1-v -f(x) # Here, v illegally uses an auxiliary variable on the RHS, so make # a 'reused' substitution as before # # first pass to find which substitutions are needed reuseTerms, subsExpr = processReused(varnames + auxvarnames, auxvarnames, flatspec, self.mspec._registry, FScompatibleNames, FScompatibleNamesInv) clash_reused = intersect(reuseTerms.keys(), self.reuseTerms.keys()) if clash_reused != []: print "Clashing terms:", clash_reused raise ValueError("User-supplied reused terms clash with auto-" "generated terms") # second pass, this time to actually make the substitutions for v in subsExpr: flatspec['vars'][v] = subsExpr[v] reuseTerms.update(self.reuseTerms) a.reuseterms = reuseTerms a.varspecs = dict(zip(varnames+auxvarnames, [flatspec['vars'][v] \ for v in varnames+auxvarnames])) a.auxvars = auxvarnames try: a.fnspecs = flatspec['auxfns'] except KeyError: # no aux fns defined! pass a.checklevel = self.checklevel a.algparams = self.algparams if self.vfcodeinsert_start != "": a.vfcodeinsert_start = self.vfcodeinsert_start if self.vfcodeinsert_end != "": a.vfcodeinsert_end = self.vfcodeinsert_end ## Events events = [] # make events from bound constraints (activated accordingly) # (parameter bounds only useful for continuation with PyCont) domnames = varnames + parnames for xname in domnames: hier_name_lo = FScompatibleNamesInv(xname) + "_domlo" FScompatibleNames[hier_name_lo] = xname + "_domlo" FScompatibleNamesInv[xname + "_domlo"] = hier_name_lo hier_name_hi = FScompatibleNamesInv(xname) + "_domi" FScompatibleNames[hier_name_hi] = xname + "_domhi" FScompatibleNamesInv[xname + "_domhi"] = hier_name_hi if self.activateAllBounds: a.activatedbounds = {}.fromkeys(domnames, (True, True)) else: a.activatedbounds = self.activatedBounds a.enforcebounds = True # add events from user events for e in self.userevents: if e not in events: events.append(e) else: raise ValueError, "Repeated event definition!" # events.extend(self.userevents) a.events = events # Add any additional special options (e.g. 'nobuild' directive) for k, v in self.optDict.iteritems(): if hasattr(a, k): raise KeyError("'%s' already exists as a Generator argument" % k) a.k = v # keep a copy of the arguments in self for users to see what was done self.conargs = a self.FScompatibleNames = FScompatibleNames self.FScompatibleNamesInv = FScompatibleNamesInv ## Make Generator try: return eval('Generator.' + self.targetGen + "(a)") except: print "Problem initializing target Generator '%s'" % self.targetGen raise
def makeGenInfoEntry(generator, allgen_names, swmap_list=[]): """Create an entry for the genInfo attribute of a Model.""" assert isinstance(allgen_names, list), "'allgen_names' argument must be a list" special_reasons = ["time"] + generator.variables.keys() assert generator.name not in special_reasons + [ "terminate" ], "Cannot use variable names or internal names 'time' and 'terminate' as generator names" try: allEndReasonNames = map(lambda (n, o): n, generator.eventstruct.getTermEvents()) + special_reasons except AttributeError: # no events associated with the generator allEndReasonNames = special_reasons assert generator.name in allgen_names, "Generator`s name not in list of all " "available Generator names!" assert alltrue( [name not in allEndReasonNames for name in allgen_names] ), "Generator names overlapped with event or variable names" alltarg_names = allgen_names + ["terminate"] # if no event map function specified, assume the identity fn seenReasons = [] swmap_pairs = [] if swmap_list != []: for mapentry in swmap_list: # check the entries of swmap_list and turn into a # (reason, infopair) pair, adding a default event map function # to some entries reason = mapentry[0] mapping_info = mapentry[1] if len(mapentry) > 2: raise ValueError("mapping entry must be (reason, infopair) tuple") if isinstance(mapping_info, tuple): genTargetName = mapping_info[0] numargs = len(mapping_info) elif isinstance(mapping_info, str): genTargetName = mapentry[1] numargs = 1 else: raise TypeError("Invalid event mapping entry") if numargs == 2: epmap = mapping_info[1] assert isinstance(epmap, EvMapping), "Must supply EvMapping class" swmap_pairs.append((reason, mapping_info)) elif numargs == 1: # use default identity mapping fn for event # and make this entry into a three-tuple swmap_pairs.append((reason, (genTargetName, EvMapping()))) else: raise ValueError("Expected 2 or 3 arguments to Generator " "switch map entry") assert reason not in seenReasons, "reason cannot appear more than" " once in map domain" seenReasons.append(reason) assert reason in allEndReasonNames, "name '" + reason + "' in map " "domain is missing" assert genTargetName in alltarg_names, "name '" + genTargetName + "' in " "map range is missing" else: # There had better be only a single Generator in allgen_names, # otherwise we need a map assert len(allgen_names) == 1, ( "There must be an event mapping " "specified when there is more than one Generator in the Model" ) unseen_sr = remain(allEndReasonNames, seenReasons) if unseen_sr != []: # then there are 'end reasons' that do not have switch rules, # so give them defaults (terminate) for r in unseen_sr: swmap_pairs.append((r, ("terminate", EvMapping()))) if len(swmap_pairs) != len(allEndReasonNames): info(dict(swmap_pairs)) print "(%i in total),versus:" % len(swmap_pairs) print allEndReasonNames, "(%i in total)" % len(allEndReasonNames) raise ValueError("Incorrect number of map pairs given in argument") return {generator.name: (generator, dict(swmap_pairs))}
def getModel(self): """Build and return (hybrid) model made up of declared Generators and the mappings between events used to change vector fields in a hybrid system.""" # 1. build constituent generators # 2. combine all generators' FScompatibleNames symbol maps FScompatibleNames = {} FScompatibleNamesInv = {} allGenNames = [] genObjs = {} for gname, geninfodict in self._generators.iteritems(): genSpec = geninfodict["modelspec"] allGenNames.append(genSpec.name) assert gname == genSpec.name, "Generator name mismatch in geninfodict" genTarg = geninfodict["target"] if "algparams" in geninfodict: genAlgPars = geninfodict["algparams"] else: genAlgPars = {} if self.inputs is not None: genInputs = self.inputs else: genInputs = {} if "unravelinfo" in geninfodict: genUnravelInfo = geninfodict["unravelinfo"] else: genUnravelInfo = True if "options" in geninfodict: genOpts = geninfodict["options"] else: genOpts = {} try: genEvents = self._events[gname] except KeyError: genEvents = [] # extract par values and ic values relevant to this generator genPars = {} for p, val in self.parvalues.iteritems(): # don't bother to check that p is a valid param name # for this generator -- that will be checked by # GeneratorConstructor if p in genSpec._registry: genPars[p] = val genICs = {} for v, val in self.icvalues.iteritems(): # don't bother to check that v is a valid variable name # for this generator -- that will be checked by # GeneratorConstructor if v in genSpec._registry: genICs[v] = val genCon = GeneratorConstructor( genSpec, checklevel=self.checklevel, userevents=genEvents, targetGen=genTarg, algparams=genAlgPars, indepvar=self.indepvar, parvalues=genPars, inputs=genInputs, icvalues=genICs, options=genOpts, unravelInfo=genUnravelInfo, reuseTerms=self.reuseTerms, abseps=self.abseps, eventtol=self.eventtol, activateAllBounds=self.activateAllBounds, activatedBounds=self.activatedBounds, ) genObjs[gname] = genCon.getGenerator() # assume that there won't be any name clashes (there shouldn't be) FScompatibleNames.update(genCon.FScompatibleNames.lookupDict) FScompatibleNamesInv.update(genCon.FScompatibleNamesInv.lookupDict) # 3. build event mappings genInfoEntries = {} for hostGen, genObj in genObjs.iteritems(): allGenTermEvents = genObj.eventstruct.getTermEvents() allGenTermEvNames = [e[0] for e in allGenTermEvents] if hostGen in self.eventmaps: genMaps = self.eventmaps[hostGen] genMapNames = [] for gmtuple in genMaps: genMapNames.append(gmtuple[0]) for evname in remain(allGenTermEvNames, genMapNames): genMaps.append((evname, "terminate")) genInfoEntries[hostGen] = makeGenInfoEntry(genObj, allGenNames, genMaps) else: # default for a generator without an event mapping is to # terminate when its time is up. genMaps = [("time", "terminate")] for evname in allGenTermEvNames: genMaps.append((evname, "terminate")) if not isfinite(genObj.indepvariable.depdomain.get(1)): print "Warning: Generator %s has no termination event" % genObj.name print "because it has an non-finite end computation time..." genInfoEntries[hostGen] = makeGenInfoEntry(genObj, allGenNames, genMaps) genInfoDict = makeGenInfo(genInfoEntries.values()) # 4. build model mod_args = { "name": self.name, "genInfo": genInfoDict, "mspecdict": copy.copy(self._generators), "FScompatibleNames": symbolMapClass(FScompatibleNames), "FScompatibleNamesInv": symbolMapClass(FScompatibleNamesInv), } model = Model.Model(mod_args) model.forceIntVars(self.forcedIntVars) del genObjs del genInfoEntries del genInfoDict return model
def getGenerator(self): """Build and return a Generator instance from an abstract specification.""" ### Instantiate (flatten) target model structured specification ## Flatten ModelSpec self.mspec using indepvarname global and inputs # and using connectivity bindings (latter not yet implemented) globalRefs = [self.indepvarname] + self.inputs.keys() try: flatspec = self.mspec.flattenSpec(self.unravelInfo, globalRefs, ignoreInputs=True) except: print "Problem flattening Model Spec '%s'" % self.mspec.name print "Global refs: ", globalRefs raise FScompatibleNames = flatspec["FScompatibleNames"] FScompatibleNamesInv = flatspec["FScompatibleNamesInv"] ## Check target Generator info if self.targetGen in self.mspec.compatibleGens and self.targetGen in theGenSpecHelper: gsh = theGenSpecHelper(self.targetGen) if gsh.lang not in self.mspec.targetLangs: raise ValueError("Incompatible target language between supplied" " ModelSpec and target Generator") else: print "ModelSpec's compatible Generators:", ", ".join(self.mspec.compatibleGens) print "ModelConstructor target Generator:", self.targetGen raise ValueError("Target Generator mismatch during generator " "construction") self.targetLang = gsh.lang ## Make Generator initialization argument dictionary a = args() if self.abseps is not None: a.abseps = self.abseps a.pars = {} parnames = flatspec["pars"].keys() for p, valstr in flatspec["pars"].iteritems(): if valstr == "": if FScompatibleNamesInv(p) not in self.parvalues: raise ValueError("Parameter %s is missing a value" % FScompatibleNamesInv(p)) else: try: a.pars[p] = float(valstr) except ValueError: raise ValueError("Invalid parameter value set in ModelSpec" " for '%s'" % p) # override any par vals set in ModelSpec with those explicitly set # here for p, val in self.parvalues.iteritems(): try: pr = FScompatibleNames(p) except KeyError: raise NameError("Parameter '%s' missing from ModelSpec" % p) if pr not in flatspec["pars"]: raise NameError("Parameter '%s' missing from ModelSpec" % p) a.pars[pr] = val if self.icvalues != {}: a.ics = {} for v, val in self.icvalues.iteritems(): try: vr = FScompatibleNames(v) except KeyError: raise NameError("Variable '%s' missing from ModelSpec" % v) if vr not in flatspec["vars"]: raise NameError("Variable '%s' missing from ModelSpec" % v) a.ics[vr] = val a.tdomain = self.indepvardomain # a.ttype = 'float' or 'int' ? a.inputs = self.inputs a.name = self.mspec.name xdomain = {} pdomain = {} for k, d in flatspec["domains"].iteritems(): # e.g. d == (float, Continuous, [-Inf, Inf]) assert d[1] == gsh.domain, "Domain mismatch with target Generator" if k in flatspec["vars"]: assert len(d[2]) == 2, "Domain spec must be a valid interval" xdomain[k] = d[2] elif k in flatspec["pars"]: assert len(d[2]) == 2, "Domain spec must be a valid interval" pdomain[k] = d[2] a.xdomain = xdomain a.pdomain = pdomain exp_vars = [v for (v, t) in flatspec["spectypes"].items() if t == "ExpFuncSpec"] rhs_vars = [v for (v, t) in flatspec["spectypes"].items() if t == "RHSfuncSpec"] imp_vars = [v for (v, t) in flatspec["spectypes"].items() if t == "ImpFuncSpec"] if gsh.specType == "RHSfuncSpec": assert imp_vars == [], "Cannot use implicitly defined variables" assert self.forcedAuxVars == [], "Cannot force auxiliary variables" varnames = rhs_vars auxvarnames = exp_vars elif gsh.specType == "ExpFuncSpec": assert imp_vars == [], "Cannot use implicitly defined variables" assert rhs_vars == [], "Cannot use RHS-type variables" varnames = exp_vars invalid_auxvars = remain(self.forcedAuxVars, varnames) if invalid_auxvars == []: # then all forced aux varnames were legitimate # so remove them from varnames and put them in auxvarnames varnames = remain(varnames, self.forcedAuxVars) auxvarnames = self.forcedAuxVars else: print "Invalid auxiliary variable names:" print invalid_auxvars raise ValueError("Forced auxiliary variable names were invalid") elif gsh.specType == "ImpFuncSpec": assert rhs_vars == [], "Cannot use RHS-type variables" varnames = imp_vars auxvarnames = exp_vars # search for explicit variable interdependencies and resolve by # creating 'reuseterms' declarations, substituting in the cross-ref'd # definitions # e.g. state variables v and w, and explicit aux vars are given by: # x = 1+v # y = f(x) + w # Here, y illegally depends on x, so define a 'reused' temporary # definition, and re-write in terms of that: # temp = 1+v # x = temp # y = f(temp) + w # e.g. state variables v and w, aux var x: # v' = 1-v -f(x) # Here, v illegally uses an auxiliary variable on the RHS, so make # a 'reused' substitution as before # # first pass to find which substitutions are needed reuseTerms, subsExpr = processReused( varnames + auxvarnames, auxvarnames, flatspec, self.mspec._registry, FScompatibleNames, FScompatibleNamesInv ) clash_reused = intersect(reuseTerms.keys(), self.reuseTerms.keys()) if clash_reused != []: print "Clashing terms:", clash_reused raise ValueError("User-supplied reused terms clash with auto-" "generated terms") # second pass, this time to actually make the substitutions for v in subsExpr: flatspec["vars"][v] = subsExpr[v] reuseTerms.update(self.reuseTerms) a.reuseterms = reuseTerms a.varspecs = dict(zip(varnames + auxvarnames, [flatspec["vars"][v] for v in varnames + auxvarnames])) a.auxvars = auxvarnames try: a.fnspecs = flatspec["auxfns"] except KeyError: # no aux fns defined! pass a.checklevel = self.checklevel a.algparams = self.algparams if self.vfcodeinsert_start != "": a.vfcodeinsert_start = self.vfcodeinsert_start if self.vfcodeinsert_end != "": a.vfcodeinsert_end = self.vfcodeinsert_end ## Events events = [] # make events from bound constraints (activated accordingly) # (parameter bounds only useful for continuation with PyCont) domnames = varnames + parnames for xname in domnames: hier_name_lo = FScompatibleNamesInv(xname) + "_domlo" FScompatibleNames[hier_name_lo] = xname + "_domlo" FScompatibleNamesInv[xname + "_domlo"] = hier_name_lo hier_name_hi = FScompatibleNamesInv(xname) + "_domi" FScompatibleNames[hier_name_hi] = xname + "_domhi" FScompatibleNamesInv[xname + "_domhi"] = hier_name_hi if self.activateAllBounds: a.activatedbounds = {}.fromkeys(domnames, (True, True)) else: a.activatedbounds = self.activatedBounds a.enforcebounds = True # add events from user events for e in self.userevents: if e not in events: events.append(e) else: raise ValueError, "Repeated event definition!" # events.extend(self.userevents) a.events = events # Add any additional special options (e.g. 'nobuild' directive) for k, v in self.optDict.iteritems(): if hasattr(a, k): raise KeyError("'%s' already exists as a Generator argument" % k) a.k = v # keep a copy of the arguments in self for users to see what was done self.conargs = a self.FScompatibleNames = FScompatibleNames self.FScompatibleNamesInv = FScompatibleNamesInv ## Make Generator try: return eval("Generator." + self.targetGen + "(a)") except: print "Problem initializing target Generator '%s'" % self.targetGen raise