Example #1
0
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))}
Example #2
0
 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
Example #3
0
    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