def combine_planets(body_data, body1, body2): """ Return effective combined single body from two bodies given as integers """ r1 = body_data[body1]['radius'] r2 = body_data[body2]['radius'] m1 = np.pi * r1 * r1 m2 = np.pi * r2 * r2 d1 = body_data[body1]['density'] d2 = body_data[body2]['density'] pos1 = pp.Point2D(body_data[body1]['position'][0], body_data[body1]['position'][1]) pos2 = pp.Point2D(body_data[body2]['position'][0], body_data[body2]['position'][1]) dp = pos2 - pos1 new_pos = pos2 - m1 / (m1 + m2) * dp # weighted mean of masses new_density = (m1 * d1 + m2 * d2) / (m1 + m2) new_radius = float(sqrt((m1 + m2) / new_density / np.pi)) # mass is redundant return { 'radius': new_radius, 'density': new_density, 'mass': m1 + m2, 'position': [new_pos[0], new_pos[1]] }
def plot_PP_fp(fp, plotter_layer, coords=None, do_evecs=True, markersize=10): """Draw fixed point from phaseplane.fixedpoint_2D objects. Optional do_evecs (default True) draws eigenvectors """ figure, layer = plotter.active_layer fig_struct, layer_struct = plotter.active_layer_structs if coords is None: x, y = layer_struct.axes_vars #fp.fp_coords # not stored in used order, just alphabetic order else: x, y = coords # When matplotlib implements half-full circle markers #if fp.classification == 'saddle': # half-open circle if fp.stability == 'u': style = 'wo' elif fp.stability == 'c': style = 'co' else: # 's' style = 'ko' # Add point and eigenvectors name = 'fp' dm.log.msg('Plot FP', name=name, layer=plotter_layer) plotter.add_point(pp.Point2D(saddle.point[x], saddle.point[y]), style=style, layer=plotter_layer, name=name) if do_evecs: for i, evec in enumerate(fp.evecs): fp_pt = fp.point evalue = fp.evals[i] if fp.classification == 'saddle': # this labeling will only work for a saddle if np.real(evalue) < 0: name = 'evec_s' style = 'g-.' else: name = 'evec_u' style = 'r-.' else: if np.real(evalue) < 0: name = 'evec_s' style = 'g-.' else: name = 'evec_u' style = 'r-.' p1, p2 = fovea.graphics.force_line_to_extent( fp_pt, fp_pt + pp.Point2D(evec, xname=x, yname=y), dict(zip(layer_struct.axes_vars, layer_struct.scale)), layer_struct.axes_vars) line = np.array((p1, p2)) name = dm.get_unique_name(name) dm.log.msg('Plot evec', name=name, layer=plotter_layer) plotter.add_data(line.T, style=style, layer=plotter_layer, name=name)
def secant(f,x0,x1, TOL=0.001, NMAX=100): """ Takes a function f, start values [x0,x1], tolerance value(optional) TOL and max number of iterations(optional) NMAX and returns the root of the equation using the secant method. """ n=1 dm.log.msg('Call args', x0=x0, x1=x1, TOL=TOL, NMAX=NMAX) plotter.add_text(0.1, 0.95, 'n=%d'%n, use_axis_coords=True, name='n_value', layer='meta_data', style='k') while n<=NMAX: dm.log = dm.log.bind(n=n) plotter.set_text('n_value', 'n=%d'%n, 'meta_data') if n == 1: rebuild = True else: plotter.toggle_display(layer='secant_text_%d'%(n-1)) plotter.toggle_display(layer='secant_data_%d'%(n-1)) rebuild = False plotter.add_layer('secant_data_%d'%n, subplot= '11') plotter.add_layer('secant_text_%d'%n, kind='text', subplot= '11') x2 = x1 - f(x1)*((x1-x0)/(f(x1)-f(x0))) x0_pt = plot_pt(x0, f, n, 'x0', 'r', 'secant', 'o') x1_pt = plot_pt(x1, f, n, 'x1', 'g', 'secant', 'o') x2_pt = plot_pt(x2, f, n, 'x2', 'k', 'secant', 'x') fs = plotter.figs['Master'] fx2 = f(x2) xleft = fs.domain[0][0] xright = fs.domain[0][1] gradient = (x1_pt[1]-x0_pt[1])/(x1_pt[0]-x0_pt[0]) yleft = gradient*(xleft-x1_pt[0]) + x1_pt[1] yright = gradient*(xright-x1_pt[0]) + x1_pt[1] plotter.add_line_by_points((pp.Point2D(xleft, yleft), pp.Point2D(xright, yright)), layer='secant_data_%d'%n, name='secantline_%d'%n, style='b-', log=dm.log) plotter.add_line_by_points((pp.Point2D(x2, 0), pp.Point2D(x2, fx2)), layer='secant_data_%d'%n, name='vertline_%d'%n, style='r-', log=dm.log) dm.log.msg('Secant loop', x0=x0, x1=x1, x2=x2) if abs(x2-x1) < TOL: dm.log.msg('Success', fval=fx2, err=abs(x2-x1)) dm.log = dm.log.unbind('n') plotter.show(rebuild=rebuild) return x2 else: # The missing increment was discovered when # layer with same name ('secant_data_1') tried to be # recreated! n = n+1 dm.log.msg('Step: x1->x0, x2->x1', err=abs(x2-x1)) x0 = x1 x1 = x2 plotter.show(rebuild=rebuild) dm.log.msg('Failure', status='fail', fval=f(x1), err=abs(x2-x1)) dm.log = dm.log.unbind('n') return False
def mouse_event_make_dom_p1(self, ev): if self.verbose: print("In make_dom_p1") # release mouse event control self.gui.fig.canvas.mpl_disconnect(self.gui.mouse_cid) self.gui.mouse_wait_state_owner = None # update state self.event('mouse') if self.gui_grow_state != 2: if self.verbose: print("make_dom_p1 failed") return # assign to p1 self.p1_pt = pp.Point2D(ev.xdata, ev.ydata) # delete display of c self.gui.selected_object_temphandle.remove() # create then iterate polygon_domain object self.polygon_domain_obj = polygon_domain(self.center_pt, self.p1_pt, self.func, nsides=40, edge_len_rtol=3) if self.verbose: print("Growing domain") try: self.polygon_domain_obj.grow() self.domain = self.polygon_domain_obj.polygon self.gui_grow_state = 3 self.show_domain(ev) if self.verbose: print("Domain complete") except AttributeError: return
def mouse_event_make_dom_c(self, ev): if ev.inaxes not in self.gui.cb_axes: print('Must select axes for which callbacks have been defined.') return self.curr_axes = ev.inaxes if self.verbose: print("In make_dom_c") # release mouse event control self.gui.fig.canvas.mpl_disconnect(self.gui.mouse_cid) # update state self.event('mouse') if self.gui_grow_state != 1: if self.verbose: print("make_dom_c failed") self.gui.mouse_wait_state_owner = None return # assign to c self.center_pt = pp.Point2D(ev.xdata, ev.ydata) # display c #self.gui.selected_object_temphandle = self.gui.ax.plot(ev.xdata, ev.ydata, 'go')[0] self.gui.selected_object_temphandle = ev.inaxes.plot( ev.xdata, ev.ydata, 'go')[0] self.gui.fig.canvas.draw() # switch control to make_dom_p1 self.gui.mouse_cid = self.gui.fig.canvas.mpl_connect( 'button_release_event', self.mouse_event_make_dom_p1)
def setup_pars(self, data): # Should generalize to non-bombardier application N = self.N radii = {} density = {} pos = {} for i, body in data.items(): pos[i] = pp.Point2D(body['position'][0], body['position'][1], labels={'body': i}) radii[i] = body['radius'] density[i] = body['density'] ixs = range(N) self.radii = [radii[i] for i in ixs] self.density = [density[i] for i in ixs] self.pos = [pos[i] for i in ixs] # planet positions self.masses = [ density[i] * np.pi * r * r for (i, r) in enumerate(self.radii) ] rdict = dict([('r%i' % i, self.radii[i]) for i in ixs]) mdict = dict([('m%i' % i, self.masses[i]) for i in ixs]) posxdict = dict([('bx%i' % i, pos[i][0]) for i in ixs]) posydict = dict([('by%i' % i, pos[i][1]) for i in ixs]) pardict = {'G': G} # global param for gravitational constant pardict.update(rdict) pardict.update(mdict) pardict.update(posxdict) pardict.update(posydict) self.body_pars = pardict self.icpos = np.array((0.0, 0.08)) self.icvel = np.array((0.0, 0.0))
def evaluate(self, target): # target should be a model interface object ptsFS = target.test_traj.sample() pt1 = self.pars.pt1 pt2 = self.pars.pt2 speed_inter = self.pars.speed_inter bearing_inter = self.pars.bearing_inter ev_name = self.pars.loc_event_name # Compute metric for closeness along, and perpendicular to, # pt1-pt2 line. # Did zero crossing event occur with direction consistent with heading? event_ix_dict = ptsFS.labels.by_label['Event:' + ev_name] if event_ix_dict is not None: if len(event_ix_dict) != 1: raise ValueError else: ix = list(event_ix_dict.keys())[0] check_time = ptsFS['t'][ix] event_pt = ptsFS[ix] else: conditions_met = False # how close did the trajectory get, perpendicularly? print("Failed") return False # check that perp distance of event_pt to pt1-pt2 line is < epsilon # tolerance of event # model = target.get('events', event_pt, check_time) ev = target.query('events')[ev_name] # initial value for conditions_met ... conditions_met = pp.distance_to_line(event_pt[['x', 'y']], (pt1, pt2)) < ev.eventtol # ? # get distance of event_pt (x,y) coords to pt1 and pt2 # if either is > |pt1-pt2| then outside of sub-domain line_seg_len = np.linalg.norm(pt2 - pt1) dist1 = np.linalg.norm(event_pt[['x', 'y']] - pt1) dist2 = np.linalg.norm(event_pt[['x', 'y']] - pt2) conditions_met = conditions_met and ((dist1 < line_seg_len) and (dist2 < line_seg_len)) # test if event_pt speed in speed_inter and bearing in bearing_inter conditions_met = conditions_met and event_pt['speed'] \ in self.pars.speed_inter # define the sense of the line's angle based on event direction: # +1 perpendicular is angle 0 line_vec = pt2 - pt1 n = pp.get_orthonormal(line_vec) vel_vec = pp.Point2D({'x': event_pt['vx'], 'y': event_pt['vy']}) speed = event_pt['speed'] vel_vec = vel_vec / speed # normalized to unit length n_dot_v = np.dot(n, vel_vec) if n_dot_v < 0: # sense of n is backwards n = -n rel_bearing = pp.get_bearing(n, vel_vec) conditions_met = conditions_met and rel_bearing \ in self.pars.bearing_inter # compute metric for closeness of velocity magnitude and direction return conditions_met
def compute_bbox(self): fig_struct, figs = self.plotter._resolve_fig(None) #Clear existing bounding boxes rem_names = [] for con_name, con_obj in self.context_objects.items(): if isinstance(con_obj, box_GUI) and con_name is not 'ref_box': rem_names.append(con_name) for name in rem_names: self.context_objects[name].remove(draw=False) fig_struct['layers']['detected']['data'] = {} self.plotter.show(rebuild=True) #Create new bounding boxes c = 0 for spike in self.spikes: peak = np.where( self.traj_samp == max(list(self.traj_samp[spike])))[0][0] tlo = peak - 20 thi = tlo + self.search_width valley = min(self.traj.sample()['x'][tlo:thi]) box_GUI(self, pp.Point2D(tlo, self.traj.sample()['x'][peak]), pp.Point2D(thi, valley), name='spike_box' + str(c), select=False) spike_seg = self.traj_samp[tlo:thi] try: X = np.row_stack((X, spike_seg)) except NameError: X = spike_seg c += 1 return X
def plot_pt(x, f, n, name, col, layer_root, marker='o'): """ Internal diagnostic helper function. """ new_layer = layer_root+'_data_%d'%n pt = pp.Point2D(x, f(x)) plotter.add_point(pt, style=col+marker, name=name+'_%d'%n, layer=new_layer, log=dm.log) fs = plotter.figs['Master'] ax = fs.arrange['11']['axes_obj'] xlim = ax.get_xlim() ylim = ax.get_ylim() x_ext = xlim[1]-xlim[0] y_ext = ylim[1]-ylim[0] # add marker text at a distance proportional to size of # current axis extent plotter.add_text(pt[0]-0.05*x_ext, pt[1]+0.02*y_ext, name, use_axis_coords=False, name=name+'_%d'%n, layer=layer_root+'_text_%d'%n, style=col) return pt
body_setup1 = setup['Full_model'] game1 = GUIrocket(body_setup1, "Scenario 1: Game 1", axisbgcol='white') # ! W1b Initial conditions game1.set((-79, 0.7)) # ! W2a Constraints # NONE # ! W2b Goals / targets # User interaction to draw line #ltarget = game1.selected_object ltarget = gx.line_GUI(game1, pp.Point2D(0.36, 0.74), pp.Point2D(0.42, 0.8), subplot='11') ltarget.make_event_def('target1', 1) game1.setup_gen(game1.model_namer) # make event terminal game1.model.setDSEventTerm('gen', 'exit_ev_target1', True) target = target4D_line('test_line', pars=args(pt1=pp.Point2D((ltarget.x1, ltarget.y1)), pt2=pp.Point2D((ltarget.x2, ltarget.y2)), speed_inter=Interval('speed', float, (1, 2)), bearing_inter=Interval( 'bearing', float, (-15, 45)), loc_event_name='exit_ev_target1'))
#Define body-1-dominant region #Define line at the edge of that region Game 4: #Assign that line to game4's currently selected object #Name it #Create the event for it #Compute end point of this regime Game 2: Assign new IC from end point of Game 4 regime and predict whether pericenter estimate is now accurate """ # LOAD game2! (not yet implemented) #l2 = game2.selected_object # Create l2 graphically, based on data from a concurrent session with game2 l4 = gx.line_GUI(game4, game4.ax, pp.Point2D(l2.x1, l2.y1), pp.Point2D(l2.x2, l2.y2)) l4.name = 'regime1_bd' l4.make_event_def('reg1_bd', 1) game4.setup_gen() game4.go() exit_pt = game4.traj.getEvents('exit_ev_reg1_bd')[0] game2.set(exit_pt[['vx', 'vy']], exit_pt[['x', 'y']], by_vel=True) game2.run() game2.graphics_refresh(cla=False) print("Mismatch of pericenter prediction with reduction = %.3f" % abs(min(w2.dist_to_1_vs_peri)))
import numpy as np import math import domain2D as dom xs = np.linspace(-6, 12, 2) ys1 = test_line1(xs) ys2 = test_line2(xs) plt.figure() ax = plt.gca() ax.set_aspect('equal') plt.plot(xs, ys1, 'k-', lw=4) plt.plot(xs, ys2, 'k-', lw=4) obj = dom.polygon_domain(pp.Point2D(1, 0.5), pp.Point2D(1, -1), [test_func1, test_func2], max_radius_fac=20, edge_len_rtol=4) plot_coords(ax, obj.polygon.exterior, '', 'o-', lw=3) plt.show() for i in range(60): plt.draw() obj.grow_step() plot_coords(ax, obj.polygon.exterior, '', '-') plot_coords(ax, obj.polygon.exterior, 'k', 'o')