Swarm-NG  1.1
logrecord.py
Go to the documentation of this file.
1 ## @file logrecord.py Routines and classes to access a binary log record structure
2 #
3 # To read the documentation generated from this file refer to @ref swarmng.logrecord
4 
5 ## @package swarmng.logrecord
6 # Contains the support functions for accessing the C++ logrecord data strcture
7 
8 from bsddb3.db import *
9 from struct import *
10 from collections import namedtuple
11 from . import keplerian_for_cartesian
12 
13 ## Compute the physical center of mass (weighted average of properties by mass) of an array of planets
14 #
15 # \arg \c bodies : an array of structure [((x,y,z),(vx,vy,vz),mass),...]
16 #
17 # Returns a tuple of structure ((x,y,z),(vx,vy,vz),mass), where x,y,z,vx,vy,vz
18 # are weighted average of the corresponding attributes in orginial array. mass is
19 # the sum of all mass.
20 #
21 def center_of_mass(bodies):
22  cx = cy = cz = cvx = cvy = cvz = cmass = 0
23  for ((x,y,z),(vx,vy,vz),mass) in bodies:
24  cx += x; cy += y; cz += z;
25  cvx += vx; cvy += vy; cvz += vz;
26  cmass += mass
27 
28  return ((cx/cmass,cy/cmass,cz/cmass),(cvx/cmass,cvy/cmass,cvz/cmass),cmass)
29 
30 ## Take a list and return a new iterable that yields elements from the original list with indices
31 def with_index(list,starting_index = 0):
32  return zip(range(starting_index,starting_index+len(list)),list)
33 
34 
35 ## Data structure equivalent of the logrecord defined in Swarm-NG C++ library
36 # This class does not use any C++ code, intead it uses pack/unpack to directly parse
37 # the binary format into Python variables.
38 #
39 # Currently, the data structure stores a snapshot of the
40 # state of a planetary system.
41 #
42 # The constructor of this class does not do anything.
43 # Static method from_binary should be used to parse binary strings
44 # and create instances of this class
45 #
46 #
47 #
48 # \TODO: make the constructor private
49 #
50 class LogRecord:
51 
52  ## List of bodies (planets and star) each element is of type \ref swarmng.logrecord.LogRecord.Body "Body"
53  bodies = property
54  ## Time of the snapshot in AU (floating point)
55  time = property
56  ## Integer identifier of the system
57  sys = property
58  ## The current state of system, different codes may be used by
59  # any software that writes the logrecord
60  #
61  # Regular values:
62  # * 0 : active : currently integrating, this wouldn't happen in a log file
63  # * 1 : inactive : not currently integrating, but will be
64  # * -1: disabled system : is ignored by integrators.
65  state = property
66 
67 
68 
69  ## Data structure for properties of a body (planet or star) in a system
70  #
71  # It has following properties:
72  # * `position` : a list of 3 floating point values for `x`, `y` and `z`
73  # * `velocity` : a list of 3 floating point values for `vx`, `vy` and `vz`
74  # * `mass` : a floating point value for the mass (relative to the star)
75  # it can be treated as a tuple, and destructed
76  Body = namedtuple('Body', ['position', 'velocity', 'mass'])
77 
78 
79  ## Return the star of a planetary system
80  # helper function for bodies_in_keplerian
81  def star(self):
82  return self.bodies[0]
83 
84  ## Barycenter, a.k.a center of mass, of the planetary system
85  # helper function for bodies_in_keplerian
86  def barycenter(self):
87  return center_of_mass(self.bodies)
88 
89  ## The origin with the mass of the star
90  # helper function for bodies_in_keplerian
91  def origin(self):
92  return LogRecord.Body((0,0,0),(0,0,0),self.bodies[0].mass)
93 
94 
95  ## Convert logrecord to keplerian coordinates, this method
96  # converts the bodies one-by-one. The coordinates are calculated with
97  # respect to a center. The possible options for a center are
98  # l.star(), l.barycenter() and l.origin()
99  # The results can be used in a for loop. This returns triplets as
100  # - Ordinal number of the planet (first planet has number 1)
101  # - Cartesian coordinates of the planet as an object that has properties
102  # position, velocity and mass
103  # - Keplerian coordinates of the planet as an object with properties
104  # a, e, i, O, w, M
105  def bodies_in_keplerian(self,center):
106  """
107  """
108  bs = with_index(self.bodies)
109  for i,b in bs[1:]:
110  yield i,b,keplerian_for_cartesian(b,center)
111 
112  ## Iterator for planets properties. For each planet, a triple of index,carteisan coordinates, keplerian coordinates
113  # is returned. The keplerian coordinates are computed with
114  # Jacobi semantics, meaning that center for every planet is
115  # the center of mass of the interior planetory system (star and all interior planets)
117  bs = with_index(self.bodies)
118  for i,b in bs[1:]:
119  center = center_of_mass(self.bodies[0:i])
120  yield i,b,keplerian_for_cartesian(b,center)
121 
122 
123  ## Parse a binary string representing a C++ logrecord struct
124  # and return a LogRecord object. Only snapshot logrecords (where event_id = 1) are
125  # supported at the moment
126  @staticmethod
127  def from_binary(s):
128  (msgid, length) = unpack('ii',s[0:8]) # msgid, len
129  l = LogRecord()
130  l.msgid = msgid
131  if msgid == 1 :
132  (time,sys,state,nbod) = unpack('diii',s[8:28])
133  bodies = []
134  for b in range(1,nbod+1):
135  (x,y,z,vx,vy,vz,mass,body_id) = \
136  unpack('dddddddi4x',s[(32+(b-1)*64):(32+(b)*64)])
137  bodies.append(LogRecord.Body((x,y,z),(vx,vy,vz) ,mass))
138  l.time = time
139  l.sys = sys
140  l.state = state
141  l.bodies = bodies
142  return l
143  else:
144  return None
145 
146  def as_map(self):
147  return {'time':self.time, 'sys':self.sys,
148  'state':self.state, 'bodies':self.bodies }
149 
150  ## String representation of the planetary system
151  # the representation is shown like a Hash.
152  def __repr__(self):
153  return self.as_map().__repr__();
154 
155