def __init__(self, kw): discGen.__init__(self, kw) self.diagnostics._errmessages[E_COMPUTFAIL] = 'Computation of trajectory failed' # user auxiliary function interface self.auxfns = auxfn_container(self) dispatch_list = ['varspecs', 'tdomain', 'ttype', 'tdata', 'tstep', 'inputs', 'ics', 'allvars', 'xtype', 'pars', 'xdomain', 'reuseterms', 'algparams', 'pdomain', 'system', 'fnspecs', 'vfcodeinserts', 'ignorespecial'] # process keys and build func spec self.funcspec = RHSfuncSpec(self._kw_process_dispatch(dispatch_list, kw)) self._kw_process_events(kw) self.checkArgs(kw) tindepdomain = Interval('t_domain', self.indepvartype, self.tdomain, self._abseps) tdepdomain = Interval('t', self.indepvartype, self.tdata, self._abseps) self.indepvariable = Variable(listid, tindepdomain, tdepdomain, 't') self._register(self.indepvariable) for xname in self.funcspec.vars + self.funcspec.auxvars: # Add a temporary dependent variable domain, for validation testing # during integration self.variables[xname] = Variable(indepdomain=tdepdomain, depdomain=Interval(xname, self.xtype[xname], self.xdomain[xname], self._abseps)) self._register(self.variables) self._generate_ixmaps() # Introduce any python-specified code to the local namespace self.addMethods() # all registration completed self.validateSpec()
def compute(self, trajname, ics=None): assert self.funcspec.targetlang == 'python', \ ('Wrong target language for functional specification. ' 'Python needed for this class') assert isinstance(self.funcspec, RHSfuncSpec), ('Map system ' 'requires RHSfuncSpec type to proceed') self.diagnostics.clearWarnings() self.diagnostics.clearErrors() if ics is not None: self.set(ics=ics) xnames = self._var_ixmap # ensures correct order # wrap up each dictionary initial value as a singleton list alltData = [self.indepvariable.depdomain[0]] allxDataDict = dict(zip(xnames, map(listid, sortedDictValues(self.initialconditions, self.funcspec.vars)))) rhsfn = getattr(self,self.funcspec.spec[1]) # Check i.c.'s are well defined (finite) self.checkInitialConditions() self.setEventICs(self.initialconditions, self.globalt0) ic = sortedDictValues(self.initialconditions, self.funcspec.vars) plist = sortedDictValues(self.pars) extralist = copy(plist) ilist = [] if self.inputs: # inputVarList is a list of Variables listend = self.numpars + len(self.inputs) inputVarList = sortedDictValues(self.inputs) try: for f in inputVarList: f.diagnostics.clearWarnings() ilist.append(f(alltData[0], self.checklevel)) except AssertionError: print('External input call has t out of range: t = %f' % \ self.indepvariable.depdomain[0]) print('Maybe checklevel is 3 and initial time is not', \ 'completely inside valid time interval') raise except ValueError: print('External input call has value out of range: t = %f' % \ self.indepvariable.depdomain[0]) for f in inputVarList: if f.diagnostics.hasWarnings(): print('External input %s out of range:' % f.name) print(' t = %r, %s, %r' % (repr(f.diagnostics.warnings[-1][0]), f.name, repr(f.diagnostics.warnings[-1][1]))) raise else: listend = self.numpars inputVarList = [] extralist.extend(ilist) precevents = self.eventstruct.query(['precise']) if precevents != []: raise PyDSTool_ValueError('precise events are not valid for map systems') eventslist = self.eventstruct.query(['highlevel', 'active', 'notvarlinked']) termevents = self.eventstruct.query(['term'], eventslist) # initialize event info dictionaries Evtimes = {} Evpoints = {} for (evname, ev) in eventslist: Evtimes[evname] = [] Evpoints[evname] = [] if eventslist != []: if self._for_hybrid_DS: # self._for_hybrid_DS is set internally by HybridModel class # to ensure not to reset events, because they may be about to # flag on first step if previous hybrid state was the same # generator and, for example, two variables are synchronizing # so that their events get very close together. # Just reset the starttimes of these events for evname, ev in eventslist: ev.starttime = self.indepvariable.depdomain[0] else: self.eventstruct.resetHighLevelEvents(self.indepvariable.depdomain[0], eventslist) self.eventstruct.validateEvents(self.funcspec.vars + \ self.funcspec.auxvars + \ ['t'], eventslist) # per-iteration storage of variable data (initial values are irrelevant) xDataDict = {} # storage of all auxiliary variable data allaDataDict = {} anames = self.funcspec.auxvars avals = getattr(self,self.funcspec.auxspec[1])(*[self.indepvariable.depdomain[0], sortedDictValues(self.initialconditions, self.funcspec.vars), extralist]) for aix in range(len(anames)): aname = anames[aix] allaDataDict[aname] = [avals[aix]] # temp storage of first time at which terminal events found # (this is used for keeping the correct end point of new mesh) first_found_t = None tmesh = self.indepvariable.depdomain.sample(self.tstep, strict=False, avoidendpoints=self.checklevel>2) # Main loop breakwhile = False success = False x = ic notdone = True # did i=0 for initial condition already i = 1 while notdone: t = tmesh[i] ## COMPUTE NEXT STATE y from x try: y = rhsfn(t, x, extralist) except: print("Error in calling right hand side function:") self.showSpec() raise for xi in range(self.dimension): xDataDict[xnames[xi]] = y[xi] if not self.contains(self.variables[xnames[xi]].depdomain, y[xi], self.checklevel): self.diagnostics.warnings.append((W_TERMSTATEBD, (t, xnames[xi], y[xi], self.variables[xnames[xi]].depdomain))) breakwhile = True break # for loop if breakwhile: notdone = False continue avals = getattr(self,self.funcspec.auxspec[1])(*[t, sortedDictValues(xDataDict), extralist]) if eventslist != []: dataDict = copy(xDataDict) dataDict['t'] = t evsflagged = self.eventstruct.pollHighLevelEvents(None, dataDict, self.pars, eventslist) termevsflagged = [e for e in termevents if e in evsflagged] nontermevsflagged = [e for e in evsflagged if e not in termevsflagged] # register any non-terminating events in the warnings list if len(nontermevsflagged) > 0: evnames = [ev[0] for ev in nontermevsflagged] self.diagnostics.warnings.append((W_NONTERMEVENT, (t, evnames))) for evname in evnames: Evtimes[evname].append(t) xv = y av = array(avals) Evpoints[evname].append(concatenate((xv, av))) if termevsflagged != []: # active terminal event flagged at this time point # register the event in the warnings evnames = [ev[0] for ev in termevsflagged] self.diagnostics.warnings.append((W_TERMEVENT, \ (t, evnames))) for evname in evnames: Evtimes[evname].append(t) xv = y av = array(avals) Evpoints[evname].append(concatenate((xv, av))) notdone = False # ?? if continue here then won't add the event point to the # trajectory values being constructed! #continue alltData.append(t) for xi in range(self.dimension): allxDataDict[xnames[xi]].append(y[xi]) for aix in range(len(anames)): aname = anames[aix] allaDataDict[aname].append(avals[aix]) try: extralist[self.numpars:listend] = [f(*[t, self.checklevel]) \ for f in inputVarList] except ValueError: print('External input call caused value out of range error:', \ 't = %f' % t) for f in inputVarList: if f.hasWarnings(): print('External input variable %s out of range:' % f.name) print(' t = %r, %s, %r' % (repr(f.diagnostics.warnings[-1][0]), f.name, repr(f.diagnostics.warnings[-1][1]))) raise except AssertionError: print('External input call caused t out of range error: t = %f' % t) raise if i >= len(tmesh) - 1: notdone = False else: i += 1 x = y # update success flag success = not notdone # Check that any terminal events found terminated the code correctly if first_found_t is not None: assert self.diagnostics.warnings[-1][0] == W_TERMEVENT, ("Event finding code " "for terminal event failed") # Package up computed trajectory in Variable variables # Add external inputs warnings to self.dignostics.warnings, if any for f in inputVarList: for winfo in f.diagnostics.warnings: self.diagnostics.warnings.append((W_NONTERMSTATEBD, (winfo[0], f.name, winfo[1], f.depdomain))) # check for non-unique terminal event termcount = 0 for (w,i) in self.diagnostics.warnings: if w == W_TERMEVENT or w == W_TERMSTATEBD: termcount += 1 if termcount > 1: self.diagnostics.errors.append((E_NONUNIQUETERM, (alltData[-1], i[1]))) ## print 'Time interval adjusted according to %s: %s' % \ ## (self._warnmessages[w], str(i[0])+", "+ str(i[1])) # Create variables (self.variables contains no actual data) variables = copyVarDict(self.variables) # build event pointset information (reset previous trajectory's) self.trajevents = {} for (evname, ev) in eventslist: evpt = Evpoints[evname] if evpt == []: self.trajevents[evname] = None else: evpt = transpose(array(evpt)) self.trajevents[evname] = Pointset({'coordnames': xnames+anames, 'indepvarname': 't', 'coordarray': evpt, 'indepvararray': Evtimes[evname], 'indepvartype': self.variables[xnames[0]].indepvartype}) for x in xnames: if len(alltData) > 1: variables[x] = Variable(Pointset({'coordnames': [x], 'coordarray': allxDataDict[x], 'coordtype': self.variables[x].coordtype, 'indepvarname': 't', 'indepvararray': alltData, 'indepvartype': self.variables[x].indepvartype}), 't', x, x) else: raise PyDSTool_ValueError("Fewer than 2 data points computed") for a in anames: if len(alltData) > 1: variables[a] = Variable(Pointset({'coordnames': [a], 'coordarray': allaDataDict[a], 'coordtype': self.variables[a].coordtype, 'indepvarname': 't', 'indepvararray': alltData, 'indepvartype': self.variables[a].indepvartype}), 't', a, a) else: raise PyDSTool_ValueError("Fewer than 2 data points computed") if success: #self.validateSpec() self.defined = True return Trajectory(trajname, list(variables.values()), abseps=self._abseps, globalt0=self.globalt0, checklevel=self.checklevel, FScompatibleNames=self._FScompatibleNames, FScompatibleNamesInv=self._FScompatibleNamesInv, events=self.trajevents, modelNames=self.name, modelEventStructs=self.eventstruct) else: print('Trajectory computation failed') self.diagnostics.errors.append((E_COMPUTFAIL, (t, self._errorcodes[errcode]))) self.defined = False
def set(self, **kw): """Set map system parameters""" if remain(kw.keys(), self._validKeys) != []: raise KeyError("Invalid keys in argument") if 'globalt0' in kw: # pass up to generic treatment for this discGen.set(self, globalt0=kw['globalt0']) if 'checklevel' in kw: # pass up to generic treatment for this discGen.set(self, checklevel=kw['checklevel']) if 'abseps' in kw: # pass up to generic treatment for this discGen.set(self, abseps=kw['abseps']) # optional keys for this call are ['pars', 'tdomain', 'ics', # 'algparams', 'tdata', 'xdomain', 'inputs', 'pdomain'] if 'ics' in kw: for k_temp, v in kw['ics'].items(): # str() ensures that Symbolic objects can be passed k = str(self._FScompatibleNames(k_temp)) if k in self.funcspec.vars+self.funcspec.auxvars: self._xdatadict[k] = ensurefloat(v) else: raise ValueError('Illegal variable name, %s'%k) self.initialconditions.update(self._xdatadict) tchange = False if 'tdata' in kw: self.tdata = kw['tdata'] tchange = True if 'tdomain' in kw: self.tdomain = kw['tdomain'] self.indepvariable.indepdomain.set(self.tdomain) tchange = True if tchange: if self.tdomain[0] > self.tdata[0]: if self.indepvariable.indepdomain.contains(self.tdata[0]) == uncertain: self.diagnostics.warnings.append((W_UNCERTVAL, (self.tdata[0],self.tdomain))) else: print('tdata cannot be specified below smallest '\ 'value in tdomain\n (possibly due to uncertain bounding).'\ ' It has been automatically adjusted from %f to %f (difference of %f)\n' % ( self.tdata[0], self.tdomain[0], self.tdomain[0]-self.tdata[0])) self.tdata[0] = self.tdomain[0] if self.tdomain[1] < self.tdata[1]: if self.indepvariable.indepdomain.contains(self.tdata[1]) == uncertain: self.diagnostics.warnings.append((W_UNCERTVAL, (self.tdata[1],self.tdomain))) else: print('tdata cannot be specified above largest '\ 'value in tdomain\n (possibly due to uncertain bounding).'\ ' It has been automatically adjusted from %f to %f (difference of %f)\n' % ( self.tdomain[1], self.tdomain[1], self.tdata[1]-self.tdomain[1])) self.tdata[1] = self.tdomain[1] self.indepvariable.depdomain.set(self.tdata) if 'xdomain' in kw: for k_temp, v in kw['xdomain'].items(): k = str(self._FScompatibleNames(k_temp)) if k in self.funcspec.vars+self.funcspec.auxvars: if isinstance(v, _seq_types): assert len(v) == 2, \ "Invalid size of domain specification for "+k if v[0] >= v[1]: raise PyDSTool_ValueError('xdomain values must be' 'in order of increasing ' 'size') else: self.xdomain[k] = copy(v) elif isinstance(v, _num_types): self.xdomain[k] = [v, v] else: raise PyDSTool_TypeError('Invalid type for xdomain spec' ' '+k) self.xdomain[k] = v else: raise ValueError('Illegal variable name') try: self.variables[k].depdomain.set(v) except TypeError: raise TypeError('xdomain must be a dictionary of variable' ' names -> valid interval 2-tuples or ' 'singletons') try: evs = self.eventstruct.events.values() except AttributeError: evs = [] for ev in evs: ev.xdomain[k] = v if 'pdomain' in kw: for k_temp, v in kw['pdomain'].items(): k = str(self._FScompatibleNames(k_temp)) if k in self.funcspec.pars: if isinstance(v, _seq_types): assert len(v) == 2, \ "Invalid size of domain specification for "+k if v[0] >= v[1]: raise PyDSTool_ValueError('pdomain values must be' 'in order of increasing ' 'size') else: self.pdomain[k] = copy(v) elif isinstance(v, _num_types): self.pdomain[k] = [v, v] else: raise PyDSTool_TypeError('Invalid type for pdomain spec' ' '+k) else: raise ValueError('Illegal parameter name') try: self.parameterDomains[k].set(v) except TypeError: raise TypeError('xdomain must be a dictionary of parameter' ' names -> valid interval 2-tuples or ' 'singletons') try: evs = self.eventstruct.events.values() except AttributeError: evs = [] for ev in evs: ev.pdomain[k] = self.pdomain[k] if 'pars' in kw: assert self.numpars > 0, ('No pars were declared for this ' 'model') for k_temp, v in kw['pars'].items(): k = str(self._FScompatibleNames(k_temp)) if k in self.pars: cval = self.parameterDomains[k].contains(v) if self.checklevel < 3: if cval is not notcontained: self.pars[k] = ensurefloat(v) if cval is uncertain and self.checklevel == 2: print('Warning: Parameter value at bound') else: raise PyDSTool_ValueError('Parameter value out of bounds') else: if cval is contained: self.pars[k] = ensurefloat(v) elif cval is uncertain: raise PyDSTool_UncertainValueError('Parameter value at bound') else: raise PyDSTool_ValueError('Parameter value out of bounds') else: raise PyDSTool_ValueError('Illegal parameter name') # pass on parameter changes to embedded system, if present if self._solver: try: shared_pars = intersect(kw['pars'].keys(), self._solver.pars) except AttributeError: # no pars for this kind of solver pass else: if shared_pars != []: self._solver.set(pars=filteredDict(kw['pars'], shared_pars)) if 'inputs' in kw: assert self.inputs, ('Cannot provide inputs after ' 'initialization without them') inputs = copy(kw['inputs']) _inputs = {} if isinstance(inputs, Trajectory): # extract the variables _inputs = self._FScompatibleNames(inputs.variables) elif isinstance(inputs, Variable): _inputs = {self._FScompatibleNames(inputs.name): inputs} elif isinstance(inputs, Pointset): # turn into Variables for n in inputs.coordnames: x_array = inputs[n] nFS = self._FScompatibleNames(n) _inputs[nFS] = \ Variable(interp1d(inputs.indepvararray, x_array), 't', Interval(nFS, float, extent(x_array), abseps=self._abseps), name=n) # keep original name here elif isinstance(inputs, dict): _inputs = self._FScompatibleNames(inputs) # ensure values are Variables for v in _inputs.values(): if not isinstance(v, Variable): raise TypeError("Invalid specification of inputs") else: raise TypeError("Invalid specification of inputs") if _inputs: for i in _inputs: assert i in self.inputs, 'Incorrect input name provided' self.inputs[i] = _inputs[i] # re-calc inputs ixmaps self._generate_ixmaps('inputs') self._extInputsChanged = True if 'inputs_t0' in kw: assert self.inputs, ('Cannot provide inputs after ' 'initialization without them') inputs_t0 = self._FScompatibleNames(kw['inputs_t0']) for iname, t0 in inputs_t0.items(): self.inputs[iname]._internal_t_offset = t0 self._extInputsChanged = True
def __init__(self, kw): ctsGen.__init__(self, kw) self._errmessages[E_COMPUTFAIL] = 'Integration failed' self.needKeys.extend(['varspecs']) self.optionalKeys.extend(['tdomain', 'xdomain', 'inputs', 'tdata', 'ics', 'events', 'compiler', 'enforcebounds', 'activatedbounds', 'checklevel', 'algparams', 'auxvars', 'vars', 'pars', 'fnspecs', 'pdomain', 'reuseterms', 'vfcodeinsert_start', 'vfcodeinsert_end']) fs_args = {} if 'varspecs' in kw: self.foundKeys += 1 varspecs = ensureStrArgDict(kw['varspecs']) else: raise PyDSTool_KeyError("Keyword 'varspecs' missing from " "argument") if 'tdomain' in kw: self._tdomain = kw['tdomain'] if self._tdomain[0] >= self._tdomain[1]: print "Time domain specified: [%s, %s]"%(self._tdomain[0], self._tdomain[1]) raise PyDSTool_ValueError('tdomain values must be in order of increasing size') self.foundKeys += 1 else: self._tdomain = [-Inf, Inf] if 'tdata' in kw: self._tdata = kw['tdata'] if self._tdata[0] >= self._tdata[1]: raise PyDSTool_ValueError('tdata values must be in order of increasing size') # _tdata is made into list to be consistent with # other uses of it in other Generators... if self._tdomain[0] > self._tdata[0]: print 'tdata cannot be specified below smallest '\ 'value in tdomain\n (possibly due to uncertain'\ 'bounding). It has been automatically adjusted\n'\ ' from\n ', self._tdata[0], 'to', self._tdomain[0],\ '(difference of', self._tdomain[0]-self._tdata[0], ')' if self._modeltag: print 'Try reducing step size in model.' self._tdata[0] = self._tdomain[0] if self._tdomain[1] < self._tdata[1]: print 'tdata cannot be specified above largest '\ 'value in tdomain\n (possibly due to uncertain '\ 'bounding). It has been automatically adjusted\n'\ ' from\n ', self._tdata[1], 'to', self._tdomain[1],\ '(difference of', self._tdata[1]-self._tdomain[1], ')' if self._modeltag: print 'Try reducing step size in model.' self._tdata[1] = self._tdomain[1] self.foundKeys += 1 else: self._tdata = self._tdomain # default needed if 'inputs' in kw: inputs = copy(kw['inputs']) self.inputs = {} if isinstance(inputs, Trajectory): # extract the variables self.inputs = inputs.variables elif isinstance(inputs, Variable): self.inputs = {inputs.name: inputs} elif isinstance(inputs, Pointset): # turn into Variables with linear interpoolation between # independent variable values for n in inputs.coordnames: x_array = inputs[n] self.inputs[n] = Variable(interp1d(inputs.indepvararray, x_array), 't', Interval(n, 'float', extent(x_array)), name=n) elif isinstance(inputs, dict): self.inputs = inputs # ensure values are Variables or Pointsets for k, v in self.inputs.iteritems(): if not isinstance(v, Variable): try: self.inputs[k]=Variable(v) except: raise TypeError, "Invalid specification of inputs" else: raise TypeError, "Invalid specification of inputs" for v in self.inputs.values(): if not iscontinuous(v): raise ValueError, \ ("External inputs for ODE system must be " "continuously defined") fs_args['inputs'] = self.inputs.keys() self._register(self.inputs) self.foundKeys += 1 self._extInputsChanged = True else: self.inputs = {} self._extInputsChanged = False if 'ics' in kw: self._xdatadict = {} for k, v in dict(kw['ics']).iteritems(): self._xdatadict[str(k)] = v self.initialconditions = self._xdatadict for name in remain(varspecs.keys(), self._xdatadict.keys()): self.initialconditions[name] = NaN self.foundKeys += 1 else: self._xdatadict = {} for name in varspecs: self.initialconditions[name] = NaN if 'auxvars' in kw: assert 'vars' not in kw, ("Cannot use both 'auxvars' and 'vars' " "keywords") if isinstance(kw['auxvars'], list): auxvars = [str(v) for v in kw['auxvars']] else: auxvars = [str(kw['auxvars'])] vars = remain(varspecs.keys(), auxvars) self.foundKeys += 1 elif 'vars' in kw: assert 'auxvars' not in kw, \ "Cannot use both 'auxvars' and 'vars' keywords" if isinstance(kw['vars'], list): vars = [str(v) for v in kw['vars']] else: vars = [str(kw['vars'])] auxvars = remain(varspecs.keys(), vars) self.foundKeys += 1 else: auxvars = [] vars = varspecs.keys() if auxvars != []: fs_args['auxvars'] = auxvars if 'xdomain' in kw: self._xdomain = {} for k, v in dict(kw['xdomain']).iteritems(): name = str(k) if type(v) in [list, Array, NArray]: assert len(v) == 2, \ "Invalid size of domain specification for "+name if v[0] >= v[1]: raise PyDSTool_ValueError('xdomain values must be in' 'order of increasing size') else: self._xdomain[name] = copy(v) elif type(v) in [float, int]: self._xdomain[name] = [v, v] else: raise PyDSTool_TypeError('Invalid type for xdomain spec' ' '+name) for name in remain(varspecs.keys(), self._xdomain.keys()): self._xdomain[name] = [-Inf, Inf] self.foundKeys += 1 else: self._xdomain = {} for name in varspecs: self._xdomain[name] = [-Inf, Inf] if 'reuseterms' in kw: fs_args['reuseterms'] = kw['reuseterms'] self.foundKeys += 1 fs_args.update({'vars': vars, 'varspecs': varspecs, 'name': self.name }) if 'algparams' in kw: self._algparams = copy(kw['algparams']) self.foundKeys += 1 else: self._algparams = {} if 'pars' in kw: self.pars = {} if type(kw['pars']) == list: # may be a list of symbolic definitions for p in kw['pars']: try: self.pars[p.name] = p.tonumeric() except (AttributeError, TypeError): raise TypeError, "Invalid parameter symbolic definition" else: for k, v in dict(kw['pars']).iteritems(): self.pars[str(k)] = v fs_args['pars'] = self.pars.keys() self._register(self.pars) self.foundKeys += 1 if 'pdomain' in kw: if self.pars: self._pdomain = {} for k, v in dict(kw['pdomain']).iteritems(): assert len(v) == 2, \ "Invalid size of domain specification for "+k self._pdomain[str(k)] = v for name in self._pdomain: if self._pdomain[name][0] >= self._pdomain[name][1]: raise PyDSTool_ValueError('pdomain values must be in order of increasing size') for name in remain(self.pars.keys(), self._pdomain.keys()): self._pdomain[name] = [-Inf, Inf] self.foundKeys += 1 else: raise ValueError('Cannot specify pdomain because no pars declared') else: if self.pars: self._pdomain = {} for pname in self.pars: self._pdomain[pname] = [-Inf, Inf] if self.pars: self.parameterDomains = {} for pname in self._pdomain: self.parameterDomains[pname] = Interval(pname, 'float', self._pdomain[pname], self._abseps) try: cval = self.parameterDomains[pname].contains(self.pars[pname]) except KeyError: raise ValueError("Parameter %s is missing a value"%pname) if self.checklevel < 3: if cval is not notcontained: if cval is uncertain and self.checklevel == 2: print 'Warning: Parameter value at bound' else: raise PyDSTool_ValueError, 'Parameter value out of bounds' else: if cval is uncertain: raise PyDSTool_UncertainValueError, 'Parameter value at bound' elif cval is notcontained: raise PyDSTool_ValueError, 'Parameter value out of bounds' if 'fnspecs' in kw: fs_args['fnspecs'] = ensureStrArgDict(kw['fnspecs']) self.foundKeys += 1 fs_args['targetlang'] = theGenSpecHelper(self).lang if 'compiler' in kw: if fs_args['targetlang'] == 'python': print "Warning: redundant option 'compiler' for python target" self._compiler = kw['compiler'] self.foundKeys += 1 else: osname = os.name # os-specific defaults for C compiler if osname == 'nt': self._compiler = 'mingw32' elif osname == 'mac': self._compiler = 'mwerks' elif osname == 'posix' or osname == 'unix': self._compiler = 'unix' elif osname == 'os2emx': self._compiler = 'emx' else: self._compiler = '' if 'vfcodeinsert_start' in kw: fs_args['codeinsert_start'] = kw['vfcodeinsert_start'] self.foundKeys += 1 if 'vfcodeinsert_end' in kw: fs_args['codeinsert_end'] = kw['vfcodeinsert_end'] self.foundKeys += 1 self.funcspec = RHSfuncSpec(fs_args) # Holder and interface for events self.eventstruct = EventStruct() if 'enforcebounds' in kw: if 'activatedbounds' in kw: ab = kw['activatedbounds'] self.foundKeys += 1 else: ab = None if kw['enforcebounds']: self._makeBoundsEvents(precise=True, activatedbounds=ab) self.foundKeys += 1 if 'events' in kw: self._addEvents(kw['events']) self.foundKeys += 1 self.checkArgs(kw) self.numpars = len(self.pars) tindepdomain = Interval('t_domain', 'float', self._tdomain, self._abseps) tdepdomain = Interval('t', 'float', self._tdata, self._abseps) self.indepvariable = Variable(listid, tindepdomain, tdepdomain, 't') self._register(self.indepvariable) self.dimension = len(self.funcspec.vars) for xname in self.funcspec.vars + self.funcspec.auxvars: # Add a temporary dependent variable domain, for validation testing # during integration self.variables[xname] = Variable(indepdomain=tdepdomain, depdomain=Interval(xname, 'float', self._xdomain[xname], self._abseps)) self._register(self.variables) self._generate_ixmaps() # Introduce any python-specified code to the local namespace if fs_args['targetlang'] == 'python': self.addMethods() # all registration completed self.validateSpec()
def set(self, **kw): """Set ODE system parameters""" validKeys = ['globalt0', 'xdomain', 'tdata', 'tdomain', 'checklevel', 'ics', 'pars', 'algparams', 'inputs', 'pdomain'] assert remain(kw.keys(), validKeys) == [], "Invalid keys in argument" if 'globalt0' in kw: # pass up to generic treatment for this ctsGen.set(self, globalt0=kw['globalt0']) # set this True so that can adjust the input time arrays # to new globalt0 self._extInputsChanged = True if 'checklevel' in kw: # pass up to generic treatment for this ctsGen.set(self, checklevel=kw['checklevel']) # optional keys for this call are ['pars', 'tdomain', 'ics', # 'algparams', 'tdata', 'xdomain', 'pdomain', 'inputs'] if 'ics' in kw: for k_temp, v in kw['ics'].iteritems(): k = k_temp.replace(NAMESEP, "_") if k in self.funcspec.vars+self.funcspec.auxvars: self._xdatadict[k] = v else: raise ValueError, 'Illegal variable name %s'%k self.initialconditions.update(self._xdatadict) if 'tdata' in kw: self._tdata = kw['tdata'] if 'tdomain' in kw: self._tdomain = kw['tdomain'] self.indepvariable.indepdomain.set(self._tdomain) if self._tdomain[0] > self._tdata[0]: print 'tdata cannot be specified below smallest '\ 'value in tdomain\n (possibly due to uncertain bounding).'\ ' It has been automatically adjusted from\n ', \ self._tdata[0], 'to', self._tdomain[0], '(difference of', \ self._tdomain[0]-self._tdata[0], ')' if self._modeltag: print 'Try reducing step size in model.' self._tdata[0] = self._tdomain[0] if self._tdomain[1] < self._tdata[1]: print 'tdata cannot be specified above largest '\ 'value in tdomain\n (possibly due to uncertain bounding).'\ ' It has been automatically adjusted from\n ', \ self._tdomain[1], 'to', \ self._tdomain[1], '(difference of', \ self._tdata[1]-self._tdomain[1], ')' if self._modeltag: print 'Try reducing step size in model.' self._tdata[1] = self._tdomain[1] self.indepvariable.depdomain.set(self._tdata) if 'xdomain' in kw: for k_temp, v in kw['xdomain'].iteritems(): k = k_temp.replace(NAMESEP, "_") # use internal names if k in self.funcspec.vars+self.funcspec.auxvars: if type(v) in [list, Array, NArray]: assert len(v) == 2, \ "Invalid size of domain specification for "+k if v[0] >= v[1]: raise PyDSTool_ValueError('xdomain values must be' 'in order of increasing ' 'size') else: self._xdomain[k] = copy(v) elif type(v) in [float, int]: self._xdomain[k] = [v, v] else: raise PyDSTool_TypeError('Invalid type for xdomain spec' ' '+k) else: raise ValueError, 'Illegal variable name' try: self.variables[k].depdomain.set(v) except TypeError: raise TypeError, ('xdomain must be a dictionary of variable' ' names -> valid interval 2-tuples or ' 'singletons') for ev in self.eventstruct.events.values(): ev._xdomain[k] = self._xdomain[k] if 'pdomain' in kw: for k_temp, v in kw['pdomain'].iteritems(): k = k_temp.replace(NAMESEP, "_") # use internal names if k in self.funcspec.pars: if type(v) in [list, Array, NArray]: assert len(v) == 2, \ "Invalid size of domain specification for "+k if v[0] >= v[1]: raise PyDSTool_ValueError('pdomain values must be' 'in order of increasing ' 'size') else: self._pdomain[k] = copy(v) elif type(v) in [float, int]: self._pdomain[k] = [v, v] else: raise PyDSTool_TypeError('Invalid type for pdomain spec' ' '+k) else: raise ValueError, 'Illegal parameter name' try: self.parameterDomains[k].depdomain.set(v) except TypeError: raise TypeError, ('xdomain must be a dictionary of parameter' ' names -> valid interval 2-tuples or ' 'singletons') for ev in self.eventstruct.events.values(): ev._pdomain[k] = self._pdomain[k] if 'pars' in kw: assert self.numpars > 0, ('No pars were declared for this ' 'model') for k_temp, v in kw['pars'].iteritems(): k = k_temp.replace(NAMESEP, "_") if k in self.pars: cval = self.parameterDomains[k].contains(v) if self.checklevel < 3: if cval is not notcontained: self.pars[k] = v if cval is uncertain and self.checklevel == 2: print 'Warning: Parameter value at bound' else: raise PyDSTool_ValueError, 'Parameter value out of bounds' else: if cval is contained: self.pars[k] = v elif cval is uncertain: raise PyDSTool_UncertainValueError, 'Parameter value at bound' else: raise PyDSTool_ValueError, 'Parameter value out of bounds' else: raise PyDSTool_ValueError, 'Illegal parameter name' if 'algparams' in kw: for k, v in kw['algparams'].iteritems(): self._algparams[k] = v if 'inputs' in kw: assert self.inputs, ('Cannot provide inputs after ' 'initialization without them') inputs = copy(kw['inputs']) _inputs = {} if isinstance(inputs, Trajectory): # extract the variables _inputs = inputs.variables elif isinstance(inputs, Variable): _inputs = {inputs.name: inputs} elif isinstance(inputs, Pointset): # turn into Variables _inputs = dict(zip(inputs.coordnames, [Variable(inputs[n],name=n) for n in inputs.coordnames])) elif isinstance(inputs, dict): _inputs = inputs # ensure values are Variables or Pointsets for k, v in _inputs.iteritems(): if not isinstance(v, Variable): try: _inputs[k]=Variable(v) except: raise TypeError, "Invalid specification of inputs" else: raise TypeError, "Invalid specification of inputs" for v in _inputs.values(): if not iscontinuous(v): raise ValueError, "External inputs for ODE system must be continously defined" if _inputs: for i in _inputs: assert i in self.inputs, 'Incorrect input name provided' self.inputs[i] = _inputs[i] # re-calc inputs ixmaps self._generate_ixmaps('inputs') self._extInputsChanged = True
def set(self, **kw): """Set ODE system parameters""" if remain(kw.keys(), self._validKeys) != []: raise KeyError("Invalid keys in argument") if 'globalt0' in kw: # pass up to generic treatment for this ctsGen.set(self, globalt0=kw['globalt0']) # set this True so that can adjust the input time arrays # to new globalt0 self._extInputsChanged = True if 'checklevel' in kw: # pass up to generic treatment for this ctsGen.set(self, checklevel=kw['checklevel']) if 'abseps' in kw: # pass up to generic treatment for this ctsGen.set(self, abseps=kw['abseps']) # optional keys for this call are ['pars', 'tdomain', 'ics', # 'algparams', 'tdata', 'xdomain', 'pdomain', 'inputs'] if 'ics' in kw: for k_temp, v in kw['ics'].items(): k = self._FScompatibleNames(k_temp) if k in self.funcspec.vars+self.funcspec.auxvars: self._xdatadict[k] = ensurefloat(v) else: raise ValueError('Illegal variable name %s'%k) self.initialconditions.update(self._xdatadict) tchange = False if 'tdata' in kw: self.tdata = kw['tdata'] tchange = True if 'tdomain' in kw: self.tdomain = kw['tdomain'] self.indepvariable.indepdomain.set(self.tdomain) tchange = True if tchange: if self.tdomain[0] > self.tdata[0]: if self.indepvariable.indepdomain.contains(self.tdata[0]) == uncertain: self.diagnostics.warnings.append((W_UNCERTVAL, (self.tdata[0],self.tdomain))) else: print('tdata cannot be specified below smallest '\ 'value in tdomain\n (possibly due to uncertain bounding).'\ ' It has been automatically adjusted from %f to %f (difference of %f)\n' % ( self.tdata[0], self.tdomain[0], self.tdomain[0]-self.tdata[0])) if self._modeltag: print('Try reducing step size in model.') self.tdata[0] = self.tdomain[0] if self.tdomain[1] < self.tdata[1]: if self.indepvariable.indepdomain.contains(self.tdata[1]) == uncertain: self.diagnostics.warnings.append((W_UNCERTVAL, (self.tdata[1],self.tdomain))) else: print('tdata cannot be specified above largest '\ 'value in tdomain\n (possibly due to uncertain bounding).'\ ' It has been automatically adjusted from %f to %f (difference of %f)\n' % ( self.tdomain[1], self.tdomain[1], self.tdata[1]-self.tdomain[1])) if self._modeltag: print('Try reducing step size in model.') self.tdata[1] = self.tdomain[1] self.indepvariable.depdomain.set(self.tdata) if 'xdomain' in kw: for k_temp, v in kw['xdomain'].items(): k = self._FScompatibleNames(k_temp) if k in self.funcspec.vars+self.funcspec.auxvars: if isinstance(v, _seq_types): assert len(v) == 2, \ "Invalid size of domain specification for "+k if v[0] >= v[1]: raise PyDSTool_ValueError('xdomain values must be' 'in order of increasing ' 'size') else: self.xdomain[k] = copy(v) elif isinstance(v, _num_types): self.xdomain[k] = [v, v] else: raise PyDSTool_TypeError('Invalid type for xdomain spec' ' '+k) else: raise ValueError('Illegal variable name') try: self.variables[k].depdomain.set(v) except TypeError: raise TypeError('xdomain must be a dictionary of variable' ' names -> valid interval 2-tuples or ' 'singletons') try: evs = self.eventstruct.events.values() except AttributeError: evs = [] for ev in evs: ev.xdomain[k] = self.xdomain[k] if 'pdomain' in kw: for k_temp, v in kw['pdomain'].items(): k = self._FScompatibleNames(k_temp) if k in self.funcspec.pars: if isinstance(v, _seq_types): assert len(v) == 2, \ "Invalid size of domain specification for "+k if v[0] >= v[1]: raise PyDSTool_ValueError('pdomain values must be' 'in order of increasing ' 'size') else: self.pdomain[k] = copy(v) elif isinstance(v, _num_types): self.pdomain[k] = [v, v] else: raise PyDSTool_TypeError('Invalid type for pdomain spec' ' '+k) else: raise ValueError('Illegal parameter name') try: self.parameterDomains[k].depdomain.set(v) except TypeError: raise TypeError('xdomain must be a dictionary of parameter' ' names -> valid interval 2-tuples or ' 'singletons') try: evs = self.eventstruct.events.values() except AttributeError: evs = [] for ev in evs: ev.pdomain[k] = self.pdomain[k] if 'pars' in kw: for k_temp, v in kw['pars'].items(): k = self._FScompatibleNames(k_temp) if k in self.pars: cval = self.parameterDomains[k].contains(v) if self.checklevel < 3: if cval is not notcontained: self.pars[k] = ensurefloat(v) if cval is uncertain and self.checklevel == 2: print('Warning: Parameter %s: value at bound'%str(k)) else: raise PyDSTool_ValueError('Parameter %s: value out of bounds'%str(k)) else: if cval is contained: self.pars[k] = ensurefloat(v) elif cval is uncertain: raise PyDSTool_UncertainValueError('Parameter %s: value at bound'%str(k)) else: raise PyDSTool_ValueError('Parameter %s: value out of bounds'%str(k)) else: raise PyDSTool_ValueError('Illegal parameter name '+str(k)) if 'algparams' in kw: for k, v in kw['algparams'].items(): self.algparams[k] = v if k in ('eventActive', 'eventTol', 'eventDelay', 'eventDir', 'eventInt', 'eventTerm', 'maxbisect'): raise ValueError("Use appropriate setX method in Generator.eventstruct") if 'inputs' in kw: assert self.inputs, ('Cannot provide inputs after ' 'initialization without them') inputs = copy(kw['inputs']) _inputs = {} if isinstance(inputs, Trajectory): # extract the variables _inputs = self._FScompatibleNames(inputs.variables) elif isinstance(inputs, Variable): _inputs = {self._FScompatibleNames(inputs.name): inputs} elif isinstance(inputs, Pointset): # turn into Variables for n in inputs.coordnames: x_array = inputs[n] nFS = self._FScompatibleNames(n) _input[nFS] = Variable(interp1d(inputs.indepvararray, x_array), 't', Interval(nFS, float, extent(x_array), abseps=self._abseps), name=n) elif isinstance(inputs, dict): _inputs = self._FScompatibleNames(inputs) # ensure values are Variables for v in _inputs.values(): if not isinstance(v, Variable): raise TypeError("Invalid specification of inputs") else: raise TypeError("Invalid specification of inputs") for v in _inputs.values(): if not iscontinuous(v): raise ValueError("External inputs for ODE system must be " "continously defined") if _inputs: for i in _inputs: assert i in self.inputs, 'Incorrect input name provided' self.inputs[i] = _inputs[i] # re-calc inputs ixmaps self._generate_ixmaps('inputs') self._extInputsChanged = True if 'inputs_t0' in kw: assert self.inputs, ('Cannot provide inputs after ' 'initialization without them') inputs_t0 = self._FScompatibleNames(kw['inputs_t0']) for iname, t0 in inputs_t0.items(): self.inputs[iname]._internal_t_offset = t0 self._extInputsChanged = True
def compute(self, trajname, ics=None): assert self.funcspec.targetlang == 'python', \ ('Wrong target language for functional specification. ' 'Python needed for this class') assert isinstance(self.funcspec, RHSfuncSpec), ('Map system ' 'requires RHSfuncSpec type to proceed') if self.defined: self.validateSpec() ## assert remain(self.initialconditions.keys(), ## self._xdatadict.keys()+self.funcspec.auxvars) == [],\ ## ('mismatching entries between initial conditions and ' ## 'declared variable names') self.clearWarnings() self.clearErrors() if ics is not None: self.set(ics=ics) xnames = self._var_ixmap # ensures correct order # wrap up each dictionary initial value as a singleton list alltData = [self.indepvariable.depdomain.get(0)] allxDataDict = dict(zip(xnames, map(listid, sortedDictValues(self.initialconditions, self.funcspec.vars)))) rhsfn = eval("self."+self.funcspec.spec[1]) # Check i.c.'s are well defined (finite) self.checkInitialConditions() self.setEventICs(self.initialconditions, self.globalt0) ic = sortedDictValues(self.initialconditions, self.funcspec.vars) plist = sortedDictValues(self.pars) extralist = copy(plist) ilist = [] if self.inputs: # inputVarList is a list of Variables listend = self.numpars + len(self.inputs) inputVarList = sortedDictValues(self.inputs) try: for f in inputVarList: f.clearWarnings ilist.append(f(alltData[0], self.checklevel)) except AssertionError: print 'External input call has t out of range: t = ', \ self.indepvariable.depdomain.get(0) print 'Maybe checklevel is 3 and initial time is not', \ 'completely inside valid time interval' raise except ValueError: print 'External input call has value out of range: t = ', \ self.indepvariable.depdomain.get(0) for f in inputVarList: if len(f.warnings): print 'External input %s out of range:' % f.name print ' t = ', repr(f.warnings[-1][0]), ', ', \ f.name, ' = ', repr(f.warnings[-1][1]) raise else: listend = self.numpars inputVarList = [] extralist.extend(ilist) precevents = self.eventstruct.query(['precise']) if precevents != []: raise PyDSTool_ValueError('precise events are not valid for map systems') eventslist = self.eventstruct.query(['highlevel', 'active', 'notvarlinked']) termevents = self.eventstruct.query(['term'], eventslist) # initialize event info dictionaries Evtimes = {} Evpoints = {} for (evname, ev) in eventslist: Evtimes[evname] = [] Evpoints[evname] = [] if eventslist != []: self.eventstruct.resetHighLevelEvents(self.indepvariable.depdomain.get(0), eventslist) self.eventstruct.validateEvents(self.funcspec.vars + \ self.funcspec.auxvars + \ ['t'], eventslist) # per-iteration storage of variable data (initial values are irrelevant) xDataDict = {} # storage of all auxiliary variable data allaDataDict = {} anames = self.funcspec.auxvars avals = apply(eval("self."+self.funcspec.auxspec[1]), [self.indepvariable.depdomain.get(0), sortedDictValues(self.initialconditions, self.funcspec.vars), extralist]) for aix in range(len(anames)): aname = anames[aix] allaDataDict[aname] = [avals[aix]] # temp storage of first time at which terminal events found # (this is used for keeping the correct end point of new mesh) first_found_t = None tmesh = self.indepvariable.depdomain.uniformSample(self.tstep, strict=False, avoidendpoints=self.checklevel>2) # Main loop breakwhile = False success = False x = ic notdone = True # did i=0 for initial condition already i = 1 while notdone: t = tmesh[i] ## COMPUTE NEXT STATE y from x try: y = rhsfn(t, x, extralist) except: print "Error in calling right hand side function:" self.showSpec() raise for xi in xrange(self.dimension): xDataDict[xnames[xi]] = y[xi] if not self.contains(self.variables[xnames[xi]].depdomain, y[xi], self.checklevel): self.warnings.append((W_TERMSTATEBD, (t, xnames[xi], y[xi], self.variables[xnames[xi]].depdomain))) breakwhile = True break # for loop if breakwhile: notdone = False continue if eventslist != []: dataDict = copy(xDataDict) dataDict['t'] = t evsflagged = self.eventstruct.pollHighLevelEvents(None, dataDict, self.pars, eventslist) termevsflagged = filter(lambda e: e in evsflagged, termevents) nontermevsflagged = filter(lambda e: e not in termevsflagged, evsflagged) # register any non-terminating events in the warnings list if len(nontermevsflagged) > 0: evnames = [ev[0] for ev in nontermevsflagged] self.warnings.append((W_NONTERMEVENT, (t, evnames))) for evname in evnames: Evtimes[evname].append(t) Evpoints[evname].append(y) if termevsflagged != []: # active terminal event flagged at this time point # register the event in the warnings evnames = [ev[0] for ev in termevsflagged] self.warnings.append((W_TERMEVENT, \ (t, evnames))) for evname in evnames: Evtimes[evname].append(t) Evpoints[evname].append(y) notdone = False continue alltData.append(t) for xi in range(self.dimension): allxDataDict[xnames[xi]].append(y[xi]) avals = apply(eval("self."+self.funcspec.auxspec[1]), [t, sortedDictValues(xDataDict), extralist]) for aix in range(len(anames)): aname = anames[aix] allaDataDict[aname].append(avals[aix]) try: extralist[self.numpars:listend] = [apply(f, [t, self.checklevel]) \ for f in inputVarList] except ValueError: print 'External input call caused value out of range error:', \ 't = ', t for f in inputVarList: if len(f.warnings): print 'External input variable %s out of range:' % f.name print ' t = ', repr(f.warnings[-1][0]), ', ', \ f.name, ' = ', repr(f.warnings[-1][1]) raise except AssertionError: print 'External input call caused t out of range error: t = ', t raise if i >= len(tmesh) - 1: notdone = False else: i += 1 x = y # update success flag success = not notdone # Check that any terminal events found terminated the code correctly if first_found_t is not None: assert self.warnings[-1][0] == W_TERMEVENT, ("Event finding code " "for terminal event failed") # Package up computed trajectory in Variable variables # Add external inputs warnings to self.warnings, if any for f in inputVarList: for winfo in f.warnings: self.warnings.append((W_NONTERMSTATEBD, (winfo[0], f.name, winfo[1], f.depdomain))) # check for non-unique terminal event termcount = 0 for (w,i) in self.warnings: if w == W_TERMEVENT or w == W_TERMSTATEBD: termcount += 1 if termcount > 1: self.errors.append((E_NONUNIQUETERM, (alltData[-1], i[1]))) ## print 'Time interval adjusted according to %s: %s' % \ ## (self._warnmessages[w], str(i[0])+", "+ str(i[1])) # Create variables (self.variables contains no actual data) variables = copyVarDict(self.variables) # build event pointset information (reset previous trajectory's) self.trajevents = {} for (evname, ev) in eventslist: evpt = Evpoints[evname] if evpt == []: self.trajevents[evname] = None else: evpt = transpose(array(evpt)) self.trajevents[evname] = Pointset({'coordnames': xnames, 'indepvarname': 't', 'coordarray': evpt, 'indepvararray': Evtimes[evname], 'indepvartype': self.variables[xnames[0]].indepvartype}) for x in xnames: if len(alltData) > 1: variables[x] = Variable(Pointset({'coordnames': [x], 'coordarray': allxDataDict[x], 'coordtype': self.variables[x].coordtype, 'indepvarname': 't', 'indepvararray': alltData, 'indepvartype': self.variables[x].indepvartype}), 't', x, x) else: raise PyDSTool_ValueError, "Fewer than 2 data points computed" for a in anames: if len(alltData) > 1: variables[a] = Variable(Pointset({'coordnames': [a], 'coordarray': allaDataDict[a], 'coordtype': self.variables[a].coordtype, 'indepvarname': 't', 'indepvararray': alltData, 'indepvartype': self.variables[a].indepvartype}), 't', a, a) else: raise PyDSTool_ValueError, "Fewer than 2 data points computed" if success: self.validateSpec() self.defined = True return Trajectory(trajname, variables.values(), self.globalt0, self.checklevel) else: print 'Trajectory computation failed' self.errors.append((E_COMPUTFAIL, (t, self._errorcodes[errcode]))) self.defined = False
def __init__(self, kw): discGen.__init__(self, kw) self._errmessages[E_COMPUTFAIL] = 'Computation of trajectory failed' self.needKeys.extend(['varspecs']) self.optionalKeys.extend(['tdomain', 'xdomain', 'inputs', 'tdata', 'ics', 'events', 'system', 'ignorespecial', #'compiler', 'auxvars', 'vars', 'fnspecs', 'ttype', 'xtype', 'tstep', 'checklevel', 'pars', 'pdomain', 'vfcodeinsert_start', 'vfcodeinsert_end', 'enforcebounds', 'activatedbounds', 'reuseterms']) fs_args = {} if 'varspecs' in kw: self.foundKeys += 1 varspecs = ensureStrArgDict(kw['varspecs']) else: raise PyDSTool_KeyError("Keyword 'varspecs' missing from " "argument") if 'pars' in kw: self.pars = {} if type(kw['pars']) == list: # may be a list of symbolic definitions for p in kw['pars']: try: self.pars[p.name] = p.tonumeric() except (AttributeError, TypeError): raise TypeError, "Invalid parameter symbolic definition" else: for k, v in dict(kw['pars']).iteritems(): self.pars[str(k)] = v fs_args['pars'] = self.pars.keys() self._register(self.pars) self.foundKeys += 1 if 'vfcodeinsert_start' in kw: fs_args['codeinsert_start'] = kw['vfcodeinsert_start'] self.foundKeys += 1 if 'vfcodeinsert_end' in kw: fs_args['codeinsert_end'] = kw['vfcodeinsert_end'] self.foundKeys += 1 if 'system' in kw: self._solver = kw['system'] try: fs_args['ignorespecial'] = [self._solver.name] except: raise TypeError, "Invalid solver system provided" self.foundKeys += 1 if self.pars: # automatically pass par values on to embedded system # when Rhs called parlist = self.pars.keys() parstr = "".join(["'%s': %s, "%(parname,parname) \ for parname in parlist]) if 'codeinsert_start' in fs_args: fs_args['codeinsert_start'] = \ ' %s.set(pars={%s})\n'%(self._solver.name, parstr) \ + fs_args['codeinsert_start'] else: fs_args['codeinsert_start'] = \ ' %s.set(pars={%s})\n'%(self._solver.name, parstr) else: fs_args['ignorespecial'] = [] self._solver = None if 'ignorespecial' in kw: fs_args['ignorespecial'].extend(kw['ignorespecial']) self.foundKeys += 1 if 'tdomain' in kw: self._tdomain = kw['tdomain'] if self._tdomain[0] >= self._tdomain[1]: raise PyDSTool_ValueError('tdomain values must be in order of increasing size') self.foundKeys += 1 else: self._tdomain = [-Inf, Inf] if 'ttype' in kw: indepvartype = kw['ttype'] assert indepvartype in _pynametype.keys(), 'Invalid ttype' self.foundKeys += 1 else: indepvartype = 'float' if 'tdata' in kw: self._tdata = kw['tdata'] if self._tdata[0] >= self._tdata[1]: raise PyDSTool_ValueError('tdata values must be in order of increasing size') # _tdata is made into list to be consistent with # other uses of it in other Generators... if self._tdomain[0] > self._tdata[0]: print 'tdata cannot be specified below smallest '\ 'value in tdomain\n (possibly due to uncertain'\ 'bounding). It has been automatically adjusted\n'\ ' from\n ', self._tdata[0], 'to', self._tdomain[0],\ '(difference of', self._tdomain[0]-self._tdata[0], ')' self._tdata[0] = self._tdomain[0] if self._tdomain[1] < self._tdata[1]: print 'tdata cannot be specified above largest '\ 'value in tdomain\n (possibly due to uncertain '\ 'bounding). It has been automatically adjusted\n'\ ' from\n ', self._tdata[1], 'to', self._tdomain[1],\ '(difference of', self._tdata[1]-self._tdomain[1], ')' self._tdata[1] = self._tdomain[1] self.foundKeys += 1 else: self._tdata = self._tdomain # default needed if 'tstep' in kw: self.tstep = kw['tstep'] if self.tstep > self._tdata[1]-self._tdata[0]: raise PyDSTool_ValueError('tstep too large') if indepvartype == 'int' and round(self.tstep) != self.tstep: raise PyDSTool_ValueError('tstep must be an integer for integer ttype') self.foundKeys += 1 else: if indepvartype == 'int': # default to 1 for integer types self.tstep = 1 else: # no reasonable default - so raise error raise PyDSTool_KeyError('tstep key needed for float ttype') if 'inputs' in kw: inputs = copy(kw['inputs']) self.inputs = {} if isinstance(inputs, Trajectory): # extract the variables self.inputs = inputs.variables elif isinstance(inputs, Variable): self.inputs = {inputs.name: inputs} elif isinstance(inputs, Pointset): # turn into Variables but only define at Pointset's # own independent variable values self.inputs = dict(zip(inputs.coordnames, [Variable(inputs[[n]],name=n) for n in inputs.coordnames])) elif isinstance(inputs, dict): self.inputs = inputs # ensure values are Variables or Pointsets for k, v in self.inputs.iteritems(): if not isinstance(v, Variable): try: self.inputs[k]=Variable(v) except: raise TypeError, "Invalid specification of inputs" else: raise TypeError, "Invalid specification of inputs" # don't check that variables have discrete domains in case wish # to use cts-valued ones sampled at discrete times fs_args['inputs'] = self.inputs.keys() self._register(self.inputs) self.foundKeys += 1 else: self.inputs = {} if 'ics' in kw: self._xdatadict = {} for k, v in dict(kw['ics']).iteritems(): self._xdatadict[str(k)] = v self.initialconditions = self._xdatadict for name in remain(varspecs.keys(), self._xdatadict.keys()): self.initialconditions[name] = NaN self.foundKeys += 1 else: self._xdatadict = {} for name in varspecs: self.initialconditions[name] = NaN if 'xtype' in kw: depvartype = kw['xtype'] assert depvartype in _pynametype.keys(), 'Invalid xtype' self.foundKeys += 1 else: depvartype = 'float' if 'auxvars' in kw: assert 'vars' not in kw, ("Cannot use both 'auxvars' and 'vars' " "keywords") if isinstance(kw['auxvars'], list): auxvars = [str(v) for v in kw['auxvars']] else: auxvars = [str(kw['auxvars'])] vars = remain(varspecs.keys(), auxvars) self.foundKeys += 1 elif 'vars' in kw: assert 'auxvars' not in kw, \ "Cannot use both 'auxvars' and 'vars' keywords" if isinstance(kw['vars'], list): vars = [str(v) for v in kw['vars']] else: vars = [str(kw['vars'])] auxvars = remain(varspecs.keys(), vars) self.foundKeys += 1 else: auxvars = [] vars = varspecs.keys() if auxvars != []: fs_args['auxvars'] = auxvars if 'xdomain' in kw: self._xdomain = {} for k, v in dict(kw['xdomain']).iteritems(): name = str(k) if type(v) in [list, Array, NArray]: assert len(v) == 2, \ "Invalid size of domain specification for "+name if v[0] >= v[1]: raise PyDSTool_ValueError('xdomain values must be in' 'order of increasing size') else: self._xdomain[name] = copy(v) elif type(v) in [float, int]: self._xdomain[name] = [v, v] else: raise PyDSTool_TypeError('Invalid type for xdomain spec' ' '+name) for name in remain(varspecs.keys(), self._xdomain.keys()): self._xdomain[name] = [-Inf, Inf] self.foundKeys += 1 else: self._xdomain = {} for name in varspecs: self._xdomain[name] = [-Inf, Inf] if 'reuseterms' in kw: fs_args['reuseterms'] = kw['reuseterms'] self.foundKeys += 1 fs_args.update({'vars': vars, 'varspecs': varspecs, 'name': self.name }) if 'pdomain' in kw: if self.pars: self._pdomain = {} for k, v in dict(kw['pdomain']).iteritems(): assert len(v) == 2, "Invalid interval for parameter %s"%k self._pdomain[str(k)] = v for name in self._pdomain: if self._pdomain[name][0] >= self._pdomain[name][1]: raise PyDSTool_ValueError('pdomain values must be in order of increasing size') for name in remain(self.pars.keys(), self._pdomain.keys()): self._pdomain[name] = [-Inf, Inf] self.foundKeys += 1 else: raise ValueError('Cannot specify pdomain because no pars declared') else: if self.pars: self._pdomain = {} for pname in self.pars: self._pdomain[pname] = [-Inf, Inf] if self.pars: self.parameterDomains = {} for pname in self._pdomain: self.parameterDomains[pname] = Interval(pname, 'float', self._pdomain[pname], self._abseps) try: cval = self.parameterDomains[pname].contains(self.pars[pname]) except KeyError: raise ValueError("Parameter %s is missing a value"%pname) if self.checklevel < 3: if cval is not notcontained: if cval is uncertain and self.checklevel == 2: print 'Warning: Parameter value at bound' else: raise PyDSTool_ValueError, 'Parameter value out of bounds' else: if cval is uncertain: raise PyDSTool_UncertainValueError, 'Parameter value at bound' elif cval is notcontained: raise PyDSTool_ValueError, 'Parameter value out of bounds' if 'fnspecs' in kw: fs_args['fnspecs'] = ensureStrArgDict(kw['fnspecs']) self.foundKeys += 1 ## fs_args['targetlang'] = 'python' ## if 'compiler' in kw: ## if fs_args['targetlang'] == 'python': ## print "Warning: redundant option 'compiler' for python target" ## self._compiler = kw['compiler'] ## self.foundKeys += 1 ## else: ## self._compiler = '' ## if fs_args['targetlang'] != 'python' and inputs: ## raise PyDSTool_ValueError('Cannot use external inputs with non-Python target language') self.funcspec = RHSfuncSpec(fs_args) # Holder and interface for events self.eventstruct = EventStruct() if 'enforcebounds' in kw: if 'activatedbounds' in kw: ab = kw['activatedbounds'] self.foundKeys += 1 else: ab = None if kw['enforcebounds']: self._makeBoundsEvents(precise=False, activatedbounds=ab) self.foundKeys += 1 if 'events' in kw: self._addEvents(kw['events']) self.foundKeys += 1 self.checkArgs(kw) self.numpars = len(self.pars) tindepdomain = Interval('t_domain', indepvartype, self._tdomain, self._abseps) tdepdomain = Interval('t', indepvartype, self._tdata, self._abseps) self.indepvariable = Variable(listid, tindepdomain, tdepdomain, 't') self._register(self.indepvariable) self.dimension = len(self.funcspec.vars) for xname in self.funcspec.vars + self.funcspec.auxvars: # Add a temporary dependent variable domain, for validation testing # during integration self.variables[xname] = Variable(indepdomain=tdepdomain, depdomain=Interval(xname, depvartype, self._xdomain[xname], self._abseps)) self._register(self.variables) self._generate_ixmaps() # Introduce any python-specified code to the local namespace ## if fs_args['targetlang'] == 'python': self.addMethods() # all registration completed self.validateSpec()