Advertisement
mwchase

Untitled

Feb 18th, 2013
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.56 KB | None | 0 0
  1. import numpy
  2. import error
  3. import math
  4.  
  5. #System specifications:
  6.  
  7. #System classes are responsible for defining the differential operator, and
  8. #rendering the initial state to seed solvers
  9.  
  10. #System constructors convert data from human read/writeable form, to an
  11. #internal representation
  12.  
  13. #System state consists of two parts: the time component, which is a float,
  14. #and the w vector, which has some shape, subject only to the restriction that
  15. #the differential operator returns an array with the same shape, when given a
  16. #w vector and a time
  17.  
  18. def optional_w(f):
  19.     def f_opt(self, w=False):
  20.         if w == False:
  21.             w = self.initial[0]['w']
  22.         return f(self, w)
  23.     f_opt.__name__ = f.__name__
  24.     f_opt.__doc__ = f.__doc__
  25.     return f_opt
  26.  
  27. def optional_state(f):
  28.     def f_opt(self, state=False):
  29.         if state == False:
  30.             state = self.initial[0]
  31.         return f(self, state)
  32.     f_opt.__name__ = f.__name__
  33.     f_opt.__doc__ = f.__doc__
  34.     return f_opt
  35.  
  36. def statify(f):
  37.     def f_new(state=False):
  38.         if state == False:
  39.             return f()
  40.         return f(state['w'])
  41.     f_new.__name__ = f.__name__
  42.     f_new.__doc__ = f.__doc__
  43.     return f_new
  44.  
  45. class System(object):
  46.    
  47.     "Dummy implementation of the System class."
  48.    
  49.     w_type = NotImplemented
  50.     initial = NotImplemented
  51.    
  52.     @optional_state
  53.     def differential(self, state):
  54.         raise NotImplementedError
  55.    
  56.     def flat_differential(self, t=None, w=None):
  57.         if w is None or t is None:
  58.             return self.differential().view(dtype=numpy.float64)
  59.         else:
  60.             return self.differential(
  61.                 {'t': t, 'w': numpy.rec.array(w,
  62.                     dtype=self.initial[0]['w'].dtype)}).view(
  63.                         dtype=numpy.float64)
  64.  
  65. class Polynomial(System):
  66.     def __init__(self, coefficients, t=0):
  67.         self.coefficients = coefficients
  68.         #self.initial =
  69.    
  70.     def exact(self, t):
  71.         return sum([coefficients[i] * t**i for i in range(len(coefficients))])
  72.    
  73.     @optional_state
  74.     def differential(self, state):
  75.         t = state['t']
  76.         return sum(i * [coefficients[i] * t**(i-1) for i in range(len(coefficients))])
  77.  
  78. class Exponential(System):
  79.     def __init__(self, initial=1, lambda_=-1, t=0):
  80.         self.lambda_ = lambda_
  81.         self.w_type = numpy.float
  82.         self.array_type = numpy.dtype([('t', numpy.float, 1),
  83.                                        ('w', self.w_type, 1)])
  84.         self.initial = numpy.empty(1, self.array_type)
  85.         self.initial[0]['t'] = t
  86.         self.initial[0]['w'] = initial
  87.    
  88.     def exact(self, t):
  89.         return self.initial[0]['w'] * math.exp(self.lambda_ * (t - self.initial[0]['t']))
  90.    
  91.     @optional_state
  92.     def differential(self, state):
  93.         return state['w'] * self.lambda_
  94.  
  95. class Orbital(System):
  96.    
  97.     def __init__(self, *bodies, **kwargs):
  98.         t = 0
  99.         if 't' in kwargs:
  100.             t = kwargs['t']
  101.         self.G = 1
  102.         if 'G' in kwargs:
  103.             self.G = kwargs['G']
  104.         self.size = len(bodies)
  105.         if self.size == 0: #Degenerate case in which nothing happens
  106.             return
  107.         if self.size == 1: #Degenerate case in which all methods have no error
  108.             return
  109.         self.masses = numpy.asarray([[body['mass']] for body in bodies])
  110.         self.mass = sum(self.masses)
  111.         self.potential_constants = -self.G*numpy.ma.masked_array(self.masses.transpose()*self.masses, numpy.eye(self.size))
  112.         self.D = len(bodies[0]['pos'])
  113.         self.zero = numpy.zeros(self.D)
  114.         if self.D != 2 and self.D != 3:
  115.             return
  116.         self.point_type = numpy.dtype([('pos', numpy.float, self.D),
  117.                                    ('vel', numpy.float, self.D)])
  118.         self.w_type = numpy.dtype((self.point_type, self.size))
  119.         self.array_type = numpy.dtype([('t', numpy.float, 1),
  120.                                        ('w', self.w_type, 1)])
  121.         self.initial = numpy.empty(1, self.array_type)
  122.         self.initial[0]['t'] = t
  123.         for i in range(self.size):
  124.             for j in range(self.D):
  125.                 self.initial[0]['w'][i]['pos'][j] = bodies[i]['pos'][j]
  126.                 self.initial[0]['w'][i]['vel'][j] = bodies[i]['vel'][j]
  127.        
  128.         self.errors = {
  129.             "barycenter": error.Projection(statify(self.barycenter),
  130.                                            self.projected_barycenter,
  131.                                            self.momentum()/sum(self.masses),
  132.                                            t),
  133.             "energy": error.Invariant(statify(self.mechanical_energy)),
  134.             "momentum": error.InvariantCoordinate(statify(self.momentum)),
  135.             "angular momentum": (
  136.                 self.D==3 and
  137.                 error.InvariantCoordinate or
  138.                 error.Invariant)(statify(self.angular_momentum))}
  139.        
  140.         if (self.momentum() == self.zero).all():
  141.             print "WARNING: The system's momentum is zero. This is physically unlikely, and leads to degenerate behavior."
  142.    
  143.     @optional_state
  144.     def pos(self, state):
  145.         return state['w']['pos']
  146.    
  147.     @optional_state
  148.     def vel(self, state):
  149.         return state['w']['vel']
  150.    
  151.     @optional_state
  152.     def tee(self, state):
  153.         return state['t']
  154.    
  155.     @optional_w
  156.     def momenta(self, w):
  157.         return self.masses * w['vel']
  158.    
  159.     def momentum(self, w=False):
  160.         return sum(self.momenta(w))
  161.    
  162.     #@optional_w
  163.     def mechanical_energy(self, w=False):
  164.         return self.kinetic_energy(w) + self.potential_energy(w)
  165.    
  166.     @optional_w
  167.     def kinetic_energy(self, w):
  168.         return 0.5 * sum(sum(self.masses * (w['vel'] * w['vel'])))
  169.    
  170.     @optional_w
  171.     def barycenter(self, w):
  172.         return sum(self.masses * w['pos']) / self.mass
  173.    
  174.     def projected_barycenter(self, t=None):
  175.         diff = 0
  176.         if t is not None:
  177.             diff = t - self.initial[0]['t']
  178.         return self.barycenter() + diff * self.momentum() / self.mass
  179.    
  180.     @optional_w
  181.     def angular_momentum(self, w):
  182.         return sum(numpy.cross(w['pos']-numpy.repeat([self.barycenter(w)],
  183.                                                      self.size, 0),
  184.                                self.momenta(w)))
  185.        
  186.     @optional_w
  187.     def displacements(self, w):
  188.         pos = numpy.repeat([w['pos']], self.size, 0)
  189.         #print pos.shape
  190.         return pos - pos.transpose(1, 0, 2)
  191.    
  192.     #@optional_w
  193.     def distances_squared(self, w=False):
  194.         return (self.displacements(w)**2).sum(2)
  195.    
  196.     #@optional_w
  197.     def distances(self, w=False):
  198.         return self.distances_squared(w)**0.5
  199.        
  200.     #@optional_w
  201.     def potentials(self, w=False):
  202.         return self.potential_constants / self.distances(w)
  203.    
  204.     #@optional_w
  205.     def potential_energy(self, w=False):
  206.         return 0.5*self.potentials(w).filled(0).sum()
  207.        
  208.     #@optional_w
  209.     def forces(self, w=False):
  210.         return ((numpy.repeat(self.potentials(w) / self.distances_squared(w),
  211.                               self.D).reshape((self.size, self.size, self.D)) *
  212.                  self.displacements(w)).filled(0)).sum(0)
  213.    
  214.     #@optional_w
  215.     def accelerations(self, w=False):
  216.         return self.forces(w)/self.masses
  217.    
  218.     @optional_state
  219.     def differential(self, state):
  220.         w = state['w']
  221.         result = numpy.empty_like(w)
  222.         result['pos'] = w['vel']
  223.         result['vel'] = self.accelerations(w)
  224.         return result
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement