diff options
Diffstat (limited to 'diffeq.py')
-rw-r--r-- | diffeq.py | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/diffeq.py b/diffeq.py new file mode 100644 index 0000000..1ecc705 --- /dev/null +++ b/diffeq.py @@ -0,0 +1,106 @@ +import time, types, itertools +from scipy.interpolate import interp1d +from scipy.integrate import odeint +from scipy.optimize import fmin + +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 + + >>> # Now suppose foo is a class method and bar is in _flags. + >>> 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 #finding the object having asked for it before + #self.__foo is returned + + >>> self.bar=2 #setting bar resets all self.__foos + + >>> self.foo #self.foo() is called again, self.__foo 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 + differentiate variable names by underscores. + + The benefit of this system is that every normal float will be optimized, + while every _under float will be ignored completely, and flagging a var + 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): + 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. + """ + def __init__(self): + self._time = time.time() + + # All floats lacking an initial _underscore will be optimized. + self.opt_vars = {} + for key, value in vars(self).items(): + if key[0] == "_": continue + if type(value) != float: continue + self.opt_vars[key] = value + def time(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 + (be very wary of storing variables under these conditions!) + """ + sgetattr = super(DiffEq, self).__getattribute__ + try: + value = sgetattr(attr) + if type(value) == types.MethodType: + try: value = 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 + + _flags = [] + def __setattribute__(self, attr): + """Clears dunder updates when phi or phi1 are changed.""" + sgetattr = super(DiffEq, self).__getattribute__ + ssetattr = super(DiffEq, self).__setattribute__ + if attr in self.flags: + for key, value in vars(self).items(): + if key[:2] != "__": continue + if type(sgetattr(key[2:])) != types.MethodType: continue + vars(self).remove(key) + ssetattr(attr) + + def check_in(self, variables): + """Usage is as follows. + + def method(self, var0=None, var1=None, ...): + self.check_in(vars()) + return do_stuff_with_vars() + """ + for key, var in variables.items(): + if var == None: + variables[key] = getattr(self, key) + + def solve_fun(self, func=None, init_vars=None, timespace=None): + """wrapper for odeint""" + check_in(vars()) + time0 = current_time() + time = numpy.linspace(*timespace) + soln = odeint(func, init_vars, time) + print " :: took %s seconds" % (current_time() - time0) + return time, soln + + #in optimize(): vars().update(self.opt_vars) + + |