diff options
Diffstat (limited to 'diffeq.py')
-rw-r--r-- | diffeq.py | 86 |
1 files changed, 45 insertions, 41 deletions
@@ -1,39 +1,34 @@ -import time, types, itertools +import time, types, itertools, os.path from scipy.interpolate import interp1d from scipy.integrate import odeint from scipy.optimize import fmin +from collections import OrderedDict class DiffEq(object): """designed to make numerically solving diff eqs more readable setattr and getattr have been modified to provide the following effects: - >>> self._foo=2 #setting an _under var makes it still callable by... + >>> self._foo=2.#setting an _under var makes it still returned by... >>> self.foo - 2 - >>> self.foo is self._foo - True #so they share the same namespace - - >>> # Now suppose foo is a class method and bar is in _flags. + 2.0 + >>> self._foo=2 #but only if it's a float + >>> self.foo + AttributeError: self has no attribute 'foo' + >>> # Now suppose _foo is a class method and bar is in _flags. + >>> self._foo = lambda self: self.bar + >>> self.flags.append('bar') + >>> self.bar = 3.14 >>> self.foo #finding the object having not found it before: - #self.foo() is called and stored to self.__foo - #self.__foo is returned + #self._foo() is called and stored to self.__foo + 3.14 #self.__foo is returned >>> self.foo #finding the object having asked for it before: - #self.__foo is returned + 3.14 #self.__foo is returned directly >>> self.bar=2 #setting bar resets all self.__foos - >>> self.foo #self.foo() is called again, self.__foo returned - - >>> # You can also subvert the second mechanism using the first, - >>> # as the mechansims do not recurse on themselves. - >>> # Suppose _foo is a class method, bar is in _flags - >>> self.foo - <bound method self._foo of ... > - >>> self._foo - <bound method self._foo of ... > - >>> self - >>> # The class is prevented from creating ___trunder variables. + >>> self.foo #self._foo() is called again, stored to self.__foo + 2 #the new self.__foo is returned Note that with this behavior you should treat all variable names, be they normal, _under, or __dunder, as in the same namespace. Don't even try to @@ -44,7 +39,7 @@ class DiffEq(object): with _under will not change the behavior of any functions using it. Additionally, if you suddenly realize that foo should be dependent on bar and baz, you simply define: - def foo(self): + def _foo(self): return do_stuff(self.bar, self.baz) and bar and baz will be optimized while foo will be ignored -- and no function code using foo needs to be rewritten. @@ -53,33 +48,35 @@ class DiffEq(object): self._time = time.time() # All floats lacking an initial _underscore will be optimized. - self.opt_vars = {} + self.opt_vars = OrderedDict() for key, value in vars(self).items(): if key[0] == "_": continue if type(value) != float: continue self.opt_vars[key] = value - def _gettime(self): return time.time() - self.time + def gettime(self): return time.time() - self.time def __getattribute__(self, attr): """Provides a few getattr psuedonyms: - allows self.foo to return: - self._foo if self.foo DNE - self.foo() if self.foo is a method + self.foo tries to return: + self.foo if foo exists + self._foo if _foo is a float + self._foo() if _foo is a method see DiffEq's documentation for examples """ sgetattr = super(DiffEq, self).__getattribute__ - try: - value = sgetattr(attr) - if type(value) == types.MethodType and attr[0] != '_': - try: value = sgetattr("__" + attr) + try: return sgetattr(attr) + except AttributeError as err: + if attr[0] == "_": raise err + value = sgetattr("_" + attr) + if type(value) == types.MethodType: + try: return sgetattr("__" + attr) except AttributeError: value = value() setattr(self, "__" + attr, value) - except AttributeError as err: - if attr[0] == "_": raise err - else: value = sgetattr("_" + attr) - return value + return value + if type(value) == float: return value + raise err _flags = [] def __setattribute__(self, attr): @@ -106,17 +103,24 @@ class DiffEq(object): self.soln = odeint(self.diff_eq, self.init_vars, self.time) print " :: took %s seconds" % (self.gettime() - time0) - #in optimize(): vars().update(self.opt_vars) + def opt_init(self, guesses=None): + if guesses == None: + for var in self.opt_vars: + self.opt_vars[var] = getattr(self, var) + else: + for var, guess in itertools.izip(self.opt_vars, guesses): + setattr(self, var, guess) + + #_outfile = tempfile.mktemp(dir='data', prefix=str(self.gettime())) + outfile = lambda: os.path.join('data', str(self.gettime())) def opt_fun(self, guesses, f, func, init_vars): """Optimize the free variables for the diff eq.""" - for key, val in zip(opt_vars.iterkeys(), guesses): - setattr(self, key, val) - #map(setattr, self, opt_vars.iterkeys(), guesses) + self.opt_init() + map(setattr, itertools.repeat(self), self.opt_vars.iterkeys(), guesses) self.__dict__.update(dict(zip(self.opt_vars.iterkeys(), guesses))) outfile = self.__dict__.get('outfile') - r0, r_roll, length, m, Mass = guesses - time, soln = solve_fun(func, init_vars) + time, soln = self.solve_diff_eq() phi, phi1, v_tan, tension, moment, momentum, max_arg = \ interpret(soln) |